Environment Configuration¶
Validibot uses environment files to configure Django settings, database credentials, and deployment-specific options. This page explains the structure and usage of these files.
Directory Structure¶
Environment configuration uses a template-based approach:
.envs.example/ # Templates (committed to git)
├── README.md # Quick start guide and variable reference
├── .local/
│ ├── .django # Django settings for local development
│ └── .postgres # Postgres credentials for local development
└── .production/
├── .docker-compose/ # Docker Compose production deployment
│ ├── .django
│ └── .postgres
├── .google-cloud/ # Google Cloud Platform deployment
│ ├── .django # Django runtime settings (uploaded to Secret Manager)
│ └── .just # Just command runner settings (sourced locally)
└── .aws/ # AWS deployment (future)
└── .django
.envs/ # Your actual secrets (NOT committed - gitignored)
└── (same structure as above)
Why This Structure?¶
The separation between .envs.example/ and .envs/ serves two purposes:
-
Templates stay in version control: The
.envs.example/folder contains example configurations with placeholder values. These are committed to git so new developers can see what variables are needed. -
Secrets stay private: The
.envs/folder contains your actual credentials and is gitignored. NEVER commit this folder to version control, especially public repositories - it contains passwords, API keys, and other sensitive data that could compromise your deployment if exposed.
This pattern follows the cookiecutter-django convention, which is widely used in the Django community.
Setup Workflow¶
Local Development¶
-
Create the directory structure:
-
Copy the templates:
-
Edit the files to set real values (especially
SUPERUSER_PASSWORD). -
Start Docker Compose:
Docker Compose Production¶
-
Create the directory structure:
-
Copy both template files:
-
Edit with your production values (generate a proper secret key, set your domain, etc.).
-
Deploy:
Google Cloud Platform¶
GCP deployments don't use local .envs/ files. Instead, secrets are stored in Google Secret Manager and mounted as environment files at runtime.
See Google Cloud Deployment for details.
How Environment Files Work¶
The Two-File Pattern¶
Each deployment environment uses two files:
| File | Purpose | Example Variables |
|---|---|---|
.postgres |
Database credentials only | POSTGRES_HOST, POSTGRES_USER, POSTGRES_PASSWORD |
.django |
Everything else | DJANGO_SECRET_KEY, REDIS_URL, SITE_URL |
This separation keeps database credentials isolated and makes it clear which variables configure which service.
DATABASE_URL Construction¶
You'll notice that DATABASE_URL is not in the environment files. This is intentional - the entrypoint script automatically constructs it from the individual postgres variables:
# From compose/local/django/entrypoint.sh
export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"
This means .postgres is the single source of truth for database credentials. You never need to duplicate connection details.
Docker Compose Loading¶
Docker Compose loads both files via the env_file directive:
The order matters only if you have duplicate variables (later files override earlier ones).
Platform-Specific Configuration¶
Local Development (Docker Compose)¶
The local configuration is designed for simplicity:
- Uses Docker service names for hostnames (
postgres,redis) - Simple default credentials (fine for local dev)
- Console email backend (emails print to terminal)
- Debug mode enabled
Key files:
- .envs/.local/.django - Django configuration
- .envs/.local/.postgres - Postgres credentials
Docker Compose Production¶
Docker Compose deployments run with production-grade settings:
DJANGO_SETTINGS_MODULE=config.settings.productionDEPLOYMENT_TARGET=docker_compose- Real SSL certificates (via reverse proxy)
- Proper secret key and passwords
The DEPLOYMENT_TARGET=docker_compose setting tells Django to:
- Use Celery for background tasks (not Cloud Tasks)
- Use Docker socket for running validator containers
- Use local filesystem or S3/GCS for file storage
Google Cloud Platform¶
GCP deployments use completely different infrastructure:
DEPLOYMENT_TARGET=gcp- Cloud SQL for database (via Unix socket)
- Cloud Tasks for background work
- Cloud Run Jobs for validator containers
- GCS for file storage
Two types of environment files:
| File | Purpose | Usage |
|---|---|---|
.django |
Django runtime settings | Uploaded to Secret Manager, mounted at /secrets/.env |
.just |
Just command runner settings | Sourced locally before running just gcp commands |
The .just file contains your GCP project ID and region, which the justfile needs to run deployment commands. Source it before running any just gcp commands:
# Source your GCP config
source .envs/.production/.google-cloud/.just
# Now you can run GCP commands
just gcp deploy prod
The .django file contains Django settings and is uploaded to Secret Manager:
just gcp secrets dev # Upload secrets for dev environment
just gcp secrets prod # Upload secrets for production
AWS (Future)¶
AWS deployment support is planned but not yet implemented. The configuration will use:
DEPLOYMENT_TARGET=aws- AWS Batch for validator containers
- SQS for task queue
- S3 for file storage
Environment Variable Reference¶
For a complete list of environment variables and their descriptions, see:
.envs.example/README.mdin the project root - Quick reference table with all variables- Configuration Settings - Django-specific settings documentation
Internal API Security (WORKER_API_KEY)¶
Validibot's worker service exposes internal API endpoints for validation execution, callbacks, and scheduled tasks. These endpoints need protection against unauthorized access.
The WORKER_API_KEY setting provides a shared-secret authentication layer:
| Deployment | Primary Auth | WORKER_API_KEY |
|---|---|---|
| Docker Compose | None (same network) | Required - protects against SSRF |
| GCP | Cloud Run IAM (OIDC) | Optional - defense in depth |
| Local dev | None | Optional |
How It Works¶
When WORKER_API_KEY is set, all requests to worker endpoints must include it in the Authorization header:
When WORKER_API_KEY is empty (the default), the check is skipped. This allows GCP deployments to rely solely on Cloud Run IAM.
Docker Compose Setup¶
For Docker Compose deployments, add WORKER_API_KEY to your .envs/.production/.docker-compose/.django file:
# Generate a key
python -c "import secrets; print(secrets.token_urlsafe(32))"
# Add to .django env file
WORKER_API_KEY=your-generated-key-here
Since all Docker Compose services (web, worker, scheduler) share the same env file, the key is automatically available to all services. The Celery worker uses it when making internal API calls.
Why This Matters¶
In Docker Compose, all containers share the same Docker bridge network. Without WORKER_API_KEY, an SSRF vulnerability in the web container could allow an attacker to call worker endpoints directly, potentially spoofing validation results or triggering data deletion.
Security Reminders¶
Never Commit Secrets
The .envs/ folder must NEVER be committed to version control, especially public repositories. This folder is gitignored for a reason - it contains passwords, API keys, database credentials, and other sensitive data. Committing these files could expose your entire deployment to attackers.
-
Generate proper secrets for production - Use the commands in
.envs.example/README.mdto generateDJANGO_SECRET_KEYand passwords. -
Randomize the admin URL - Change
DJANGO_ADMIN_URLfrom the defaultadmin/to a random path. This prevents automated scanners from finding your admin login page. Generate one with:python -c "import secrets; print(secrets.token_urlsafe(16))". -
Use different secrets per environment - Dev, staging, and production should have completely different credentials.
-
Rotate secrets periodically - Especially after team member departures or security incidents.
-
Use Secret Manager in cloud deployments - GCP Secret Manager (or AWS Secrets Manager) provides audit logging and access controls that local files can't.