diff --git a/.github/workflows/web-deploy.yml b/.github/workflows/web-deploy.yml index 4101b87..856ea21 100644 --- a/.github/workflows/web-deploy.yml +++ b/.github/workflows/web-deploy.yml @@ -44,10 +44,8 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/checkout@v4 - with: - ref: ${{ steps.meta.outputs.ref }} - fetch-depth: 1 + - name: Checkout code + uses: actions/checkout@v5 - name: Git short SHA id: git @@ -59,7 +57,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . - file: deploy/Dockerfile + file: ./deployment/Dockerfile platforms: linux/amd64 push: true provenance: false @@ -77,8 +75,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - # Need repo files for scp (deploy job does not inherit build-package checkout). - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v5 - name: Ensure remote directory uses: appleboy/ssh-action@v1.2.5 @@ -98,9 +96,10 @@ jobs: key: ${{ secrets.DEPLOY_SSH_KEY }} port: 22 timeout: 2m - source: deploy/docker-compose.yml + source: deployment/docker-compose.yml target: ~/pengine/ overwrite: true + strip_components: 1 - name: SSH — docker login, compose pull, up uses: appleboy/ssh-action@v1.2.5 @@ -118,8 +117,8 @@ jobs: envs: GHCR_USER,GHCR_TOKEN,PENGINE_WEB_IMAGE script: | set -euo pipefail - cd ~/pengine + cd ~/pengine/deployment echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GHCR_USER" --password-stdin export PENGINE_WEB_IMAGE docker compose pull - docker compose up -d --remove-orphans + docker compose up -d diff --git a/deploy/Dockerfile b/deployment/Dockerfile similarity index 96% rename from deploy/Dockerfile rename to deployment/Dockerfile index 313732d..e20b664 100644 --- a/deploy/Dockerfile +++ b/deployment/Dockerfile @@ -2,7 +2,6 @@ FROM node:22-alpine AS builder WORKDIR /app ENV HUSKY=0 -ENV NODE_ENV=production COPY package.json package-lock.json ./ RUN npm ci --ignore-scripts diff --git a/deploy/docker-compose.yml b/deployment/docker-compose.yml similarity index 88% rename from deploy/docker-compose.yml rename to deployment/docker-compose.yml index aec15cf..7b4f2cc 100644 --- a/deploy/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -10,11 +10,6 @@ services: - "1422" environment: - NODE_ENV=production - networks: - pengui-network: - aliases: - - pengine - - app healthcheck: test: ["CMD", "curl", "-fsS", "http://127.0.0.1:1422/"] interval: 30s diff --git a/doc/guides/deploying-web.md b/doc/guides/deploying-web.md index feade93..7fab813 100644 --- a/doc/guides/deploying-web.md +++ b/doc/guides/deploying-web.md @@ -6,8 +6,8 @@ The pengine web bundle is deployed to a remote host via the [`Deploy web app`](../../.github/workflows/web-deploy.yml) GitHub Actions workflow. It has two jobs: -1. **Build and push image** — Checks out the input tag and builds [`deploy/Dockerfile`](../../deploy/Dockerfile) from that revision. Steps: **`npm ci`** → [`npm run build:web`](../../package.json) → runtime **[`vite preview`](https://vite.dev/guide/cli#vite-preview)**. CI passes `VITE_APP_ORIGIN=https://pengine.net` as a **build-arg**. **Always** pushes to GHCR: `:`, `:sha-`, and `:latest`. -2. **Deploy to host** — checks out the workflow branch and **scp**’s [`deploy/docker-compose.yml`](../../deploy/docker-compose.yml) to the server, then SSH runs **`docker login`** → **`docker compose pull`** → **`docker compose up`**. **`PENGINE_WEB_IMAGE`** is **`ghcr.io//pengine-web:`** from the workflow input. +1. **Build and push image** — Checks out the input tag and builds [`deploy/Dockerfile`](../../deployemnt/Dockerfile) from that revision. Steps: **`npm ci`** → [`npm run build:web`](../../package.json) → runtime **[`vite preview`](https://vite.dev/guide/cli#vite-preview)**. CI passes `VITE_APP_ORIGIN=https://pengine.net` as a **build-arg**. **Always** pushes to GHCR: `:`, `:sha-`, and `:latest`. +2. **Deploy to host** — checks out the workflow branch and **scp**’s [`deploy/docker-compose.yml`](../../deployment/docker-compose.yml) to the server, then SSH runs **`docker login`** → **`docker compose pull`** → **`docker compose up`**. **`PENGINE_WEB_IMAGE`** is **`ghcr.io//pengine/web:`** from the workflow input. The app listens on **port 1422** inside the container (**Vite preview** — matches `preview.port` in `vite.config.ts`; dev server stays on **1420**). Add a **host** @@ -17,7 +17,7 @@ not defined in this repository — point nginx (or similar) at that upstream URL ## Triggers -- **Manual only** — Actions → *Deploy web app* → *Run workflow*. Enter a **`tag`** +- **Manual only** — Actions → _Deploy web app_ → _Run workflow_. Enter a **`tag`** (e.g. `1.0.1` or `v1.0.1`) that exists as a **git ref** on the remote. The workflow checks out that ref, builds the image, **always pushes** it to GHCR for that tag, then deploys with **`docker compose pull`** on the host. @@ -26,18 +26,18 @@ not defined in this repository — point nginx (or similar) at that upstream URL ## Required secrets -Add under *Settings → Secrets and variables → Actions*: +Add under _Settings → Secrets and variables → Actions_: -| Secret | Value | -| --- | --- | -| `DEPLOY_HOST` | Hostname or IP of the deploy target | -| `DEPLOY_USER` | SSH user on the target (must be in the `docker` group) | +| Secret | Value | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `DEPLOY_HOST` | Hostname or IP of the deploy target | +| `DEPLOY_USER` | SSH user on the target (must be in the `docker` group) | | `DEPLOY_SSH_KEY` | Private key (full file, `BEGIN`/`END` lines), **no passphrase**. Ed25519 recommended — [generate a deploy key](#ssh-deploy-key). Public key on the host in `~/.ssh/authorized_keys`. | Optional (not wired in the workflow today; extend the `appleboy` steps if you need host-key pinning): -| Secret | Value | -| --- | --- | +| Secret | Value | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Host key fingerprint | [appleboy/ssh-action](https://github.com/appleboy/ssh-action) supports `fingerprint` (SHA256 of the server host key) for MITM protection — add to the workflow `with:` block if you use it. | GHCR auth on the host uses the per-run `GITHUB_TOKEN` — no extra secret @@ -128,7 +128,7 @@ ssh "$DEPLOY_USER@$DEPLOY_HOST" 'docker ps --filter name=pengine' curl -fsSL https://pengine.net/ | head ``` -To roll back, run *Deploy web app* again with an older **`tag`** — the workflow +To roll back, run _Deploy web app_ again with an older **`tag`** — the workflow rebuilds and overwrites that tag’s image in GHCR, then deploys it. ## Local image build