Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
428 lines (419 loc) · 20.3 KB
/
Copy pathdocker-compose.yml
File metadata and controls
428 lines (419 loc) · 20.3 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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# Oneirodex Docker Compose — Unraid / NAS
# App always connects to the Compose service named "db".
#
# ---------------------------------------------------------------------------
# UNRAID VOLUMES (host .env → container mounts)
# Do NOT conflate these two mounts.
#
# GAMES (scan root only — never uploads)
# Host: DATA_FOLDER_GAMES
# Mount: → /storage:ro
# App env: DATA_FOLDER_GAMES=/storage (container path; hard-set below)
#
# LIBRARY / UPLOADS (covers, themes, user uploads)
# Host: LIBRARY_HOST_PATH
# Mount: → /app/oneirodex/static/library (RW)
# App env: UPLOAD_FOLDER=/app/oneirodex/static/library (hard-set below)
#
# BIOS / FIRMWARE (optional — household Unraid only; never ship binaries in git/image)
# Host: EMULATOR_BIOS_HOST_PATH (appdata, NOT the games share)
# Mount: → /app/oneirodex/static/library/bios (RW; nested under library mount)
# App env: EMULATOR_BIOS_PATH=/app/oneirodex/static/library/bios
# Public/GitHub stance: Admin upload only — do not bake firmware into layers.
# Uncomment the bind below when the host folder has legally obtained files.
#
# Unraid path examples: .env.unraid.example
# Profiles (opt-in): livekit | clamav | challenge
# Observability: commented stub only — see docs/runbooks/observability-profile.md
#
# P3b (ADR 0003): new installs default to oneirodex-* names. Live Unraid stacks
# that still run oneirodex-app / oneirodex-db should pin those names in .env
# until the scan FIFO is idle, then drop the pins so Compose recreates:
# APP_IMAGE=oneirodex:1.1.8
# APP_CONTAINER_NAME=oneirodex-app
# DB_CONTAINER_NAME=oneirodex-db
# Preferred Hub image: cephyrixzyth/oneirodex:1.1.8. Postgres *database* name stays
# POSTGRES_DB (default oneirodex) so existing volumes keep their catalog.
# Sidecar profile container names (livekit / clamav / …) are unchanged.
# ---------------------------------------------------------------------------
services:
app:
build:
context: .
dockerfile: Dockerfile
# Filled by scripts/ops/unraid_ship_update_now.py at deploy time; empty
# for a hand-run `docker compose build`, which the Ops tile reports as
# "n/a" rather than guessing.
args:
ONEIRODEX_BUILD_SHA: ${ONEIRODEX_BUILD_SHA:-}
ONEIRODEX_BUILT_AT: ${ONEIRODEX_BUILT_AT:-}
image: ${APP_IMAGE:-oneirodex:1.1.8}
container_name: ${APP_CONTAINER_NAME:-oneirodex-app}
restart: unless-stopped
ports:
- "5006:5006"
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-oneirodex}
- DATABASE_HOST=db
- DATABASE_PORT=5432
# Container paths (always); host paths live on the volume mounts below
- DATA_FOLDER_GAMES=/storage
# Extra scan locations, as the CONTAINER sees them. Every path listed
# here needs a matching bind mount below, otherwise it is a root that
# browses as an empty folder. See docs/runbooks/remote-scan-locations.md
# ONEIRODEX_LIBRARY_ROOTS=NAS ROMs=/storage2|Archive=/storage3
- ONEIRODEX_LIBRARY_ROOTS=${ONEIRODEX_LIBRARY_ROOTS:-}
- UPLOAD_FOLDER=/app/oneirodex/static/library
- SECRET_KEY=${SECRET_KEY}
- DEV_MODE=${DEV_MODE:-false}
- POSTGRES_USER=${POSTGRES_USER:-postgres}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
- POSTGRES_DB=${POSTGRES_DB:-oneirodex}
- ENABLE_ARR_MODULE=${ENABLE_ARR_MODULE:-true}
- ENABLE_ARR_HARDLINK_PIPELINE=${ENABLE_ARR_HARDLINK_PIPELINE:-true}
- ALLOW_PRIVATE_LAN_URLS=${ALLOW_PRIVATE_LAN_URLS:-true}
- ENABLE_AI_ASSIST=${ENABLE_AI_ASSIST:-true}
- ENABLE_AI_AUTO_APPLY=${ENABLE_AI_AUTO_APPLY:-false}
# Generated covers (FEAT-D3). Compose has no env_file dump — host .env keys
# only reach the container when listed here. Point AI_ARTWORK_URL at a LAN
# GPU box (see docs/runbooks/artwork-gpu-workstation.md); do not rely on
# the optional `artwork` profile on a GPU-less NAS.
- ENABLE_AI_ARTWORK=${ENABLE_AI_ARTWORK:-false}
- AI_ARTWORK_URL=${AI_ARTWORK_URL:-}
- AI_ARTWORK_ENGINE=${AI_ARTWORK_ENGINE:-a1111}
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
- OLLAMA_MODEL=${OLLAMA_MODEL:-llama3.2}
- ENABLE_HARDLINK_HELPERS=${ENABLE_HARDLINK_HELPERS:-true}
- ALLOW_HARDLINK_APPLY=${ALLOW_HARDLINK_APPLY:-false}
- ENABLE_VR_BROWSE=${ENABLE_VR_BROWSE:-true}
- OIDC_ENABLED=${OIDC_ENABLED:-false}
- OIDC_ISSUER_URL=${OIDC_ISSUER_URL:-}
- OIDC_CLIENT_ID=${OIDC_CLIENT_ID:-}
- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET:-}
- OIDC_REDIRECT_URI=${OIDC_REDIRECT_URI:-}
- OIDC_SCOPES=${OIDC_SCOPES:-openid email profile}
- OIDC_ROLE_CLAIM=${OIDC_ROLE_CLAIM:-groups}
- OIDC_ROLE_MAP=${OIDC_ROLE_MAP:-}
- OIDC_DISPLAY_NAME=${OIDC_DISPLAY_NAME:-Sign in with SSO}
- ENABLE_MOD_TRACKING=${ENABLE_MOD_TRACKING:-true}
- ENABLE_ACTIVITY_FEED=${ENABLE_ACTIVITY_FEED:-true}
- ENABLE_FREE_GAMES=${ENABLE_FREE_GAMES:-true}
- ENABLE_DISCOVER_ML=${ENABLE_DISCOVER_ML:-true}
- ENABLE_EMAIL_DIGEST=${ENABLE_EMAIL_DIGEST:-true}
- ENABLE_LOGIN_RATE_LIMIT=${ENABLE_LOGIN_RATE_LIMIT:-true}
- ENABLE_REMOTE_PLAY=${ENABLE_REMOTE_PLAY:-false}
- ENABLE_AMBIENT_LIGHTING=${ENABLE_AMBIENT_LIGHTING:-false}
- PROWLARR_URL=${PROWLARR_URL:-}
- PROWLARR_API_KEY=${PROWLARR_API_KEY:-}
- JACKETT_URL=${JACKETT_URL:-}
- JACKETT_API_KEY=${JACKETT_API_KEY:-}
- QBITTORRENT_URL=${QBITTORRENT_URL:-}
- QBITTORRENT_USERNAME=${QBITTORRENT_USERNAME:-admin}
- QBITTORRENT_PASSWORD=${QBITTORRENT_PASSWORD:-}
# Secure cookies are required by default; set false only for deliberate
# direct-HTTP LAN/development access (cookies can then cross the network).
- SESSION_COOKIE_SECURE=${SESSION_COOKIE_SECURE:-true}
- REMEMBER_COOKIE_SECURE=${REMEMBER_COOKIE_SECURE:-true}
- CHAT_ATTACHMENT_STORAGE_MAX_BYTES=${CHAT_ATTACHMENT_STORAGE_MAX_BYTES:-1073741824}
- CHAT_ATTACHMENT_STORAGE_MAX_FILES=${CHAT_ATTACHMENT_STORAGE_MAX_FILES:-10000}
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-0}
- ENABLE_LIVEKIT=${ENABLE_LIVEKIT:-true}
- LIVEKIT_URL=${LIVEKIT_URL:-}
- LIVEKIT_API_KEY=${LIVEKIT_API_KEY:-}
- LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET:-}
- ENABLE_MALWARE_SCAN=${ENABLE_MALWARE_SCAN:-true}
- MALWARE_SCAN_BLOCK_ON_HIT=${MALWARE_SCAN_BLOCK_ON_HIT:-true}
- CLAMAV_HOST=${CLAMAV_HOST:-clamav}
- CLAMAV_PORT=${CLAMAV_PORT:-3310}
- CLAMAV_SOCKET=${CLAMAV_SOCKET:-}
- ENABLE_GAME_ASSISTS=${ENABLE_GAME_ASSISTS:-true}
- ENABLE_DEBRID=${ENABLE_DEBRID:-true}
- ENABLE_PCDOS_BROWSER=${ENABLE_PCDOS_BROWSER:-true}
- ENABLE_RUFFLE=${ENABLE_RUFFLE:-true}
- ENABLE_ROM_PATCH_APPLY=${ENABLE_ROM_PATCH_APPLY:-true}
- ENABLE_PATCH_CATALOG=${ENABLE_PATCH_CATALOG:-true}
- ENABLE_ROM_AI_TRANSLATE=${ENABLE_ROM_AI_TRANSLATE:-true}
- SUPPORT_GITHUB_TOKEN=${SUPPORT_GITHUB_TOKEN:-}
- SUPPORT_GITHUB_REPO=${SUPPORT_GITHUB_REPO:-cephyrixzyth/oneirodex}
# Challenge / captcha solver (opt-in — set ENABLE_CHALLENGE_SOLVER=true + URL)
- ENABLE_CHALLENGE_SOLVER=${ENABLE_CHALLENGE_SOLVER:-false}
- CHALLENGE_SOLVER_URL=${CHALLENGE_SOLVER_URL:-}
- CHALLENGE_SOLVER_PROVIDER=${CHALLENGE_SOLVER_PROVIDER:-flaresolverr_compat}
- CHALLENGE_SOLVER_TIMEOUT_MS=${CHALLENGE_SOLVER_TIMEOUT_MS:-60000}
- CHALLENGE_SOLVER_MAX_TIER=${CHALLENGE_SOLVER_MAX_TIER:-5}
# Default 1 — SSE/schedulers single-process; override UVICORN_WORKERS=2 OK
- UVICORN_WORKERS=${UVICORN_WORKERS:-1}
# Optional private BIOS mount (container path). Default matches static library bios
# so WebRetro / Admin see the same folder. Requires config.EMULATOR_BIOS_PATH
# from env (Backend) when overriding away from the default path.
- EMULATOR_BIOS_PATH=${EMULATOR_BIOS_PATH:-/app/oneirodex/static/library/bios}
extra_hosts:
- "host.docker.internal:host-gateway"
# ----- UNRAID VOLUMES (see header) -----
volumes:
# Games: host DATA_FOLDER_GAMES → scan root only (RO). Never put uploads here.
- "${DATA_FOLDER_GAMES}:/storage:ro"
# Library/uploads: host LIBRARY_HOST_PATH → covers, themes, uploads (RW)
- "${LIBRARY_HOST_PATH:-./data/library}:/app/oneirodex/static/library"
# Extra scan locations (second disk, NAS share, another appdata share).
# Uncomment one line per location, mount it RO like /storage, and list the
# container path in ONEIRODEX_LIBRARY_ROOTS above. The host side is mounted by
# the host — Docker binds what the kernel already has, it does not speak
# SMB or NFS itself. See docs/runbooks/remote-scan-locations.md
# - "${LIBRARY_ROOT_2_HOST_PATH}:/storage2:ro"
# - "${LIBRARY_ROOT_3_HOST_PATH}:/storage3:ro"
# - "${LIBRARY_ROOT_4_HOST_PATH}:/storage4:ro"
# Optional WebRetro cores bind-mount (PCE/VICE/DOS). Host dir must include
# the shipped 24 cores OR run scripts/fetch-webretro-cores.sh --defaults first —
# an empty mount hides image cores. See docs/runbooks/webretro-cores.md
- "${WEBRETRO_CORES_HOST_PATH:-/mnt/cache/appdata/oneirodex/webretro-cores}:/app/oneirodex/static/vendor/webretro/cores"
# Optional private BIOS / firmware (RW appdata — NOT /storage:ro games).
# Host example: /mnt/user/appdata/oneirodex/bios
# Nested bind overrides LIBRARY_HOST_PATH/bios so dumps stay out of the
# games share. Empty host dir is fine (Admin upload still works into it).
# Never commit BIOS binaries; never bake them into the public image.
# - "${EMULATOR_BIOS_HOST_PATH:-/mnt/user/appdata/oneirodex/bios}:/app/oneirodex/static/library/bios"
depends_on:
db:
condition: service_healthy
healthcheck:
# /awake requires DB + startup init — do not probe login/setup "/"
test: ["CMD-SHELL", "curl -f http://localhost:5006/awake || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
db:
image: postgres:17.6
container_name: ${DB_CONTAINER_NAME:-oneirodex-db}
restart: unless-stopped
shm_size: 128mb
environment:
- POSTGRES_USER=${POSTGRES_USER:-postgres}
# SET A STRONG PASSWORD in .env (.env.*.example say how to generate one).
# The `postgres` fallback only exists so a stack whose .env predates this
# variable keeps starting; it is a known password, so never rely on it on a
# host anyone else can reach. Postgres reads this only when it first creates
# the db_data volume: changing it later does NOT rotate an existing database
# (docs/runbooks/docker-compose-deploy.md § Postgres password).
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
- POSTGRES_DB=${POSTGRES_DB:-oneirodex}
- PGDATA=/var/lib/postgresql/data/pgdata
# Force a Compose-friendly HBA so Docker-bridge IPs can connect without SSL.
# (Stale volume pg_hba with only hostssl → "no encryption" / no pg_hba entry.)
# listen_addresses=* is required INSIDE the container: the app reaches db over
# the Compose bridge network. What keeps it off the LAN is the published-port
# bind below plus the private-range rules in docker/postgres/pg_hba.conf.
command:
- postgres
- -c
- listen_addresses=*
- -c
- hba_file=/etc/oneirodex/pg_hba.conf
volumes:
- db_data:/var/lib/postgresql/data/pgdata
- ./docker/postgres/pg_hba.conf:/etc/oneirodex/pg_hba.conf:ro
ports:
# Host access for local pytest / native app against Compose Postgres.
# Loopback only by default: a Postgres superuser login must not be offered
# to the whole LAN. To reach it from another machine, opt in explicitly
# (POSTGRES_HOST_BIND=0.0.0.0, or the host's LAN IP) AND set a strong
# POSTGRES_PASSWORD. The app container never uses this mapping.
- "${POSTGRES_HOST_BIND:-127.0.0.1}:${POSTGRES_HOST_PORT:-5432}:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\""]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
# Optional LiveKit SFU — start with: docker compose --profile livekit up -d
#
# Not in --dev mode. Dev mode ships the public key pair devkey/secret, so
# anyone who can reach :7880 could mint room tokens. The pair now comes from
# LIVEKIT_API_KEY / LIVEKIT_API_SECRET in .env, the same two values the app
# reads to mint tokens, so there is one source of truth. Generate them
# (.env.*.example say how) — with either empty LiveKit refuses to start
# ("one of key-file or keys must be provided") rather than running open.
# Keep the key and secret alphanumeric (no $ : # or quotes) and the secret at
# least 32 characters. If you still carry devkey/secret from an older
# template it starts, but logs "secret is too short" — rotate both.
#
# --udp-port 7882 is load-bearing once --dev is gone: dev mode quietly pinned
# WebRTC media to the single UDP port 7882; without it LiveKit uses UDP
# 50000-60000, which this file does not publish, and audio would never flow.
livekit:
profiles: ['livekit']
image: livekit/livekit-server:v1.8.4
container_name: oneirodex-livekit
restart: unless-stopped
command: --bind 0.0.0.0 --port 7880 --udp-port 7882
environment:
# Must read exactly "key: secret", colon and space included, so the whole
# entry is quoted for YAML.
- "LIVEKIT_KEYS=${LIVEKIT_API_KEY:-}: ${LIVEKIT_API_SECRET:-}"
ports:
- "${LIVEKIT_HOST_PORT:-7880}:7880"
- "${LIVEKIT_RTC_PORT:-7881}:7881"
- "${LIVEKIT_UDP_PORT:-7882}:7882/udp"
# Optional ClamAV (clamd) — start with: docker compose --profile clamav up -d
# App uses CLAMAV_HOST=clamav:3310 by default. On Unraid you can instead bind-mount
# a host clamd socket and set CLAMAV_SOCKET=/run/clamav/clamd.sock (see runbook).
clamav:
profiles: ['clamav']
image: clamav/clamav:1.4
container_name: oneirodex-clamav
restart: unless-stopped
volumes:
- clamav_db:/var/lib/clamav
healthcheck:
test: ['CMD', '/usr/local/bin/clamdcheck.sh']
interval: 60s
timeout: 10s
retries: 5
start_period: 300s
# Optional TRAWL challenge solver — start with: docker compose --profile challenge up -d
# Redis + TRAWL sidecar for FlareSolverr-compatible /v1. No host ports — Docker/LAN only.
# Set ENABLE_CHALLENGE_SOLVER=true and CHALLENGE_SOLVER_URL=http://trawl:8191 on app.
# Old NAS / kernel <5.1: TRAWL_IMAGE=ghcr.io/germondai/trawl:baseline — see runbook.
challenge-redis:
profiles: ['challenge']
image: redis:8.10.2-alpine
container_name: oneirodex-challenge-redis
restart: unless-stopped
volumes:
- challenge_redis_data:/data
trawl:
profiles: ['challenge']
image: ${TRAWL_IMAGE:-ghcr.io/germondai/trawl:latest}
container_name: oneirodex-trawl
restart: unless-stopped
shm_size: 1gb
environment:
- REDIS_URL=redis://challenge-redis:6379
- BROWSER_POOL_SIZE=${TRAWL_BROWSER_POOL_SIZE:-3}
- MITM_PROXY_ENABLED=${TRAWL_MITM_PROXY_ENABLED:-false}
- MITM_PROXY_HOST=0.0.0.0
- MITM_PROXY_PORT=8192
- MITM_PROXY_CA_DIR=/data/proxy-ca
- MITM_PROXY_MAX_TIER=${TRAWL_MITM_PROXY_MAX_TIER:-4}
volumes:
- trawl_proxy_ca:/data/proxy-ca
depends_on:
- challenge-redis
healthcheck:
test: ['CMD', 'curl', '-sf', 'http://localhost:8191/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 90s
# ---------------------------------------------------------------------------
# profile: artwork — OPTIONAL generated cover art (FEAT-D3)
#
# Not started unless you ask for it: docker compose --profile artwork up -d
# Then set in .env: ENABLE_AI_ARTWORK=true
# AI_ARTWORK_URL=http://sdnext:7860
#
# SD.Next speaks the same /sdapi/v1/txt2img API as AUTOMATIC1111 and Forge, so
# AI_ARTWORK_ENGINE=a1111 covers all three. Nothing leaves your network.
#
# NOTE: image generation wants a GPU, and this file never asks for one. On CPU
# it runs and is extremely slow rather than failing, which is the right
# default: an NVIDIA `deploy` reservation on a host without a loaded driver
# hard-fails container create ("nvml error: driver not loaded") and takes the
# whole `compose up` with it. Two ways to get the GPU, neither of them an edit
# to this file:
#
# GPU in the Docker host → docker-compose.gpu.yml, via COMPOSE_FILE
# GPU on another machine → docker-compose.artwork-local.yml on that box
# (Windows 2080 workstation: see
# docs/runbooks/artwork-gpu-workstation.md), then
# AI_ARTWORK_URL=http://<that-host>:7860 and do
# not start this profile at all
# ---------------------------------------------------------------------------
sdnext:
profiles: ['artwork']
image: ${SDNEXT_IMAGE:-saladtechnologies/sdnext:latest}
container_name: oneirodex-sdnext
restart: unless-stopped
environment:
- SD_NOHASHING=true
# The image ships a CMD that still passes `--skip-tests`, a flag its own
# pinned SD.Next checkout (f45b3328, 2023-12-12) never defined — argparse
# exits before the server binds, so the container restart-loops with
# "error: unrecognized arguments: --skip-tests". This is the stock CMD
# minus that flag; `--skip-torch` already covers the torch test it meant.
command:
- --listen
- --no-download
- --docs
- --skip-requirements
- --skip-extensions
- --skip-git
- --skip-torch
- --quick
volumes:
# The app lives at /webui with DATA_DIR=/webui/data (models resolve to
# <data-dir>/models) and runs with cwd=/webui, so generated images land
# in /webui/outputs. There is no /app in this image.
- sdnext_models:/webui/data/models
- sdnext_outputs:/webui/outputs
ports:
# SD.Next has no login. Loopback by default so only this host can open its
# UI; the app reaches it over the Compose network (AI_ARTWORK_URL=
# http://sdnext:7860) and does not use this mapping. To browse it from
# another machine set SDNEXT_HOST_BIND to this host's LAN IP.
- "${SDNEXT_HOST_BIND:-127.0.0.1}:${SDNEXT_HOST_PORT:-7860}:7860"
# No `deploy:` GPU reservation here on purpose — see the note above. It used
# to sit commented out at this spot, which invited exactly one fix ("just
# uncomment it") and no way to undo that per host. It lives in
# docker-compose.gpu.yml now.
#
# The image has no curl (it is a conda-based image; wget is what ships), so
# a curl healthcheck can only ever fail with "executable file not found" and
# the container sits unhealthy forever while serving fine.
healthcheck:
test: ['CMD', 'wget', '-q', '-O', '/dev/null', 'http://localhost:7860/sdapi/v1/sd-models']
interval: 30s
timeout: 10s
retries: 3
start_period: 180s
# ---------------------------------------------------------------------------
# profile: observability — OPTIONAL stub (not enabled; no images required)
# Prometheus/Grafana are NOT bundled for 1.0. Prefer Admin → Ops + /pulse
# + /awake. When you add scrape later, uncomment and wire your own config —
# see docs/runbooks/observability-profile.md. Do not enable until /metrics
# (or an equivalent scrape target) exists and is auth-gated.
# ---------------------------------------------------------------------------
# prometheus:
# profiles: ['observability']
# image: prom/prometheus:v2.54.1
# container_name: oneirodex-prometheus
# restart: unless-stopped
# volumes:
# - ./ops/prometheus.yml:/etc/prometheus/prometheus.yml:ro
# - prometheus_data:/prometheus
# ports:
# - "${PROMETHEUS_HOST_PORT:-9090}:9090"
# grafana:
# profiles: ['observability']
# image: grafana/grafana:11.2.0
# container_name: oneirodex-grafana
# restart: unless-stopped
# depends_on: [prometheus]
# ports:
# - "${GRAFANA_HOST_PORT:-3000}:3000"
# volumes:
# - grafana_data:/var/lib/grafana
volumes:
db_data:
driver: local
clamav_db:
driver: local
challenge_redis_data:
driver: local
trawl_proxy_ca:
driver: local
sdnext_models:
driver: local
sdnext_outputs:
driver: local