-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
120 lines (116 loc) · 4.28 KB
/
docker-compose.yml
File metadata and controls
120 lines (116 loc) · 4.28 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
120
# OpenStudy stack: postgres + fastapi + frontend.
# All three containers live on an internal docker network. Only `frontend`
# (which serves the SPA and reverse-proxies API traffic to fastapi) and
# `openstudy` (kept exposed for direct curl debugging) are bound to the host.
# A user's outer reverse proxy (Caddy / nginx / Traefik / whatever)
# terminates TLS and forwards to 127.0.0.1:8080 (the frontend container).
#
# Bring up: ./deploy.sh
# Logs: docker compose logs -f openstudy
# Shell in: docker compose exec openstudy bash
services:
postgres:
image: postgres:16-alpine
container_name: openstudy-postgres
restart: unless-stopped
env_file:
- path: .env.docker
format: raw
required: true
environment:
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
volumes:
- /opt/postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 3s
retries: 12
start_period: 15s
networks: [internal]
# Never expose postgres to the host or internet — only the openstudy
# backend talks to it via the internal docker network (psycopg pool).
openstudy:
build:
context: .
dockerfile: Dockerfile
image: openstudy:latest
container_name: openstudy
restart: unless-stopped
env_file:
# format: raw disables ${VAR} interpolation inside values — required so
# APP_PASSWORD_HASH ("$argon2id$v=19$m=...") isn't mangled by compose
# treating $argon2id, $v, $m as undefined variables.
- path: .env
format: raw
required: true
- path: .env.docker
format: raw
required: true
environment:
# Tell the storage layer where the canonical course tree lives.
STUDY_ROOT: "/opt/courses"
depends_on:
postgres:
condition: service_healthy
volumes:
# Bind mount, not volume — files live on the host, container reads/writes
# them in place. Same path inside and outside for sanity.
- /opt/courses:/opt/courses:rw
ports:
# Bind to localhost only; Caddy on the host reverse-proxies in.
- "127.0.0.1:8000:8000"
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8000/api/health"]
interval: 10s
timeout: 5s
retries: 6
start_period: 30s
networks: [internal]
frontend:
build:
# Context is the repo root (not just web/) because the Vite prebuild
# invokes scripts/build-seo.mjs which lives one level up.
context: .
dockerfile: web/Dockerfile
args:
# Build-time env baked into the SPA bundle.
#
# API_BASE_URL is empty: the in-image Caddy proxies /api/* to the
# openstudy container on the internal network, so the SPA always
# talks to the API as same-origin.
#
# PUBLIC_SITE_URL / PUBLIC_SITE_NAME come from your .env.docker
# (or shell env). They land in <link rel=canonical>, OpenGraph
# tags, JSON-LD, robots.txt, sitemap.xml and the manifest. Set
# them to YOUR domain and name; the localhost default keeps the
# build deterministic for first-run dev but is not what you want
# for a public deploy.
VITE_API_BASE_URL: ""
VITE_SITE_URL: "${PUBLIC_SITE_URL:-http://localhost:8080}"
VITE_SITE_NAME: "${PUBLIC_SITE_NAME:-OpenStudy}"
VITE_SHOW_LANDING: "${PUBLIC_SHOW_LANDING:-false}"
# Google Search Console verification token (paste from Search Console's
# "HTML tag" verification — the value of `content="..."`). Empty by
# default so forks aren't carrying the upstream owner's token.
VITE_GOOGLE_SITE_VERIFICATION: "${PUBLIC_GOOGLE_SITE_VERIFICATION:-}"
image: openstudy-frontend:latest
container_name: openstudy-frontend
restart: unless-stopped
depends_on:
openstudy:
condition: service_started
ports:
# Bind to localhost only; the host's reverse proxy (Caddy etc.)
# terminates TLS and forwards here.
- "127.0.0.1:8080:80"
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost/"]
interval: 15s
timeout: 5s
retries: 4
start_period: 10s
networks: [internal]
networks:
internal:
driver: bridge