From 9e162bd59540d8a75cf2ca4637d0ee8e598ce804 Mon Sep 17 00:00:00 2001 From: Kenneth Obsequio Date: Mon, 21 Sep 2026 23:26:01 +0800 Subject: [PATCH] ci: deploy Signed-off-by: Kenneth Obsequio --- .github/workflows/deploy-qas.yml | 22 ------- .github/workflows/deploy.yml | 105 +++++++++++++++++++++++-------- apps/api/Dockerfile | 2 +- pnpm-workspace.yaml | 1 + 4 files changed, 81 insertions(+), 49 deletions(-) delete mode 100644 .github/workflows/deploy-qas.yml diff --git a/.github/workflows/deploy-qas.yml b/.github/workflows/deploy-qas.yml deleted file mode 100644 index 562e676..0000000 --- a/.github/workflows/deploy-qas.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Deploy to Cloudflare - -on: - push: - branches: [qas] - paths: - - 'apps/api/**' - - 'docker-compose.yml' - - 'pnpm-workspace.yaml' - workflow_dispatch: {} - -jobs: - deploy: - # Runner lives on the same home machine (ux) that Cloudflare Tunnel - # already points at — no WireGuard/SSH hop needed like the droplet - # workflow, the runner IS the target. - runs-on: [self-hosted, ux] - steps: - - uses: actions/checkout@v4 - - - name: Rebuild and restart backend - run: docker compose up -d --build backend diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fa07b30..ab57296 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,47 +1,100 @@ -name: Deploy to droplet +name: Deploy to production droplet on: push: branches: [main] - paths: - - 'apps/api/**' - - 'docker-compose.yml' - - 'pnpm-workspace.yaml' workflow_dispatch: {} +concurrency: + group: production-deployment + cancel-in-progress: true + jobs: deploy: runs-on: ubuntu-latest steps: - # nodejs-api only accepts SSH over its WireGuard tunnel (public :22 was - # removed). This peer is scoped to AllowedIPs 10.100.1.3/32 on the - # droplet side, so it can only ever reach 10.100.1.1 — nothing else. - - name: Bring up WireGuard tunnel + - name: Check out source + uses: actions/checkout@v4 + + - name: Install WireGuard run: | sudo apt-get update -y sudo apt-get install -y wireguard-tools + + # The CI peer must be configured on the droplet's wg0 interface: + # PublicKey = + # AllowedIPs = 10.100.2.11/32 + - name: Bring up production WireGuard tunnel + env: + CI_WG_PRIVATE_KEY: ${{ secrets.CI_WG_PRIVATE_KEY }} + DROPLET_WG_PUBLIC_KEY: ${{ secrets.DROPLET_WG_PUBLIC_KEY }} + run: | + set -Eeuo pipefail umask 077 sudo mkdir -p /etc/wireguard - cat < /dev/null + cat < /dev/null [Interface] - PrivateKey = ${{ secrets.CI_WG_PRIVATE_KEY }} - Address = 10.100.1.3/32 + PrivateKey = ${CI_WG_PRIVATE_KEY} + Address = 10.100.2.11/32 [Peer] - PublicKey = ${{ secrets.NODEJS_API_WG_PUBLIC_KEY }} - Endpoint = 68.183.239.171:51820 - AllowedIPs = 10.100.1.1/32 + PublicKey = ${DROPLET_WG_PUBLIC_KEY} + Endpoint = 161.35.103.214:51820 + AllowedIPs = 10.100.2.1/32 PersistentKeepalive = 25 EOF - sudo wg-quick up wg0 + sudo wg-quick up /etc/wireguard/new-starr-ci.conf - # The key below is restricted server-side to only run - # /opt/new_starr/deploy.sh (see authorized_keys forced-command on the - # droplet) — it can't run arbitrary commands even if this secret leaks. - - name: Deploy via SSH - uses: appleboy/ssh-action@v1 - with: - host: 10.100.1.1 - username: deploy - key: ${{ secrets.DEPLOY_SSH_KEY }} - script: deploy + - name: Configure SSH + env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + run: | + set -Eeuo pipefail + install -d -m 700 "$HOME/.ssh" + printf '%s\n' "$DEPLOY_SSH_KEY" > "$HOME/.ssh/new-starr-deploy" + chmod 600 "$HOME/.ssh/new-starr-deploy" + ssh-keyscan -H 10.100.2.1 >> "$HOME/.ssh/known_hosts" + + - name: Build frontend bundle + run: | + set -Eeuo pipefail + scp -i "$HOME/.ssh/new-starr-deploy" \ + -o IdentitiesOnly=yes \ + starr-deploy@10.100.2.1:/home/starr-deploy/new_starr/apps/web/.env \ + apps/web/.env + corepack enable + corepack prepare pnpm@11.3.0 --activate + pnpm install --no-frozen-lockfile + pnpm --filter web build + + - name: Upload source + run: | + set -Eeuo pipefail + tar \ + --exclude=.git \ + --exclude=node_modules \ + --exclude='apps/api/.env' \ + --exclude='apps/web/.env' \ + -czf - . | + ssh -i "$HOME/.ssh/new-starr-deploy" \ + -o IdentitiesOnly=yes \ + starr-deploy@10.100.2.1 \ + 'rm -rf "$HOME/new_starr-release" && mkdir -p "$HOME/new_starr-release" && tar -xzf - -C "$HOME/new_starr-release"' + + - name: Build and restart production stack + run: | + set -Eeuo pipefail + ssh -i "$HOME/.ssh/new-starr-deploy" \ + -o IdentitiesOnly=yes \ + starr-deploy@10.100.2.1 <<'REMOTE' + set -Eeuo pipefail + cd "$HOME/new_starr-release" + test -f "$HOME/new_starr/apps/api/.env" + test -f "$HOME/new_starr/apps/web/.env" + test -f "$HOME/new_starr/.env" + cp "$HOME/new_starr/apps/api/.env" apps/api/.env + cp "$HOME/new_starr/apps/web/.env" apps/web/.env + cp "$HOME/new_starr/.env" .env + docker compose up -d --build + docker compose ps + REMOTE diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 8f389c0..48be87a 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -10,7 +10,7 @@ RUN npm install -g pm2 sequelize-cli # Typst — compiles certificate.typ into the downloadable PDF certificate. # Not available as an apk package, so lift the binary out of pandoc/typst. -COPY --from=typst /usr/bin/typst /usr/local/bin/typst +COPY --from=typst /usr/local/bin/typst /usr/local/bin/typst WORKDIR /app diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3c578c3..b33629c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,6 @@ packages: - "apps/*" allowBuilds: + "@parcel/watcher": true unrs-resolver: true msw: true