Host on AWS Lightsail as boards.watersmedia.org
Deploy Waters Boards to AWS / deploy (push) Canceled after 0s
Deploy Waters Boards to AWS / deploy (push) Canceled after 0s
Replace the planned Synology deploy with one Lightsail box: Caddy in front of the app for automatic HTTPS (deploy/aws/docker-compose.yml, Caddyfile), a deploy script that rsyncs server/ and rebuilds in place without touching data/ or .env, and a Gitea workflow that runs the same script from the nas runner over SSH. README documents the box, DNS, .env, deploys and restore. Allow both church Google Workspace domains to sign in. Drop the NAS-only compose file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+38
-53
@@ -1,23 +1,35 @@
|
||||
# Push to main -> the NAS rebuilds Waters Boards.
|
||||
# Push to main -> Waters Boards is rebuilt on the AWS Lightsail box.
|
||||
#
|
||||
# Same shape as the checklist app's deploy: runs on the "nas" act_runner (in Docker on the
|
||||
# NAS itself), copies server/ over the live directory, then recreates the container in place.
|
||||
# Runs on the "nas" act_runner, which lives inside the church network and can reach the
|
||||
# internet. (The Gitea server isn't reachable from outside, so AWS can't pull from it; the
|
||||
# runner pushes to AWS instead.) It syntax-checks the code, rsyncs server/ and deploy/aws/ to
|
||||
# /opt/waters-boards on the box over SSH, rebuilds in place and waits for the healthcheck.
|
||||
# All of that is deploy/aws/deploy.sh, the same script you run from a laptop.
|
||||
#
|
||||
# ONE-TIME NAS SETUP before the first run (see README.md › Deploy):
|
||||
# 1. mkdir /volume2/docker/waters-boards and put a filled-in .env there
|
||||
# 2. add "/volume2/docker/waters-boards" to container.valid_volumes in the act_runner
|
||||
# config.yaml on the NAS, and restart the runner
|
||||
# 3. point a reverse-proxy hostname (https) at port 3100 — Google sign-in needs https
|
||||
# 4. set the repository variable DEPLOY_ENABLED=true (Settings ▸ Actions ▸ Variables).
|
||||
# Until then this job is skipped, so pushes don't fail before the NAS is ready.
|
||||
# ONE-TIME SETUP before the first run (see README.md › Deploy to AWS):
|
||||
# 1. Make a deploy-only SSH key (e.g. ssh-keygen -t ed25519 -N '' -f deploy_key) and add the
|
||||
# public half to /home/ubuntu/.ssh/authorized_keys on the box.
|
||||
# 2. Add repository secrets (Settings ▸ Actions ▸ Secrets):
|
||||
# DEPLOY_SSH_KEY the private key from step 1
|
||||
# DEPLOY_KNOWN_HOSTS the output of: ssh-keyscan -t ed25519 <static IP>
|
||||
# 3. Add repository variables (Settings ▸ Actions ▸ Variables):
|
||||
# DEPLOY_HOST the box's static IP
|
||||
# DEPLOY_ENABLED true
|
||||
# Until DEPLOY_ENABLED is true this job is skipped, so pushes made before the box is
|
||||
# ready don't show as failures.
|
||||
# 4. The "nas" runner must be registered where it can see this repo (user- or instance-level,
|
||||
# not only on the checklist repo).
|
||||
# /opt/waters-boards/.env must already exist on the box. The deploy never creates or
|
||||
# overwrites it, and never touches data/.
|
||||
|
||||
name: Deploy Waters Boards to NAS
|
||||
name: Deploy Waters Boards to AWS
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'server/**'
|
||||
- 'deploy/aws/**'
|
||||
- '.gitea/workflows/deploy.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -27,55 +39,28 @@ jobs:
|
||||
runs-on: nas
|
||||
container:
|
||||
image: node:22-alpine
|
||||
volumes:
|
||||
# Mounted at the SAME path as on the host: docker-compose.yml binds ./data relative to
|
||||
# the compose file and the daemon resolves that as a host path. (The docker socket is
|
||||
# already mounted by act_runner — declaring it again breaks the job.)
|
||||
- /volume2/docker/waters-boards:/volume2/docker/waters-boards
|
||||
|
||||
steps:
|
||||
- name: Install tools
|
||||
run: apk add --no-cache docker-cli docker-cli-compose rsync
|
||||
# deploy.sh is a bash script and needs node (already in the image) for its syntax check.
|
||||
run: apk add --no-cache bash openssh-client rsync
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check the deploy directory is set up
|
||||
- name: Set up the SSH key
|
||||
# Secrets go in through env, not pasted into the script text.
|
||||
env:
|
||||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||
DEPLOY_KNOWN_HOSTS: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
|
||||
run: |
|
||||
set -eu
|
||||
DEST=/volume2/docker/waters-boards
|
||||
test -f "$DEST/.env" || { echo "REFUSING: $DEST/.env is missing — see README.md › Deploy"; exit 1; }
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
printf '%s\n' "$DEPLOY_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
||||
chmod 644 ~/.ssh/known_hosts
|
||||
|
||||
- name: Copy server files over the live directory
|
||||
run: |
|
||||
set -eu
|
||||
# data/ holds the live database, uploads and backups; .env holds the secrets.
|
||||
# Neither is in git and neither may ever be written here. No --delete.
|
||||
rsync -a \
|
||||
--exclude 'data/' \
|
||||
--exclude '.env' \
|
||||
--exclude 'node_modules/' \
|
||||
server/ /volume2/docker/waters-boards/
|
||||
|
||||
- name: Verify the live data and credentials survived
|
||||
run: |
|
||||
set -eu
|
||||
test -f /volume2/docker/waters-boards/.env || { echo "ABORT: .env is gone"; exit 1; }
|
||||
echo ".env intact"; ls -la /volume2/docker/waters-boards/data 2>/dev/null || echo "(no data/ yet — first deploy)"
|
||||
|
||||
- name: Rebuild the container in place
|
||||
# No 'down' first: an interrupted deploy then leaves the old container serving.
|
||||
run: docker compose -f /volume2/docker/waters-boards/docker-compose.yml up -d --build --remove-orphans
|
||||
|
||||
- name: Healthcheck
|
||||
run: |
|
||||
set -eu
|
||||
for i in $(seq 1 20); do
|
||||
S=$(docker inspect --format '{{.State.Health.Status}}' waters-boards 2>/dev/null || echo starting)
|
||||
[ "$S" = "healthy" ] && { echo "container healthy"; exit 0; }
|
||||
sleep 3
|
||||
done
|
||||
echo "container did not report healthy in time:"
|
||||
docker ps --filter name=waters-boards --format '{{.Names}} {{.Status}}'
|
||||
docker logs --tail 30 waters-boards
|
||||
exit 1
|
||||
- name: Deploy
|
||||
run: BOARDS_HOST="ubuntu@${{ vars.DEPLOY_HOST }}" bash deploy/aws/deploy.sh
|
||||
|
||||
Reference in New Issue
Block a user