# The Halkyon Learn instance: Caddy in front, the Serverpod server, PostgreSQL, and # the dictionaries kept current beside them. # # 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:-} # How much room people's files may take, in MiB; empty: the defaults. FILE_LIMIT_ANONYMOUS_MB: ${FILE_LIMIT_ANONYMOUS_MB:-} FILE_LIMIT_IDENTIFIED_MB: ${FILE_LIMIT_IDENTIFIED_MB:-} FILE_LIMIT_INSTANCE_MB: ${FILE_LIMIT_INSTANCE_MB:-} # The git repositories of published studysets (ADR 0005, rule 3). REPOSITORIES_DIR: /app/repositories # The dictionary files it loads at start and rereads hourly, those that changed # (see the server's README): those the dictionaries service keeps current, read # only. To supply files yourself instead, remove that service and mount # ./dictionaries here (`- ./dictionaries:/app/dictionaries:ro`). volumes: - dictionaries:/app/dictionaries:ro # Every release of every published studyset: backed up beside the database # (backup.sh), never deleted with `down -v`. - repositories:/app/repositories depends_on: postgres: condition: service_healthy logging: *logging # Keeps the dictionary files current from EDRDG's files of the day, once they are a # week old (EDRDG's licence asks it of servers showing its dictionaries at least # monthly; the curator's README): in a container of its own, the curator never in # the server's image or process. It only downloads (some 25 MB a week) and writes # into the volume; the files are never backed up, as they can be had again. dictionaries: build: context: .. dockerfile: halkyon_learn_curator/Dockerfile image: halkyon-learn-dictionaries restart: unless-stopped # Docker's stop signal reaches the curator through a small init. init: true # A conversion takes some 400 MB for a minute a week. mem_limit: 1g volumes: - dictionaries:/dictionaries 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: dictionaries: postgres_data: repositories: