12 — Configuration Reference
All settings: environment variables, Django settings, and database-backed settings.
Environment Variables
Set in tools/docker-compose-prod/.env.
Core (required)
| Variable |
Description |
Generate with... |
POSTGRES_PASSWORD |
DB password |
openssl rand -base64 24 |
FORGE_SECRET_KEY |
Django crypto key |
openssl rand -base64 32 |
FORGE_BROADCAST_WEBSOCKET_SECRET |
WS auth secret |
openssl rand -base64 32 |
FORGE_ADMIN_PASSWORD |
Admin password |
Manually — strong password |
FORGE_CSRF_TRUSTED_ORIGINS |
CSRF origins |
https://forge.example.com |
Optional
| Variable |
Default |
Description |
FORGE_IMAGE |
forge-platform/forge |
Docker image |
FORGE_TAG |
latest |
Image tag |
POSTGRES_USER |
forge |
DB user |
POSTGRES_DB |
forge |
DB name |
FORGE_ADMIN_USER |
admin |
Admin username |
FORGE_ALLOWED_HOSTS |
* |
Allowed HTTP hosts |
FORGE_NODE_NAME |
forge-node |
Cluster node name |
FORGE_NODE_TYPE |
hybrid |
hybrid / control / execution |
NGINX_HTTP_PORT |
80 |
HTTP port |
NGINX_HTTPS_PORT |
443 |
HTTPS port |
SESSION_COOKIE_SECURE |
True |
Cookie only over HTTPS |
CSRF_COOKIE_SECURE |
True |
CSRF cookie only over HTTPS |
Watch out
-
FORGE_SECRET_KEY — never change it after deployment — it invalidates all sessions,
tokens, and encrypted credentials.
-
FORGE_CSRF_TRUSTED_ORIGINS must be a full URL with protocol: https://forge.example.com.
Hostname only without https:// won't work.
-
For local development without HTTPS, set SESSION_COOKIE_SECURE=False and CSRF_COOKIE_SECURE=False.
Django Settings Files
Loaded in order (later ones override earlier):
1. forge/settings/defaults/*.py ← Default values
2. forge/settings/production.py ← Production override (DEBUG=False)
3. /etc/tower/settings.py ← Root settings in the container
4. /etc/tower/conf.d/*.py ← Per-module settings in the container
5. Database settings ← Runtime override via API
Key default files
| File |
What it controls |
defaults/base.py |
DATABASES, INSTALLED_APPS, REST_FRAMEWORK |
defaults/auth.py |
Authentication backends |
defaults/jobs.py |
Job execution defaults |
defaults/celery_conf.py |
Celery/Redis |
defaults/logging_conf.py |
Logging levels and formats |
production.py |
DEBUG=False, ALLOWED_HOSTS, security |
Database-Backed Settings (changed without restart)
Access via API: /api/v2/settings/
Job Settings (/api/v2/settings/jobs/)
| Setting |
Default |
Description |
SCHEDULE_MAX_JOBS |
10 |
Max concurrent runs of the same scheduled template |
AWX_TASK_ENV |
{} |
Extra env variables for ALL playbook runs |
DEFAULT_JOB_TIMEOUT |
0 |
Global job timeout in seconds (0 = no limit) |
DEFAULT_INVENTORY_UPDATE_TIMEOUT |
0 |
Inventory sync timeout |
DEFAULT_PROJECT_UPDATE_TIMEOUT |
0 |
Project sync timeout |
MAX_FORKS |
200 |
Maximum forks per job |
AWX_ROLES_ENABLED |
True |
Allow Ansible roles download |
AWX_COLLECTIONS_ENABLED |
True |
Allow Ansible collections download |
PROJECT_UPDATE_VVV |
False |
Verbose project sync output |
Auth Settings (/api/v2/settings/authentication/)
| Setting |
Default |
Description |
SESSION_COOKIE_AGE |
1800 |
Session timeout in seconds (30 min) |
SESSIONS_PER_USER |
-1 |
Max concurrent sessions (-1 = unlimited) |
AUTH_BASIC_ENABLED |
True |
Allow Basic auth for API |
ALLOW_OAUTH2_FOR_EXTERNAL_USERS |
False |
SSO users can create tokens |
Logging Settings (/api/v2/settings/logging/)
| Setting |
Default |
Description |
LOG_AGGREGATOR_HOST |
None |
External log collector hostname |
LOG_AGGREGATOR_PORT |
None |
Port |
LOG_AGGREGATOR_TYPE |
None |
logstash, splunk, loggly, sumologic |
LOG_AGGREGATOR_ENABLED |
False |
Enable log forwarding |
LOG_AGGREGATOR_LEVEL |
WARNING |
Minimum level |
Common Configuration Tasks
Extend session to 8 hours
curl -u admin:password -X PATCH \
-H 'Content-Type: application/json' \
-d '{"SESSION_COOKIE_AGE": 28800}' \
https://forge.example.com/api/v2/settings/authentication/
Set global job timeout to 1 hour
curl -u admin:password -X PATCH \
-H 'Content-Type: application/json' \
-d '{"DEFAULT_JOB_TIMEOUT": 3600}' \
https://forge.example.com/api/v2/settings/jobs/
Add proxy for all jobs
curl -u admin:password -X PATCH \
-H 'Content-Type: application/json' \
-d '{"AWX_TASK_ENV": {"HTTP_PROXY": "http://proxy:3128", "HTTPS_PROXY": "http://proxy:3128"}}' \
https://forge.example.com/api/v2/settings/jobs/
Disable Basic Auth (more secure)
curl -u admin:password -X PATCH \
-H 'Content-Type: application/json' \
-d '{"AUTH_BASIC_ENABLED": false}' \
https://forge.example.com/api/v2/settings/authentication/
Send logs to Splunk
curl -u admin:password -X PATCH \
-H 'Content-Type: application/json' \
-d '{
"LOG_AGGREGATOR_HOST": "splunk.example.com",
"LOG_AGGREGATOR_PORT": 8088,
"LOG_AGGREGATOR_TYPE": "splunk",
"LOG_AGGREGATOR_ENABLED": true
}' \
https://forge.example.com/api/v2/settings/logging/
curl -u admin:password -X PATCH \
-H 'Content-Type: application/json' \
-d '{
"AUTH_LDAP_SERVER_URI": "ldaps://ldap.example.com:636",
"AUTH_LDAP_BIND_DN": "cn=forge,ou=services,dc=example,dc=com",
"AUTH_LDAP_BIND_PASSWORD": "LDAPPassword",
"AUTH_LDAP_USER_SEARCH": ["ou=users,dc=example,dc=com", "SCOPE_SUBTREE", "(uid=%(user)s)"],
"AUTH_LDAP_ORGANIZATION_MAP": {
"Default": {"users": true, "remove_users": false}
}
}' \
https://forge.example.com/api/v2/settings/ldap/
uWSGI Workers
processes = 5 # Default. Increase to 8-16 for high traffic.
harakiri = 120 # Worker timeout (seconds)
max-requests = 1000 # Restart worker after N requests
Node Capacity
CPU capacity = CPU cores × 4
RAM capacity = RAM (MB) / 100
Effective = whichever is smaller
Example: 8 cores, 16GB RAM → 32 forks → ~6 jobs with 5 forks each simultaneously
Recommended Hardware
| Size |
CPU |
RAM |
Disk |
| Small (≤100 hosts) |
4 |
8GB |
50GB SSD |
| Medium (≤1000) |
8 |
16GB |
100GB SSD |
| Large (≤10000) |
16 |
32GB |
200GB SSD |
| Enterprise (10000+) |
16+ |
64GB+ |
500GB SSD |