Environment & secrets
SES keeps non-secret configuration separate from secrets. Both live in env files outside of version control and are supplied to Docker at runtime.
The two env files
| File | Contents | Committed to git? |
|---|---|---|
.env.local / .env.prd | Non-secret configuration (domain, feature flags) | No |
.env.secrets | All secrets (passwords, keys, tokens) | No |
- Non-secret configuration
- Secrets
Public URL
| Variable | Example | Purpose |
|---|---|---|
DOMAIN | docs.safeexamsupport.eu | Public domain |
URL_SCHEME | https | Public URL scheme |
PUBLIC_PORT | 443 | Public port |
Django
| Variable | Default | Purpose |
|---|---|---|
DEBUG | False in production | Debug mode |
ENVIRONMENT | production | Deployment environment |
ALLOWED_HOSTS | comma-separated | Django allowed hosts |
CSRF_TRUSTED_ORIGINS | comma-separated | Django CSRF origins |
Database
| Variable | Default | Purpose |
|---|---|---|
DB_HOST | odyssey | DB host (connection pooler) |
DB_PORT | 6432 | DB port (pooler) |
DB_NAME | ses_server_db | Database name |
DB_USER | postgres | Database user |
POOL_TYPE | session | Pool type (session = schema isolation) |
POOL_SIZE | 100 | Pool size |
SSO
| Variable | Default | Purpose |
|---|---|---|
SSO_ENABLED | True | Enable Keycloak SSO |
KEYCLOAK_URL | http://keycloak:8080 | Internal Keycloak URL |
KEYCLOAK_EXTERNAL_URL | https://kcd.example.com | Public Keycloak URL |
KEYCLOAK_REALM | ses | Keycloak realm |
KEYCLOAK_CLIENT_ID | ses-server | OIDC client ID |
Rate limiting
| Variable | Default | Purpose |
|---|---|---|
RATE_LIMIT_GLOBAL | 50000 | Global requests / minute |
RATE_LIMIT_INSTITUTE | 5000 | Requests / minute per institute |
| Variable | Generate with |
|---|---|
SECRET_KEY (Django signing / CSRF) | openssl rand -hex 32 |
SES_SESSION_TOKEN_SECRET (HMAC shared with proxy) | openssl rand -hex 32 |
SECURE_ENCRYPTION_KEY (Fernet, encrypt at rest) | python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
DB_PASSWORD | openssl rand -hex 16 |
REDIS_PASSWORD | openssl rand -hex 16 |
KEYCLOAK_ADMIN_PASSWORD | openssl rand -base64 24 |
KEYCLOAK_DB_PASSWORD | openssl rand -hex 16 |
GIT_TOKEN (clone private repos) | GitHub fine-grained token |
Generating secrets
# In the deployment repository
chmod +x generate/generate_secrets.sh
./generate/generate_secrets.sh <your-github-pat>
The script is idempotent — it keeps existing values and only fills in missing ones.
Keep secrets private
Never commit .env.secrets. Use .env.secrets.example to document which
variables exist, without exposing values.
Session token must match across the stack
SES_SESSION_TOKEN_SECRET must be identical on the server and the proxy
container, otherwise the proxy rejects valid sessions.