Files
proxy/docker-compose.yml
wmantly 8e78604a37 Persist Redis (AOF+vol), read config from mounted secrets.js, add backup/restore docs (#118)
Lossless upgrades + config story for the all-in-one proxy image.

Redis persistence (Part A):
- Replace in-memory `--save "" --appendonly no` with AOF + RDB persisted to
  /data. Host records, permissions, DNS creds, local users, AND the
  lua-resty-auto-ssl Let's Encrypt certs now all survive container recreation
  (persisting Redis persists the cert store — no LE re-issue / rate-limit on
  rebuild).
- Add the `proxy-data` named volume -> /data in docker-compose.yml; fix the
  stale "in-memory, lost on recreation" comment.

Config from ./config/proxy-secrets.js (Part B):
- docker-entrypoint.sh: when /config/proxy-secrets.js is mounted, symlink it to
  /app/conf/secrets.js so @simpleworkjs/conf reads the oidc/ldap/auth config
  from the file. No app_* env should then be passed (app_* beats secrets.js).
  Falls back to app_* env when the file is absent (standalone still works).
- docker-compose.yml: drop all app_oidc__* / app_ldap__* / app_auth__* env and
  add `./config:/config:ro`. Keep RESOLVER/REAL_IP_FROM/NODE_ENV/NODE_PORT
  (OpenResty-runtime / process env, not app_* config). No env_file.
- New secrets.js.example (the proxy had none): oidc (enabled, endpoints,
  clientId/clientSecret, redirectUri, scopes, claims), ldap (url, bindDN,
  bindPassword, searchBase, userFilter, tlsOptions), auth (adminGroups,
  adminUsers, groupRoleMap), plus an orchestrator-only `stack` key.

Backup/restore docs:
- Full "Backups and restore" runbook in DEPLOYMENT.md (what lives where, manual
  backup, Redis restore with the AOF-vs-RDB note — AOF wins on startup so the
  AOF must be deleted before an RDB load; restoring Redis restores cert state
  at snapshot time; migrations note). Update the Setup + Auto-SSL sections.
- docs/docker.md: update Quick start + How configuration works + Auto-SSL for
  the new ./config/ approach (app_* env now advanced/optional).

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-12 13:00:34 -04:00

68 lines
3.0 KiB
YAML

# Docker Compose for the theta42/proxy all-in-one image
# (OpenResty + Node management app + Redis in one container).
#
# The proxy is an OIDC client of an SSO Manager (or any OIDC provider) AND a
# direct LDAP client for user lookups. That wiring (oidc/ldap/auth) is read from
# a bind-mounted ./config/proxy-secrets.js — docker-entrypoint.sh symlinks it
# into /app/conf/secrets.js so @simpleworkjs/conf reads it. No app_* env is
# passed here: app_* env beats secrets.js in @simpleworkjs/conf (precedence:
# base.js < <env>.js < secrets.js < app_* env), so the file must be the only
# source. See secrets.js.example for the shape.
#
# Compose only interpolates the port + OpenResty-runtime defaults below — there
# is no .env file. Override on the command line if needed:
# HTTP_PORT=8080 HTTPS_PORT=8443 docker compose up -d
#
# Requires @simpleworkjs/conf >= 1.1.0 in the image. The lock is already on
# ^1.1.0; rebuild with `docker compose up -d --build` after any package change.
services:
proxy:
build:
context: .
dockerfile: Dockerfile
container_name: proxy
restart: unless-stopped
ports:
# Public proxy listeners (autossl.conf). 80 is used for ACME HTTP-01 +
# redirecting to HTTPS; 443 is the primary; 4443 is the alternate HTTPS.
- "${HTTP_PORT:-80}:80"
- "${HTTPS_PORT:-443}:443"
- "${HTTPS_ALT_PORT:-4443}:4443"
# Management API + web UI. Bind to localhost so it isn't exposed to the
# LAN — the OpenResty front proxies the UI/api under its own TLS.
- "127.0.0.1:${MGMT_PORT:-3000}:3000"
environment:
# OpenResty runtime (see docker-entrypoint.sh). These are NOT app_* config
# keys, so they don't conflict with secrets.js. oidc/ldap/auth config comes
# from ./config/proxy-secrets.js, not from env.
# Resolver for upstream names in Host records (default = Docker DNS).
- RESOLVER=${RESOLVER:-127.0.0.11}
# Trusted range for X-Real-IP. Empty = proxy is the front (default,
# removes the real_ip block). Set to an upstream proxy's CIDR if one
# sits in front and sets X-Real-IP.
- REAL_IP_FROM=${REAL_IP_FROM:-}
- NODE_ENV=production
- NODE_PORT=3000
volumes:
# Operator-edited secrets (proxy-secrets.js). The entrypoint symlinks
# /config/proxy-secrets.js -> /app/conf/secrets.js so @simpleworkjs/conf
# reads the oidc/ldap/auth config. See secrets.js.example for the shape.
- ./config:/config:ro
# Persist Redis (AOF + RDB) so Host records, permissions, DNS creds, local
# users, AND the lua-resty-auto-ssl Let's Encrypt certs survive container
# recreation. Restoring Redis also restores cert state at snapshot time.
- proxy-data:/data
- proxy-cache:/var/cache/nginx/proxy
- proxy-logs:/var/log/nginx
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
volumes:
proxy-cache:
proxy-logs:
proxy-data: