trails/.github/workflows/cd.yml
Ullrich Schäfer 8e2f183288
Enable CD deployment to Hetzner (task 11.8)
CD workflow:
- Uncommented deploy step
- Copy docker-compose.yml + Caddyfile to server via SCP
- Login to ghcr.io with DEPLOY_GHCR_TOKEN (classic PAT, read:packages)
- Download Germany BRouter segments on first deploy (~750MB)
- Pull images, restart services, verify

Infrastructure:
- BRouter segments as bind mount (./segments) not Docker volume
- Added ORIGIN, PLANNER_URL, SESSION_SECRET, NODE_ENV to Journal
- Added NODE_ENV to Planner
- Disabled Garage for now (no media storage yet)

Required secrets: DEPLOY_HOST, DEPLOY_SSH_KEY, DEPLOY_GHCR_TOKEN

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:00:00 +01:00

107 lines
3 KiB
YAML

name: CD
on:
push:
branches: [main]
concurrency:
group: deploy
cancel-in-progress: false
jobs:
build-images:
name: Build & Push Docker Images
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
app: [journal, planner]
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
file: apps/${{ matrix.app }}/Dockerfile
push: true
tags: |
ghcr.io/trails-cool/${{ matrix.app }}:latest
ghcr.io/trails-cool/${{ matrix.app }}:${{ github.sha }}
build-brouter:
name: Build & Push BRouter Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: docker/brouter
push: true
tags: |
ghcr.io/trails-cool/brouter:latest
ghcr.io/trails-cool/brouter:${{ github.sha }}
deploy:
name: Deploy to Hetzner
needs: [build-images, build-brouter]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Copy files to server
uses: appleboy/scp-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: root
key: ${{ secrets.DEPLOY_SSH_KEY }}
source: "infrastructure/docker-compose.yml,infrastructure/Caddyfile"
target: /opt/trails-cool
strip_components: 1
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: root
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
cd /opt/trails-cool
# Login to ghcr.io to pull private images
echo "${{ secrets.DEPLOY_GHCR_TOKEN }}" | docker login ghcr.io -u stigi --password-stdin
# Download BRouter segments if missing
if [ ! -d /opt/trails-cool/segments ] || [ -z "$(ls /opt/trails-cool/segments/*.rd5 2>/dev/null)" ]; then
mkdir -p /opt/trails-cool/segments
echo "Downloading Germany BRouter segments..."
for tile in E5_N45 E5_N50 E10_N45 E10_N50; do
[ -f "/opt/trails-cool/segments/${tile}.rd5" ] || \
wget -q "https://brouter.de/brouter/segments4/${tile}.rd5" -O "/opt/trails-cool/segments/${tile}.rd5"
done
fi
# Pull latest images and restart
docker compose pull
docker compose up -d --remove-orphans
# Verify services are running
sleep 10
docker compose ps