# The Halkyon Learn instance: Caddy in front, the Serverpod server, PostgreSQL. # # cd deploy # cp .env.example .env && chmod 600 .env # then fill in the secrets # docker compose up -d --build # # Only Caddy publishes ports. Docker opens published ports directly in the kernel's # packet filter, past ufw, and the Serverpod server listens on every interface, so the # server and Postgres publish nothing: they're reachable only inside this project's # network, where Caddy finds the server by its service name. name: halkyon-learn # Logs go to the host's journal, whose size and age limits apply (journald.conf). x-logging: &logging driver: journald services: caddy: image: caddy:2 restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" # HTTP/3 environment: # `learn.halkyon.eu` on sahaquiel (automatic Let's Encrypt certificate); # `http://localhost` for the local rehearsal (plain HTTP, no certificate). DOMAIN: ${DOMAIN:?set DOMAIN in deploy/.env} volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data # certificates: must survive restarts (rate limits) - caddy_config:/config depends_on: - server logging: *logging server: build: context: .. dockerfile: halkyon_learn_server/Dockerfile image: halkyon-learn-server restart: unless-stopped # Applies pending migrations at every start, then serves. One instance only, so # no two servers ever migrate at once. (On learn.halkyon.eu, deploy/redeploy.sh has # applied them in a run of their own before, so nothing is left to do here.) command: ["--apply-migrations"] environment: SERVERPOD_DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in deploy/.env} SERVERPOD_PASSWORD_serverSideSessionKeyHashPepper: ${SESSION_KEY_HASH_PEPPER:?set SESSION_KEY_HASH_PEPPER in deploy/.env} # GitHub sign-in, only with this instance's GitHub OAuth app; empty: off. SERVERPOD_PASSWORD_githubClientId: ${GITHUB_CLIENT_ID:-} SERVERPOD_PASSWORD_githubClientSecret: ${GITHUB_CLIENT_SECRET:-} # Where the source of what this instance runs is; empty: the project's. SOURCE_URL: ${SOURCE_URL:-} depends_on: postgres: condition: service_healthy logging: *logging postgres: image: postgres:16 restart: unless-stopped # The server's session is UTC anyway (the driver sets it); this makes the # database's own default UTC too, for psql, COPY loads and future sidecars. command: ["postgres", "-c", "timezone=UTC", "-c", "log_timezone=UTC"] environment: POSTGRES_USER: halkyon_learn POSTGRES_DB: halkyon_learn POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in deploy/.env} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U halkyon_learn -d halkyon_learn"] interval: 5s timeout: 5s retries: 12 logging: *logging volumes: caddy_data: caddy_config: postgres_data: