docker-compose.vps.yml
2,723 bytes
| 1 | # roundtable.rasmusj.com, the shared-host variant of docker-compose.yml. |
|---|---|
| 2 | # |
| 3 | # The VPS already runs one Caddy for every site on it, so this file leaves TLS |
| 4 | # and the domain out entirely: nothing is published to the host and the proxy |
| 5 | # reaches the app by container name over the external `web` network. The domain |
| 6 | # lives in /opt/caddy/Caddyfile alone. |
| 7 | # |
| 8 | # Postgres stays off `web`. Every other project on the box shares that network, |
| 9 | # and a database has no business being reachable from any of them. |
| 10 | # |
| 11 | # Deploy with ./deploy.sh, which builds this on the server. |
| 12 | |
| 13 | # Named explicitly because every project on this host is deployed into a |
| 14 | # directory called `app`, and Compose would otherwise derive the same project |
| 15 | # name for all of them and treat the neighbours' containers as orphans. |
| 16 | name: roundtable |
| 17 | |
| 18 | services: |
| 19 | db: |
| 20 | image: postgres:16-alpine |
| 21 | container_name: roundtable-db |
| 22 | restart: unless-stopped |
| 23 | environment: |
| 24 | POSTGRES_USER: roundtable |
| 25 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} |
| 26 | POSTGRES_DB: roundtable |
| 27 | volumes: |
| 28 | - roundtable-pgdata:/var/lib/postgresql/data |
| 29 | networks: |
| 30 | - internal |
| 31 | healthcheck: |
| 32 | test: ['CMD-SHELL', 'pg_isready -U roundtable -d roundtable'] |
| 33 | interval: 5s |
| 34 | timeout: 5s |
| 35 | retries: 12 |
| 36 | logging: |
| 37 | driver: json-file |
| 38 | options: |
| 39 | max-size: '10m' |
| 40 | max-file: '3' |
| 41 | |
| 42 | app: |
| 43 | build: |
| 44 | context: . |
| 45 | image: roundtable:vps |
| 46 | container_name: roundtable |
| 47 | restart: unless-stopped |
| 48 | depends_on: |
| 49 | db: |
| 50 | condition: service_healthy |
| 51 | environment: |
| 52 | DATABASE_URL: postgresql://roundtable:${POSTGRES_PASSWORD}@db:5432/roundtable?schema=public |
| 53 | ENCRYPTION_KEY: ${ENCRYPTION_KEY:?set ENCRYPTION_KEY in .env} |
| 54 | AUTH_TRUST_HOST: 'true' |
| 55 | OPENROUTER_APP_URL: ${OPENROUTER_APP_URL:-https://roundtable.rasmusj.com} |
| 56 | OPENROUTER_APP_TITLE: ${OPENROUTER_APP_TITLE:-Roundtable} |
| 57 | # Inference is always paid by the visitor's own OpenRouter key, so the |
| 58 | # public site costs nothing to run. /demo replays seeded debates and needs |
| 59 | # no key at all. |
| 60 | MOCK_LLM: ${MOCK_LLM:-0} |
| 61 | RATE_LIMIT_DEBATES_PER_HOUR: ${RATE_LIMIT_DEBATES_PER_HOUR:-10} |
| 62 | PORT: '3000' |
| 63 | networks: |
| 64 | - web |
| 65 | - internal |
| 66 | expose: |
| 67 | - '3000' |
| 68 | healthcheck: |
| 69 | test: ['CMD', 'node', '-e', "fetch('http://127.0.0.1:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"] |
| 70 | interval: 30s |
| 71 | timeout: 5s |
| 72 | start_period: 40s |
| 73 | retries: 3 |
| 74 | logging: |
| 75 | driver: json-file |
| 76 | options: |
| 77 | max-size: '10m' |
| 78 | max-file: '3' |
| 79 | |
| 80 | volumes: |
| 81 | roundtable-pgdata: |
| 82 | |
| 83 | networks: |
| 84 | web: |
| 85 | external: true |
| 86 | internal: |
| 87 | |