Repository navigation
Expand file tree
/
Copy pathdocker-compose.https.yml
More file actions
234 lines (217 loc) · 9.33 KB
/
Copy pathdocker-compose.https.yml
File metadata and controls
234 lines (217 loc) · 9.33 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# Overlay: the whole spaces stack at https names, the way the real network looks, so an
# app built for the real network runs against the devnet with no devnet code. Stack it
# LAST, on all five spaces files, with a project name of your choosing:
#
# docker compose -p <project> -f docker-compose.yml -f docker-compose.test.yml \
# -f docker-compose.spaces.yml -f docker-compose.multi-pds.yml \
# -f docker-compose.relay.yml -f docker-compose.https.yml up -d --wait
#
# scripts/https-up.sh does exactly that (DEVNET_PROJECT names the project), plus the
# certificates, the lexicon authority's second pass and data/devnet.env. Use it.
#
# Names, all answered by nginx on 127.0.0.1:443 with one leaf from data/https/
# (scripts/https-ca.sh), signed by a local CA that can vouch for nothing else.
# devnet.test is DEVNET_DOMAIN's default; set it and every .devnet.test name follows:
#
# alpha.devnet.test *.devnet.test pds the spaces alpha, invites on
# regular.devnet.test *.regular.devnet.test pds-regular a current release
# prod.devnet.test *.prod.devnet.test pds-prod the build you run in prod
# plc.directory plc this stack's PLC
# slingshot.devnet.test slingshot handle and DID lookups (resolveMiniDoc)
# <name>.devnet.internal an app on this machine, at the port
# scripts/https-app.sh recorded for <name>
#
# Each PDS's public URL, OAuth issuer and DID document endpoint is https://<its name>.
# Every PDS trusts the CA (NODE_EXTRA_CA_CERTS), and inside the compose network nginx
# also answers to the three PDS names, so the PDSes reach each other, the lexicon
# authority and an app's client metadata over TLS. The relay crawls them as wss://
# hosts. On the machine, the names resolve to 127.0.0.1 only for commands run under
# scripts/https-run, so every other program still reaches the real plc.directory.
#
# Published ports, all on 127.0.0.1: 443 (nginx), the PLC (DEVNET_PLC_PORT), Jetstream
# (DEVNET_JETSTREAM_PORT, DEVNET_JETSTREAM_METRICS_PORT) and maildev
# (DEVNET_MAILDEV_WEB_PORT, DEVNET_MAILDEV_SMTP_PORT). The PDS, relay, TAP and Postgres
# ports are not published: reach a PDS by its https name.
x-devnet-ca: &devnet-ca ./data/https/ca.crt:/https/ca.crt:ro
x-app-names: &app-names ./https/app-names.cjs:/https/app-names.cjs:ro
# Go reads every file in /etc/ssl/certs on top of its bundle, so the public roots stay.
x-go-ca: &go-ca ./data/https/ca.crt:/etc/ssl/certs/atproto-devnet-ca.pem:ro
x-https-pds-env: &https-pds-env
# Every address a PDS fetches from here (nginx, the PLC, this machine) is an RFC 1918
# one, which the SSRF-protected fetch would refuse.
PDS_DISABLE_SSRF_PROTECTION: "true"
NODE_EXTRA_CA_CERTS: /https/ca.crt
# <name>.devnet.internal resolves to nginx inside each PDS (https/app-names.cjs).
NODE_OPTIONS: --require /https/app-names.cjs
PDS_EMAIL_FROM_ADDRESS: noreply@${DEVNET_DOMAIN:-devnet.test}
services:
pds:
environment:
<<: *https-pds-env
PDS_HOSTNAME: alpha.${DEVNET_DOMAIN:-devnet.test}
# docker-compose.multi-pds.yml names all three PDSes under devnet.test, as on the
# plain stack, which does not read DEVNET_DOMAIN; here they follow it.
PDS_SERVICE_DID: did:web:alpha.${DEVNET_DOMAIN:-devnet.test}
# Explicit: the default would be .alpha.devnet.test.
PDS_SERVICE_HANDLE_DOMAINS: .${DEVNET_DOMAIN:-devnet.test}
PDS_HANDLE_DOMAINS: .${DEVNET_DOMAIN:-devnet.test}
# The public URL is https, so the alpha runs as it would on the real network.
# ("false", not !reset: compose keeps a key an earlier overlay set.)
PDS_DEV_MODE: "false"
volumes:
- *devnet-ca
- *app-names
ports: !reset []
pds-regular:
environment:
<<: *https-pds-env
PDS_HOSTNAME: regular.${DEVNET_DOMAIN:-devnet.test}
PDS_SERVICE_DID: did:web:regular.${DEVNET_DOMAIN:-devnet.test}
PDS_SERVICE_HANDLE_DOMAINS: .regular.${DEVNET_DOMAIN:-devnet.test}
volumes:
- *devnet-ca
- *app-names
pds-prod:
environment:
<<: *https-pds-env
PDS_HOSTNAME: prod.${DEVNET_DOMAIN:-devnet.test}
PDS_SERVICE_DID: did:web:prod.${DEVNET_DOMAIN:-devnet.test}
PDS_SERVICE_HANDLE_DOMAINS: .prod.${DEVNET_DOMAIN:-devnet.test}
volumes:
- *devnet-ca
- *app-names
relay:
# Its own tag, so an image built from an older relay/ patch is never reused.
image: atproto-devnet-relay:https-${DEVNET_RELAY_INDIGO_COMMIT:-b2619d864df00a66455bd9f5f0c83c1ac13ad73d}
environment:
# Every host is a wss:// one now.
RELAY_ALLOW_INSECURE_HOSTS: !reset null
volumes:
- *go-ca
depends_on:
nginx:
condition: service_healthy
# init seeds alice and bob on the alpha, so under its handle domain. docker-compose.yml
# itself does not read DEVNET_DOMAIN: the plain stack keeps DEVNET_HANDLE_DOMAIN.
init:
environment:
PDS_HOSTNAME: alpha.${DEVNET_DOMAIN:-devnet.test}
HANDLE_DOMAIN: .${DEVNET_DOMAIN:-devnet.test}
DEVNET_DOMAIN: ${DEVNET_DOMAIN:-devnet.test}
relay-init:
depends_on:
nginx:
condition: service_healthy
environment:
# Bare names are https/wss hosts to the relay.
RELAY_HOSTS: alpha.${DEVNET_DOMAIN:-devnet.test} regular.${DEVNET_DOMAIN:-devnet.test} prod.${DEVNET_DOMAIN:-devnet.test}
# Resync fetches repos through an SSRF-safe transport, which refuses nginx's address,
# so TAP follows the relay's stream but cannot resync a repo here.
tap:
volumes:
- *go-ca
# Slingshot (microcosm-rs) answers com.bad-example.identity.resolveMiniDoc, a handle's
# DID and PDS, from this stack's PLC and this stack's Jetstream. The public one cannot
# see a devnet account. It reaches the handles' names over TLS, which needs two things
# the other services do not: the CA as its only root, and a DNS that answers any name
# under the domain. slingshot-dns holds the network namespace Slingshot runs in, the
# way the extra PDSes share the alpha's, so nginx reaches Slingshot as slingshot-dns:8080.
slingshot-dns:
build: ./https/dns
image: atproto-devnet-dns:https-1
restart: unless-stopped
environment:
DEVNET_DOMAIN: ${DEVNET_DOMAIN:-devnet.test}
dns:
- 127.0.0.1
depends_on:
nginx:
condition: service_healthy
networks:
- atproto-devnet
slingshot:
# DEVNET_SLINGSHOT_COMMIT is a full microcosm-rs commit: it picks what is built and
# names the image, so the tag is always the source.
build:
context: ./slingshot
args:
MICROCOSM_COMMIT: ${DEVNET_SLINGSHOT_COMMIT:-3137b07d5268812d2de0f3177664be92196994d8}
image: atproto-devnet-slingshot:${DEVNET_SLINGSHOT_COMMIT:-3137b07d5268812d2de0f3177664be92196994d8}
restart: unless-stopped
network_mode: service:slingshot-dns
depends_on:
slingshot-dns:
condition: service_started
plc:
condition: service_healthy
jetstream:
condition: service_healthy
environment:
SLINGSHOT_PLC_DIRECTORY: http://plc:2582
SLINGSHOT_JETSTREAM: ws://jetstream:6008/subscribe
SLINGSHOT_CACHE_DIR: /data
SLINGSHOT_BIND: 0.0.0.0:8080
# The devnet's CA is the only root; the names it reaches are all the devnet's.
SSL_CERT_FILE: /https/ca.crt
volumes:
- *devnet-ca
- slingshot-data:/data
healthcheck:
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/127.0.0.1/8080'"]
interval: 5s
timeout: 3s
retries: 10
postgres:
# The PLC's database, named, so a `down` without -v keeps every DID.
volumes:
- plc-db:/var/lib/postgresql/data
ports: !reset []
plc:
ports: !override
- "127.0.0.1:${DEVNET_PLC_PORT:-2582}:2582"
jetstream:
ports: !override
- "127.0.0.1:${DEVNET_JETSTREAM_PORT:-6008}:6008"
- "127.0.0.1:${DEVNET_JETSTREAM_METRICS_PORT:-6009}:6009"
maildev:
ports: !override
- "127.0.0.1:${DEVNET_MAILDEV_WEB_PORT:-1081}:1080"
- "127.0.0.1:${DEVNET_MAILDEV_SMTP_PORT:-1026}:1025"
nginx:
image: nginx:1.30-alpine
restart: unless-stopped
depends_on:
pds:
condition: service_healthy
plc:
condition: service_healthy
ports:
- "${DEVNET_BIND:-127.0.0.1}:443:443"
extra_hosts:
# This machine, where an app registered with scripts/https-app.sh listens.
- host.docker.internal:host-gateway
environment:
# The image fills ${DEVNET_DOMAIN} into the template at start, and only names
# starting DEVNET_, so nginx's own $host and the like are left alone.
DEVNET_DOMAIN: ${DEVNET_DOMAIN:-devnet.test}
NGINX_ENVSUBST_FILTER: ^DEVNET_
volumes:
- ./https/nginx.conf.template:/etc/nginx/templates/default.conf.template:ro
- ./data/https/leaf.crt:/etc/nginx/https/leaf.crt:ro
- ./data/https/leaf.key:/etc/nginx/https/leaf.key:ro
# The app routes scripts/https-app.sh writes (a directory, so a rewrite shows up).
- ./data/https/nginx:/etc/nginx/devnet:ro
networks:
atproto-devnet:
aliases:
- alpha.${DEVNET_DOMAIN:-devnet.test}
- regular.${DEVNET_DOMAIN:-devnet.test}
- prod.${DEVNET_DOMAIN:-devnet.test}
healthcheck:
test: ["CMD", "nginx", "-t", "-q"]
interval: 5s
timeout: 3s
retries: 10
volumes:
plc-db:
slingshot-data: