8.1 KiB
Operations And Configuration
Runtime Services
docker-compose.yml defines:
db(Postgres 16)redis(Redis 7)typesense(Typesense 29)api(FastAPI backend)worker(RQ worker viapython -m app.worker.run_worker)frontend(Vite React UI)
Persistent volumes:
db-dataredis-datadcm-storagetypesense-data
Reset all persisted runtime data:
docker compose down -v
Core Commands
Start or rebuild:
docker compose up --build -d
Stop:
docker compose down
Tail logs:
docker compose logs -f
Host Bind Mounts
If you replace Docker named volumes with host bind mounts (for example ./data/storage:/data/storage), ensure host directories exist and are writable by the backend runtime user.
Backend and worker run as non-root user uid=10001 inside containers. For host-mounted storage paths:
mkdir -p ./data/storage
sudo chown -R 10001:10001 ./data/storage
sudo chmod -R u+rwX,g+rwX ./data/storage
If permissions are incorrect, API startup fails with errors similar to:
PermissionError: [Errno 13] Permission denied: '/data/storage'FileNotFoundErrorfor/data/storage/originals
Frontend Build Baseline
The frontend Dockerfile uses node:22-slim with a standard npm ci --no-audit install step and no npm-specific build tuning flags.
Authentication Model
- Legacy shared build-time frontend token behavior was removed.
- API now uses server-issued sessions that are stored in HttpOnly cookies (
dcm_session) with a separate CSRF cookie (dcm_csrf). - Bootstrap users are provisioned from environment:
AUTH_BOOTSTRAP_ADMIN_USERNAMEAUTH_BOOTSTRAP_ADMIN_PASSWORD- optional
AUTH_BOOTSTRAP_USER_USERNAME - optional
AUTH_BOOTSTRAP_USER_PASSWORD
- Login brute-force protection is enabled by default and keyed by username and source IP:
AUTH_LOGIN_FAILURE_LIMITAUTH_LOGIN_FAILURE_WINDOW_SECONDSAUTH_LOGIN_LOCKOUT_BASE_SECONDSAUTH_LOGIN_LOCKOUT_MAX_SECONDS- Frontend signs in through
/api/v1/auth/loginand relies on browser session persistence for valid cookie-backed sessions.
DEV And LIVE Configuration Matrix
Use .env.example as baseline. The table below documents user-managed settings and recommended values.
| Variable | Local DEV (HTTP, docker-only) | LIVE (HTTPS behind reverse proxy) |
|---|---|---|
APP_ENV |
development |
production |
HOST_BIND_IP |
127.0.0.1 or local LAN bind if needed |
127.0.0.1 (publish behind proxy only) |
PUBLIC_BASE_URL |
http://localhost:8000 |
https://api.example.com |
VITE_API_BASE |
empty for host-derived http://<frontend-host>:8000/api/v1, or explicit local URL |
https://api.example.com/api/v1 (build-time value for production frontend image) |
VITE_ALLOWED_HOSTS |
optional comma-separated hostnames, for example localhost,docs.lan |
optional comma-separated public frontend hostnames, for example app.example.com |
CORS_ORIGINS |
["http://localhost:5173","http://localhost:3000"] |
exact frontend origins only, for example ["https://app.example.com"] |
REDIS_URL |
redis://:<password>@redis:6379/0 in isolated local network |
rediss://:<password>@redis.internal:6379/0 |
REDIS_SECURITY_MODE |
compat or auto |
strict |
REDIS_TLS_MODE |
allow_insecure or auto |
required |
AUTH_LOGIN_FAILURE_LIMIT |
default 5 |
tune to identity-protection policy and support requirements |
AUTH_LOGIN_FAILURE_WINDOW_SECONDS |
default 900 |
tune to identity-protection policy and support requirements |
AUTH_LOGIN_LOCKOUT_BASE_SECONDS |
default 30 |
tune to identity-protection policy and support requirements |
AUTH_LOGIN_LOCKOUT_MAX_SECONDS |
default 900 |
tune to identity-protection policy and support requirements |
AUTH_COOKIE_DOMAIN |
empty (host-only cookies) | parent frontend/API domain for split hosts, for example docs.lan |
AUTH_COOKIE_SAMESITE |
auto |
none for cross-origin frontend/API deployments, lax or strict for same-origin |
PROVIDER_BASE_URL_ALLOW_HTTP |
true only when intentionally testing local HTTP provider endpoints |
false |
PROVIDER_BASE_URL_ALLOW_PRIVATE_NETWORK |
true only for trusted local development targets |
false |
PROVIDER_BASE_URL_ALLOWLIST |
allow needed test hosts | explicit production allowlist, for example ["api.openai.com"] |
PROCESSING_LOG_STORE_MODEL_IO_TEXT |
false by default; temporary true only for controlled debugging |
false |
PROCESSING_LOG_STORE_PAYLOAD_TEXT |
false by default; temporary true only for controlled debugging |
false |
CONTENT_EXPORT_MAX_DOCUMENTS |
default 250 or lower based on host memory |
tuned to production capacity |
CONTENT_EXPORT_MAX_TOTAL_BYTES |
default 52428800 (50 MiB) or lower |
tuned to production capacity |
CONTENT_EXPORT_RATE_LIMIT_PER_MINUTE |
default 6 |
tuned to API throughput and abuse model |
PUBLIC_BASE_URL must point to the backend API public URL, not the frontend URL.
HTTPS Proxy Deployment Notes
This application supports both:
- local HTTP-only operation (no TLS termination in containers)
- HTTPS deployment behind a reverse proxy that handles TLS
Recommended LIVE pattern:
- Proxy terminates TLS and forwards to
apiandfrontendinternal HTTP endpoints. - Keep container published ports bound to localhost or internal network.
- Set
PUBLIC_BASE_URLandVITE_API_BASEto final HTTPS URLs. - Set
CORS_ORIGINSto exact HTTPS frontend origins. - Credentialed CORS is enabled and constrained for cookie-based sessions with strict origin allowlists.
Security Controls
- CORS uses explicit origin allowlist only; broad origin regex matching is removed.
- Worker Redis startup validates URL auth and TLS policy before consuming jobs.
- Provider API keys are encrypted at rest with standard AEAD (
cryptographyFernet).- legacy
enc-v1payloads are read for backward compatibility - new writes use
enc-v2
- legacy
- Processing logs default to metadata-only persistence.
- Login endpoint applies escalating temporary lockout on repeated failed credentials using Redis-backed subject keys for username and source IP.
- Markdown export enforces:
- max document count
- max total markdown bytes
- per-user Redis-backed rate limit
- spool-file streaming to avoid unbounded memory archives
- User-role document access is owner-scoped for non-admin accounts.
Frontend Runtime
- Frontend no longer consumes
VITE_API_TOKEN. - Frontend image target is environment-driven:
APP_ENV=developmentbuilds thedevelopmenttarget and runs Vite dev serverAPP_ENV=productionbuilds theproductiontarget and serves static assets through unprivileged Nginx
- Frontend Docker targets are selected from
APP_ENV, so usedevelopmentorproductionvalues. - Production frontend Nginx uses non-root runtime plus
/tmptemp-path configuration so it can run with container capability dropping enabled. - Vite dev server host allowlist uses the union of:
- hostnames extracted from
CORS_ORIGINS - optional explicit hostnames from
VITE_ALLOWED_HOSTS
- hostnames extracted from
VITE_ALLOWED_HOSTSonly affects development mode where Vite is running.- API auth cookies support optional domain and SameSite configuration through
AUTH_COOKIE_DOMAINandAUTH_COOKIE_SAMESITE. - HTTPS cookie security detection falls back to
PUBLIC_BASE_URLscheme when proxy headers are missing. - CSRF validation accepts header matches against any
dcm_csrfcookie value in the request, covering stale plus fresh duplicate-cookie transitions. - Session authentication is cookie-based; browser reloads and new tabs can reuse an active session until it expires or is revoked.
- Protected media and file download flows still use authenticated fetch plus blob/object URL handling.
Validation Checklist
After configuration changes:
GET /api/v1/healthreturns healthy response- login succeeds for bootstrap admin user
- admin can upload, search, open preview, download, and export markdown
- user account can only access its own documents
- admin-only settings and processing logs are not accessible by user role
docker compose logs -f api workershows no startup validation failures