chore: harden docker-compose deployment (bind, memory limits, no-new-privileges)
- frontend publishes on ${FRONTEND_PUBLISH_ADDR:-127.0.0.1} not 0.0.0.0 (M4).
- mem_limit on backend(4g)/postgres(1g)/frontend(512m), .env-overridable (M3).
- security_opt: no-new-privileges on app + postgres services.
New knobs documented + allowlisted in the config meta-test; compose validates.
Deferred (need host verification): image pinning, backend healthcheck, cap_drop
on postgres/tor, Postgres backup sidecar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
11
.env.example
11
.env.example
@@ -427,3 +427,14 @@ VISION_MANAGER_DATABASE_URL=
|
||||
# VISION_MEM_LOW_WATERMARK_PCT used% >= this → inhibit starts (keep HIGH - LOW >= ~10 so the band beats jitter). Default 80.
|
||||
# VISION_MEM_YIELD_COOLDOWN Seconds after a pressure-stop during which restart is refused regardless of backlog. Default 300.
|
||||
# VISION_MEM_POLL_INTERVAL Mem sub-poll cadence, seconds (<= VISION_POLL_INTERVAL); catches spikes between backlog ticks. Default 5.
|
||||
|
||||
# ---- Deployment resource bounds & exposure (docker-compose.yml) ----
|
||||
# Host interface the frontend port publishes on. Default 127.0.0.1 so SvelteKit
|
||||
# (plain HTTP) is reachable only by a host-local reverse proxy. Set 0.0.0.0 only
|
||||
# if your TLS terminator runs on a different host.
|
||||
FRONTEND_PUBLISH_ADDR=127.0.0.1
|
||||
# Per-container memory ceilings (docker mem_limit). Generous defaults; tune to
|
||||
# your host. The backend runs OCR + headless Chromium and is the heavy one.
|
||||
BACKEND_MEM_LIMIT=4g
|
||||
FRONTEND_MEM_LIMIT=512m
|
||||
POSTGRES_MEM_LIMIT=1g
|
||||
|
||||
@@ -1096,6 +1096,13 @@ mod tests {
|
||||
"BACKEND_URL",
|
||||
"BACKEND_PROXY_TIMEOUT_MS",
|
||||
"VISION_MANAGER_DATABASE_URL",
|
||||
// Compose-level deployment knobs (port publish interface + per-container
|
||||
// memory ceilings) — consumed by docker-compose.yml itself, never read
|
||||
// by the backend process, so they don't belong in its environment block.
|
||||
"FRONTEND_PUBLISH_ADDR",
|
||||
"BACKEND_MEM_LIMIT",
|
||||
"FRONTEND_MEM_LIMIT",
|
||||
"POSTGRES_MEM_LIMIT",
|
||||
];
|
||||
|
||||
/// Keys whose compose RHS is intentionally NOT a `${KEY...}`
|
||||
|
||||
@@ -23,6 +23,12 @@ services:
|
||||
# takes the whole stack offline. Match the policy already set on
|
||||
# tor / docker-socket-proxy / vision-manager.
|
||||
restart: unless-stopped
|
||||
# Bound Postgres so a runaway query/backlog can't consume all host RAM.
|
||||
# Tune to your host via .env (should comfortably exceed shared_buffers +
|
||||
# work_mem * max_connections).
|
||||
mem_limit: ${POSTGRES_MEM_LIMIT:-1g}
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
tor:
|
||||
# SOCKS5 proxy for the crawler, plus a control port so the backend
|
||||
@@ -197,6 +203,13 @@ services:
|
||||
expose:
|
||||
- "8080"
|
||||
restart: unless-stopped
|
||||
# Bound the heaviest consumer: the backend hosts the OCR/analysis worker and
|
||||
# drives a headless Chromium crawler, either of which can balloon and
|
||||
# OOM-kill the host (taking Postgres with it) with no limit. Tune to your
|
||||
# host via .env — this default is a generous ceiling, not a target.
|
||||
mem_limit: ${BACKEND_MEM_LIMIT:-4g}
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
frontend:
|
||||
build: ./frontend
|
||||
@@ -213,8 +226,17 @@ services:
|
||||
# to 300000 (5 min) in hooks.server.ts; raise/lower via .env.
|
||||
BACKEND_PROXY_TIMEOUT_MS: ${BACKEND_PROXY_TIMEOUT_MS:-300000}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
# Bind to loopback by default so SvelteKit (plain HTTP; COOKIE_SECURE=true
|
||||
# expects TLS in front) is reachable ONLY by a host-local reverse proxy,
|
||||
# not cleartext over the LAN/internet. A host-external TLS terminator can
|
||||
# set FRONTEND_PUBLISH_ADDR=0.0.0.0 (or a specific interface) in .env.
|
||||
- "${FRONTEND_PUBLISH_ADDR:-127.0.0.1}:3000:3000"
|
||||
restart: unless-stopped
|
||||
# Cap runaway memory (SvelteKit is light, but bound it anyway) and forbid
|
||||
# privilege escalation. Tune the limit to your host via .env.
|
||||
mem_limit: ${FRONTEND_MEM_LIMIT:-512m}
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
# ----- Vision autoscaling (profile: ai) -----------------------------------
|
||||
# Two extra containers that idle-stop the mangalord-vision (llama.cpp)
|
||||
|
||||
Reference in New Issue
Block a user