4.9 KiB
Production Deployment Guide
Overview
AOC runs as a set of Docker containers orchestrated by Docker Compose:
- nginx — reverse proxy, TLS termination, static file serving
- backend — FastAPI application (Gunicorn + Uvicorn workers)
- mongo — MongoDB data store (not exposed externally)
- valkey — Redis-compatible cache and async job queue (not exposed externally)
Prerequisites
- Docker Engine 24+ and Docker Compose plugin
- A server with ports 80/443 reachable from your users
- TLS certificates (place in
nginx/ssl/or use Let's Encrypt) - A valid
.envfile at the repo root (see.env.example)
Quick start
-
Clone / pull the latest release
git checkout v1.7.14 -
Copy and edit environment variables
cp .env.example .env # Edit .env and fill in real credentials -
Set the release version
export AOC_VERSION=v1.7.14 -
Deploy
docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d -
Verify
curl http://localhost/health curl http://localhost/api/events
Updating to a new release
export AOC_VERSION=v1.7.14
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
Enabling HTTPS
Option A: Use your own certificates
-
Place
cert.pemandkey.peminnginx/ssl/ -
Uncomment the HTTPS server block in
nginx/nginx.conf -
Uncomment the HTTP → HTTPS redirect server block
-
Reload nginx:
docker compose -f docker-compose.prod.yml exec nginx nginx -s reload
Option B: Let's Encrypt with Certbot
Replace the nginx service in docker-compose.prod.yml with a Certbot-friendly setup (e.g., use the nginx-proxy + acme-companion stack) or mount the Certbot certificates into nginx/ssl/.
Security Hardening
- MongoDB is not exposed to the host — only the backend container can reach it.
- Valkey/Redis is not exposed to the host — only the backend container can reach it.
- The backend runs as a non-root (
aoc) user inside the container. - nginx adds security headers (
X-Frame-Options,X-Content-Type-Options, etc.). - Keep
.envout of version control — it is listed in.gitignore. - Set
AUTH_ENABLED=trueand configureAUTH_ALLOWED_ROLESorAUTH_ALLOWED_GROUPSto restrict access to admin/security roles. - Set explicit
CORS_ORIGINS— do not use*in production when auth is enabled. - Set
DOCS_ENABLED=falseto hide OpenAPI docs (/docs,/openapi.json). - Configure
WEBHOOK_CLIENT_SECRETto validate Graph webhook notifications. - Set
LLM_ALLOWED_DOMAINSif using AI features (e.g.api.openai.com,*.openai.azure.com). - Set
SIEM_ALLOWED_DOMAINSif using SIEM forwarding. - Review
METRICS_ALLOWED_IPS— defaults to private networks + loopback.
Azure Key Vault (Optional)
To eliminate long-lived secrets from .env:
-
Create an Azure Key Vault and add these secrets:
aoc-client-secret— your Graph appCLIENT_SECRETaoc-llm-api-key— yourLLM_API_KEY(if using AI)aoc-mongo-uri— yourMONGO_URIaoc-webhook-client-secret— yourWEBHOOK_CLIENT_SECRET
-
Uncomment
azure-identityandazure-keyvault-secretsinbackend/requirements.txt -
Set
AZURE_KEY_VAULT_NAME=your-keyvault-namein.env -
Grant the container identity
Getpermission on secrets:- If using Azure Container Instances / AKS: assign a managed identity
- If using VM: assign a managed identity or use a service principal
- If using local Docker: authenticate via
az loginon the host
-
Rebuild and redeploy:
docker compose -f docker-compose.prod.yml up -d --build
Rollback
export AOC_VERSION=v1.7.13
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
Monitoring
-
Prometheus metrics:
http://your-host/metrics(IP-restricted by default) -
Health check:
http://your-host/health -
Container logs:
docker compose -f docker-compose.prod.yml logs -f backend docker compose -f docker-compose.prod.yml logs -f nginx docker compose -f docker-compose.prod.yml logs -f mongo docker compose -f docker-compose.prod.yml logs -f valkey
Troubleshooting
- Auth warning in logs: "AUTH_ENABLED is true but no AUTH_ALLOWED_ROLES or AUTH_ALLOWED_GROUPS are configured" — set these to restrict access.
- CORS issues: Set
CORS_ORIGINSto your exact frontend origin(s). Wildcard with auth enabled disables credentials. - Rate limiting 429s: Check Redis/Valkey connectivity. The rate limiter fails closed (returns 429) when Redis is down.
- LLM errors: Verify
LLM_BASE_URLis inLLM_ALLOWED_DOMAINSif the allowlist is configured. - SIEM not forwarding: Verify
SIEM_WEBHOOK_URLuses HTTPS and is inSIEM_ALLOWED_DOMAINS.