Files
sso-manager-node/docker-compose.yml
wmantly 6920a9f9f0 Persist Redis (AOF+vol), read config from mounted secrets.js, add backup/restore docs (#34)
Lossless upgrades + config story for the all-in-one image.

Redis persistence (Part A):
- Replace in-memory `--save "" --appendonly no` with AOF + RDB persisted to /data
  (--appendonly yes, periodic saves, --dbfilename dump.rdb). OAuth clients,
  tokens, and other model-redis state now survive container recreation.
- Add the `sso-data` named volume -> /data in docker-compose.yml.

Config from ./config/sso-secrets.js (Part B):
- docker-entrypoint.sh: when /config/sso-secrets.js is mounted, symlink it to
  /app/conf/secrets.js and read the server-side LDAP vars (base DN, admin pass,
  org, domain, cert CN, JWT) from the file via one `node` call (base64-decoded,
  no eval/quoting hazards). No app_* env is exported in this mode, so the file
  is authoritative (@simpleworkjs/conf precedence: base < env < secrets.js <
  app_* env). Falls back to the existing LDAP_* env-var mode when the file is
  absent (standalone/bare-metal still works).
- docker-compose.yml: trim `environment:` to NODE_ENV/NODE_PORT only and add
  `./config:/config:ro`. Removing the app_* env is required — any leftover
  app_* would silently override secrets.js.
- secrets.js.example: add orchestrator-only `stack`, `bootstrap`, and
  `serviceAccountPass` keys (ignored by the app; read by the entrypoint, the
  theta-env bootstrap, and setup.sh).

Backup/restore docs:
- Full "Backups and restore" runbook in DEPLOYMENT.md (what lives where,
  manual backup, full / Redis-only / LDAP-only restore, AOF-vs-RDB note,
  upgrades). Restore uses slapadd -f (static slapd.conf), and RDB restore
  requires deleting the AOF first (AOF wins on startup).
- Pointers in docs/deployment.md and docs/ldap.md; update the Docker Setup
  section for the new ./config/ approach (env vars now advanced/optional).

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

71 lines
3.2 KiB
YAML

# Docker Compose for the SSO Manager all-in-one image (app + OpenLDAP in one container).
#
# The image (Dockerfile.openldap) bundles a slapd that the app talks to over
# localhost. The app reads its configuration from conf/base.js + conf/secrets.js
# (deep-merged by @simpleworkjs/conf). The operator-edited secrets live in a
# bind-mounted ./config/sso-secrets.js, which docker-entrypoint.sh symlinks into
# /app/conf/secrets.js on startup. No app_* env vars are passed here: any app_*
# env would override secrets.js (env beats the file in @simpleworkjs/conf), so
# the file must be the only source.
#
# Compose only interpolates the port defaults below — there is no .env file.
# Override a port on the command line if needed:
# PORT=3002 LDAPS_PORT=1636 docker compose up -d
#
# Requires @simpleworkjs/conf >= 1.1.0 in the image. Refresh
# nodejs/package-lock.json with `npm install @simpleworkjs/conf@^1.1.0` before
# building.
services:
sso-manager:
build:
context: .
dockerfile: Dockerfile.openldap
container_name: sso-manager
restart: unless-stopped
ports:
# SSO Manager web UI (HTTP inside the container; terminate TLS at the
# front proxy — e.g. the theta42/proxy). Don't expose 3001 to the open
# internet; bind it to localhost or leave it on the docker network only.
- "${PORT:-3001}:3001"
# LDAPS — direct LDAP binds from legacy apps / the proxy over the network
# (TLS, self-signed cert by default; mount your own at LDAP_CERT_DIR).
- "${LDAPS_PORT:-636}:636"
# LDAP plain (389) is NOT mapped to the host by default — it would allow
# cleartext password binds over the LAN. Uncomment to permit StartTLS or
# plain binds from the LAN (not recommended):
# - "${LDAP_PORT:-389}:389"
environment:
# Config (LDAP, OAuth, SMTP, ...) comes from ./config/sso-secrets.js (see
# volumes below), not from env. NODE_ENV/NODE_PORT are the only env the app
# reads that are not part of its conf tree.
- NODE_ENV=production
- NODE_PORT=3001
volumes:
# Operator-edited secrets (sso-secrets.js). The entrypoint symlinks
# /config/sso-secrets.js -> /app/conf/secrets.js so @simpleworkjs/conf reads
# it. See secrets.js.example / config.example/ for the shape.
- ./config:/config:ro
# Persist the LDAP database across container recreation.
- ldap-data:/var/lib/ldap
# Persist the auto-generated self-signed TLS cert so clients don't have to
# re-trust it on every rebuild. To use your own CA-signed cert instead,
# replace this with a bind mount of your cert dir, e.g.:
# - ./certs:/etc/openldap/certs
# (must contain ldap.crt + ldap.key; the entrypoint leaves them untouched).
- ldap-certs:/etc/openldap/certs
# Persist Redis (AOF + RDB) so OAuth clients, tokens, and other
# Redis-backed state survive container recreation. Restoring Redis also
# restores lua-resty-auto-ssl cert state if this image fronts a proxy.
- sso-data:/data
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
volumes:
ldap-data:
ldap-certs:
sso-data: