Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
119 lines (116 loc) · 6.4 KB
/
Copy pathdocker-compose.yml
File metadata and controls
119 lines (116 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
networks:
traefik:
external: true
volumes:
# Persists the SQLite DB across restarts/redeploys. The image ships /data owned
# by nonroot (65532), so this fresh named volume inherits writable ownership.
dday-data:
# Persists the bot's DM room cache (handle -> room id) across restarts. Kept
# separate from dday-data so the bot never touches the web service's DB. Same
# ownership story: the image ships /data owned by nonroot (65532), so this
# fresh named volume inherits writable ownership for uid 65532.
bot-data:
services:
dday:
networks:
- traefik
labels:
traefik.http.routers.dday.rule: "Host(`dday.hs-ldz.pl`)"
traefik.http.routers.dday.entrypoints: "websecure"
traefik.http.routers.dday.tls.certresolver: "myresolver"
expose:
- "3329"
restart: unless-stopped
build: .
volumes:
- dday-data:/data
environment:
# Private age key (decrypts registration tokens) passed BY VALUE as base64,
# not as a mounted file — a 0600 key file is unreadable by the distroless
# nonroot user (uid 65532), which crash-loops the container. `make up`
# writes AGE_KEY_DATA into .env (gitignored) from config/dday_ed25519.
# If unset, the landing still serves and only registration returns 503.
AGE_KEY_DATA: ${AGE_KEY_DATA:-}
# SQLite DB path on the persistent volume.
DB_PATH: /data/dday.db
# Optional override of the registration time gate, sourced from .env (not
# hardcoded). `make up` writes it EMPTY by default, which means "unset" →
# the built-in time gate rules and registration opens by itself at the
# moment REGISTRATION_OPEN_AT names (evaluated per request, no restart).
# Set 1 to force it open now or 0 to force it closed — testing only.
REGISTRATION_OPEN: ${REGISTRATION_OPEN:-}
# Event dates — the single source of truth for the site, the bot and the
# landing page (see internal/regwindow). Unset → built-in defaults.
# Accepted: RFC3339 or "2006-01-02 15:04" (Europe/Warsaw).
REGISTRATION_OPEN_AT: ${REGISTRATION_OPEN_AT:-}
EVENT_START_AT: ${EVENT_START_AT:-}
EVENT_END_AT: ${EVENT_END_AT:-}
# Shared secret guarding GET /api/registered (the bot's "already registered?"
# probe). `make up` writes a stable INTERNAL_TOKEN into .env so both services
# agree. If empty, the endpoint is disabled (404) and the bot skips the check.
INTERNAL_TOKEN: ${INTERNAL_TOKEN:-}
# Shared HMAC key authenticating the registration link token. `make up` writes
# a stable TOKEN_SECRET into .env so the bot (which signs) and web (which
# verifies) agree. If empty, links carry no real authenticity — production
# always has one generated.
TOKEN_SECRET: ${TOKEN_SECRET:-}
# Token guarding the read-only admin view GET /admin (?t=… or an
# Authorization: Bearer header). `make up` writes one into .env; empty
# disables the endpoint entirely (404). Web-only — the bot never needs it.
ADMIN_TOKEN: ${ADMIN_TOKEN:-}
# The Matrix bot: a separate long-lived process that listens for !start and
# DMs the sender a registration link (or a "not open yet" notice when closed).
# It reuses the same image but overrides the entrypoint to run /bot.
bot:
# No `networks:` — the bot must reach matrix.org, so it stays on the default
# project network (egress NAT). The `traefik` external network is inbound-only
# for the web service and would not give the bot internet access.
build: .
entrypoint: ["/bot"]
# The image HEALTHCHECK probes :3329/healthz, which only the web service
# serves — the bot has no HTTP listener, so it would always read "unhealthy".
healthcheck:
disable: true
restart: unless-stopped
# matrix.env (gitignored) supplies MATRIX_HOMESERVER/USER/PASSWORD + REGISTER_URL
# and MATRIX_ROOM, which doubles as the default ANNOUNCE_ROOM (the channel new
# registrations are announced in). Set ANNOUNCE_ROOM there to override it.
env_file: matrix.env
volumes:
- bot-data:/data
environment:
# Persist the bot state on the volume so it survives restarts: the DM room
# cache (a redeploy reuses the recorded DM for a known handle without asking
# the server) and the id of the last announced registration (so a restart
# does not re-announce). /data is owned by nonroot (65532) in the image.
DM_CACHE_PATH: /data/dm_cache.json
# Pure-Go SQLite crypto store on the volume: the bot's device identity and
# its megolm sessions live here, so a redeploy keeps reading/answering in
# encrypted rooms instead of re-registering a fresh, unverified device.
CRYPTO_DB_PATH: /data/crypto.db
# Encrypts the olm account at rest. `make up` writes a stable one into .env;
# it MUST stay constant across restarts (paired with the crypto volume) or
# the bot loses its device + sessions. Empty → the bot generates an
# ephemeral key and warns (a restart then loses all encrypted sessions).
CRYPTO_PICKLE_KEY: ${CRYPTO_PICKLE_KEY:-}
# matrix.env also sets AGE_PUB=config/... — a host path that does not exist
# inside the image. Override with the public key passed BY VALUE as base64;
# the bot prefers AGE_PUB_DATA over AGE_PUB. `make up` writes it into .env.
AGE_PUB_DATA: ${AGE_PUB_DATA:-}
# Same optional override as the web service, sourced from .env. `make up`
# leaves it empty → the built-in time gate rules and the bot starts handing
# out links by itself at REGISTRATION_OPEN_AT (evaluated per command, no
# restart). Set 1 to force open or 0 to force closed — testing only.
REGISTRATION_OPEN: ${REGISTRATION_OPEN:-}
# Same date configuration as the web service, so the bot's "not open yet"
# reply states exactly the same moment.
REGISTRATION_OPEN_AT: ${REGISTRATION_OPEN_AT:-}
EVENT_START_AT: ${EVENT_START_AT:-}
EVENT_END_AT: ${EVENT_END_AT:-}
# Same shared secret as the web service, so the bot can call
# GET /api/registered before issuing a link and poll GET /api/registrations
# for new signups to announce. Empty → both are skipped.
INTERNAL_TOKEN: ${INTERNAL_TOKEN:-}
# Shared HMAC key authenticating the registration link token — must match the
# web service so the token the bot signs verifies there. `make up` writes it.
TOKEN_SECRET: ${TOKEN_SECRET:-}