diff --git a/.github/workflows/init.yml b/.github/workflows/init.yml index e17d737..d181512 100644 --- a/.github/workflows/init.yml +++ b/.github/workflows/init.yml @@ -17,6 +17,7 @@ on: options: - 'letsencrypt' - 'custom' + - 'none' default: 'letsencrypt' jobs: @@ -27,7 +28,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Validate required variables run: | @@ -133,3 +134,9 @@ jobs: echo "| Host | ${{ vars.SSH_HOST }} |" >> $GITHUB_STEP_SUMMARY echo "| TLS Mode | ${{ inputs.tls_mode }} |" >> $GITHUB_STEP_SUMMARY echo "| Image | ${{ steps.setup.outputs.sfp-image }} |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Admin Credentials" >> $GITHUB_STEP_SUMMARY + echo "Credentials are stored securely on the server. To retrieve them:" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "ssh ${{ vars.SSH_USER || 'root' }}@${{ vars.SSH_HOST }} \"cat ${{ vars.BASE_DIR || './sfp-server' }}/tenants/${{ vars.TENANT_NAME }}/credentials.json\"" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/start.yml b/.github/workflows/start.yml index 4c84215..0555fbd 100644 --- a/.github/workflows/start.yml +++ b/.github/workflows/start.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup SFP CLI and SSH id: setup diff --git a/.github/workflows/stop.yml b/.github/workflows/stop.yml index 05f4fcd..7d0e612 100644 --- a/.github/workflows/stop.yml +++ b/.github/workflows/stop.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup SFP CLI and SSH id: setup diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index dccb0d5..15e5471 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Resolve image tag id: resolve diff --git a/README.md b/README.md index 5a3c85c..a597a6a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This repository provides GitHub Actions workflows to: - **Update** an existing server to the latest version - **Check** for new versions on a weekly schedule -The workflows connect to your server via SSH, download the SFP CLI from Gitea, and run the appropriate server lifecycle commands. +The workflows connect to your server via SSH, pull the SFP server Docker image, and run the CLI from inside it to manage the server lifecycle. ## Prerequisites @@ -19,10 +19,9 @@ Before using this repository, ensure you have: 1. **Linux server** -- x86_64, 8+ vCPU, 32+ GB RAM, 250+ GB SSD 2. **Docker Engine 24+** and **Docker Compose v2** installed on the server 3. **Domain name** (FQDN) resolving to the server -4. **TLS certificate + private key** (PEM format) -- or use Let's Encrypt for automatic TLS -5. **SSH access** to the server from GitHub Actions runners -6. **Docker registry token** for pulling SFP server images (the CLI runs from inside the image) -7. **Port 443** open on the server firewall +4. **SSH access** to the server from GitHub Actions runners +5. **Docker registry token** for pulling SFP server images (the CLI runs from inside the image) +6. **Port 443** (HTTPS) or **port 80** (HTTP) open depending on TLS mode For detailed requirements, see the [Self-Hosting Prerequisites](https://source.flxbl.io/flxbl/sfp-pro/src/branch/main/docs/self-hosting-prerequisites.md) guide. @@ -63,23 +62,41 @@ Go to **Settings** > **Secrets and variables** > **Actions** > **Variables** and 1. Go to **Actions** > **Initialize SFP Server** 2. Click **Run workflow** -3. Select the TLS mode (`custom` or `letsencrypt`) +3. Select the **environment** and **TLS mode** (see below) 4. Click **Run workflow** +#### TLS Modes + +| Mode | When to Use | Requirements | +|------|-------------|--------------| +| `letsencrypt` | Server is internet-accessible, you want automatic TLS | Domain DNS points to server, port 80 + 443 open | +| `custom` | You have your own TLS certificates (internal CA, commercial CA) | `ORIGIN_CERT` and `ORIGIN_KEY` secrets set (base64 PEM) | +| `none` | You run your own reverse proxy (nginx, HAProxy, ALB) in front of SFP | External proxy handles TLS, port 80 open for Caddy HTTP | + The init process will: - Pull the SFP server Docker image (the CLI runs from inside it) - Connect to your server via SSH - Create the directory structure and configuration - Auto-generate database credentials - Pull Docker images from your registry -- Start all services - Create the default admin user -The admin credentials will be displayed in the workflow output. +### 5. Retrieve Admin Credentials -### 5. Verify +Admin credentials are **not printed** in workflow logs for security. They are stored on the server in a protected file. Retrieve them via SSH: -Open `https://your-domain` in a browser to verify the server is accessible. +```bash +ssh @ "cat /tenants//credentials.json" +``` + +The file contains: +- `adminEmail` -- admin login email +- `adminPassword` -- admin login password +- `studioUser` / `studioPassword` -- Supabase Studio dashboard credentials + +### 6. Verify + +Open `https://your-domain` (or `http://your-domain` if using `tls-mode=none`) in a browser to verify the server is accessible. ## Post-Init: Integration Setup @@ -114,6 +131,34 @@ Add the relevant environment variables to `.env` on the server and restart: - `SLACK_APP_TOKEN`, `SLACK_SIGNING_SECRET`, `SLACK_BOT_TOKEN` - `OPENAI_API_KEY`, `AI_PROVIDER`, `AI_MODEL` +## Admin Dashboard Access (ALLOWED_IPS) + +The following admin dashboards are IP-restricted by Caddy: + +| Dashboard | Port | Purpose | +|-----------|------|---------| +| Hatchet | 8080 | Workflow monitoring | +| Supabase Studio | 3100 | Database management | +| Verdaccio | 4873 | npm registry browser | + +By default, only private network ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`) can access these ports. To add your IP addresses, SSH to the server and edit `.env`: + +```bash +# Single IP +ALLOWED_IPS=203.0.113.10 + +# Multiple IPs +ALLOWED_IPS=203.0.113.10,198.51.100.5 + +# CIDR ranges +ALLOWED_IPS=10.0.0.0/8,172.16.0.0/12 +``` + +After changing `ALLOWED_IPS`, restart Caddy: +```bash +docker compose restart caddy +``` + ## Updating To update the server to a new version: @@ -134,12 +179,7 @@ The update process: ## Version Checks -The **Check for Updates** workflow runs weekly (Monday 8 AM UTC) and: -- Queries Gitea for the latest release -- Compares with the currently deployed version -- Creates a GitHub Issue if a newer version is available - -You can also trigger it manually from **Actions** > **Check for Updates**. +The **Check Deployed Version** workflow can be triggered manually to check what version is running on the server. It SSHs in and reads the `IMAGE_TAG` from the server's `.env` file, comparing it with the configured `IMAGE_TAG` variable. ## Backup and Recovery @@ -181,7 +221,9 @@ If the server is destroyed, you will need the backed-up `.env` to restore withou |------|---------| | `.github/actions/setup-sfp/action.yml` | Composite action: pull Docker image + configure SSH | | `.github/workflows/init.yml` | One-time server initialization workflow | +| `.github/workflows/start.yml` | Start server services | +| `.github/workflows/stop.yml` | Stop server services | | `.github/workflows/update.yml` | Server update workflow | -| `.github/workflows/check-update.yml` | Weekly version check workflow | +| `.github/workflows/check-update.yml` | Check deployed version | | `config/server-config.example.json` | Example JSON config for manual (non-workflow) init | | `.env.template` | Reference for all configuration variables |