Configuration
Environment Variables
Cleanmails is configured entirely through environment variables. These are set in your .env file (located at /opt/cleanmails/.env after installation).
ENCRYPTION_KEY is required
The ENCRYPTION_KEY must be a 64-character hex string (32 bytes). It's used for AES-256-GCM encryption of all sender passwords and integration tokens. Generate with: openssl rand -hex 32
Full Example
/opt/cleanmails/.env
# Domain
DOMAIN=app.yourdomain.com
# Database
DB_PASSWORD=your-generated-password
DATABASE_URL=postgres://cleanmails:${DB_PASSWORD}@postgres:5432/cleanmails?sslmode=disable
# Redis
REDIS_URL=redis://redis:6379
# Security
ENCRYPTION_KEY=your-64-hex-char-key-here
JWT_SECRET=your-jwt-secret-here
# App
BASE_URL=https://app.yourdomain.com
API_PORT=8080
GIN_MODE=release
ALLOWED_ORIGINS=https://app.yourdomain.comCore Settings
| Variable | Default | Description |
|---|---|---|
DOMAIN | — | Your domain name (used by Caddy for SSL provisioning) |
DATABASE_URL | — | Required. PostgreSQL connection string |
REDIS_URL | redis://localhost:6379 | Redis connection URL (used by Asynq task queue) |
API_PORT | 8080 | Port the API server listens on |
BASE_URL | http://localhost:8080 | Public URL of your instance (used in tracking links, unsubscribe URLs) |
GIN_MODE | debug | Set to release in production (disables debug logging) |
ALLOWED_ORIGINS | http://localhost:3000 | Comma-separated list of allowed CORS origins |
Security
| Variable | Description |
|---|---|
ENCRYPTION_KEY | Required. 64-char hex string for AES-256-GCM encryption of credentials |
JWT_SECRET | Required. Secret key for signing JWT tokens (7-day expiry) |
DB_PASSWORD | PostgreSQL password (used in DATABASE_URL and by the postgres container) |
Database
| Variable | Default | Description |
|---|---|---|
DB_PASSWORD | — | PostgreSQL password (shared between app and postgres container) |
DATABASE_URL | — | Full PostgreSQL connection string with sslmode |
REDIS_URL | redis://redis:6379 | Redis URL for Asynq background jobs |
Frontend
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_API_URL | http://localhost:8080 | API URL the frontend uses (set to your public URL in production) |
HOSTNAME | 0.0.0.0 | Frontend listen host |
PORT | 3000 | Frontend listen port |
Auto-generated by installer
The install script (install.sh) automatically generates all secrets using openssl rand -hex. You only need to provide the --domain flag. The generated .env file is set to mode 640 for security.
Worker Configuration
The background worker connects to the same PostgreSQL and Redis instances. Worker behavior is configured through the Asynq server settings in code:
| Setting | Value | Description |
|---|---|---|
| Concurrency | 10 | Total concurrent task processors |
| Critical queue weight | 6 | Bounce/complaint handling priority |
| Default queue weight | 3 | Campaign dispatch, validation tasks |
| Low queue weight | 1 | IMAP sync, AI replies |
Docker Resource Limits
The production Docker Compose sets memory limits per service:
| Service | Memory Limit |
|---|---|
| PostgreSQL | 512 MB |
| Redis | 192 MB |
| API Server | 256 MB |
| Worker | 256 MB |
| Frontend | 256 MB |
| Caddy | 64 MB |