Skip to content

Environment Variables

Need help getting set up?

Bunker Operations provides managed infrastructure and hands-on setup assistance for organizations running Changemaker Lite. We handle domains, tunnels, SMTP, and servers so you can focus on your campaign. Get in touch: bnkops.com | admin@bnkops.ca

Changemaker Lite uses a single .env file at the project root to configure all services. Copy the example file to get started:

cp .env.example .env

Security Essentials

  • Change every REQUIRED_STRONG_PASSWORD_CHANGE_THIS value before starting services
  • Generate secrets with openssl rand -hex 32 (or -hex 16 where noted)
  • Never commit .env to version control
  • Use unique values for each secret — do not reuse JWT secrets as encryption keys

Quick Reference

Variables are grouped by service. Each table marks whether a variable is required for a basic deployment or optional (has a sensible default or only needed for specific features).

Symbol Meaning
Must be set before first run
Has a working default; change for production
Feature flag — opt-in

General

Variable Default Description
NODE_ENV development Set to production for production deployments. Controls logging, error detail, and security checks.
DOMAIN cmlite.org Root domain. Used for nginx subdomain routing (app.DOMAIN, api.DOMAIN, etc.). The root domain serves the MkDocs documentation site; all application routes live under app.DOMAIN.
USER_ID 1000 UID for container file ownership. Match your host user's UID (id -u).
GROUP_ID 1000 GID for container file ownership. Match your host user's GID (id -g).
DOCKER_GROUP_ID 984 GID of the docker group on the host. Needed for containers that access the Docker socket. Find with getent group docker.

PostgreSQL (Main Database)

The primary database for both the Express API and the Fastify Media API (shared).

Variable Default Description
V2_POSTGRES_USER changemaker Database username.
V2_POSTGRES_PASSWORD Must change. Database password.
V2_POSTGRES_DB changemaker_v2 Database name.
V2_POSTGRES_PORT 5433 Host port mapping. The container listens on 5432 internally.

Connection string

The DATABASE_URL is constructed automatically inside Docker. If running locally, set:

DATABASE_URL=postgresql://changemaker:YOUR_PASSWORD@localhost:5433/changemaker_v2


JWT Authentication

Variable Default Description
JWT_ACCESS_SECRET Secret for signing access tokens. Generate with openssl rand -hex 32.
JWT_REFRESH_SECRET Secret for signing refresh tokens. Must differ from the access secret.
JWT_INVITE_SECRET Secret for signing volunteer invite tokens. Must differ from access and refresh secrets. Generate with openssl rand -hex 32.
JWT_ACCESS_EXPIRY 15m Access token lifetime. Short-lived by design.
JWT_REFRESH_EXPIRY 7d Refresh token lifetime. Tokens are rotated atomically on each refresh.

Encryption Key

Variable Default Description
ENCRYPTION_KEY AES key for encrypting secrets stored in the database (SMTP passwords, API keys, etc.). Generate with openssl rand -hex 32. Must not reuse a JWT secret. Required in all environments (no longer falls back to JWT secret in development).

Security Extras

Additional secrets for key separation. These fall back to JWT_ACCESS_SECRET if empty, but setting unique values is strongly recommended for production.

Variable Default Description
GITEA_SSO_SECRET (empty) Cookie signing secret for Gitea SSO integration. Falls back to JWT_ACCESS_SECRET if empty. Generate with openssl rand -hex 32.
SERVICE_PASSWORD_SALT (empty) Salt for deriving deterministic service passwords (Gitea, Rocket.Chat user provisioning). Falls back to JWT_ACCESS_SECRET if empty — rotating JWT_ACCESS_SECRET would then invalidate all provisioned service passwords. Generate with openssl rand -hex 32.
CSP_ENABLED false Enable Content Security Policy headers in API responses.

Key separation

If GITEA_SSO_SECRET and SERVICE_PASSWORD_SALT are left empty, the API logs security warnings on every startup. Set unique values to isolate secret rotation and prevent one compromised key from affecting other subsystems.


Initial Admin Account

These credentials create the first super-admin user during database seeding (npx prisma db seed).

Variable Default Description
INITIAL_ADMIN_EMAIL admin@cmlite.org Email address for the initial admin.
INITIAL_ADMIN_PASSWORD Must change. Must be 12+ characters with uppercase, lowercase, and a digit. Change this password after first login.

API Server

Variable Default Description
API_PORT 4000 Host port for the Express API.
API_URL http://localhost:4000 Public URL of the API. Used for generating links in emails and QR codes.
CORS_ORIGINS http://localhost:3000,http://localhost Comma-separated list of allowed CORS origins. Add your production domain (e.g., https://app.yourdomain.org) for production.

Production CORS

If you deploy behind a tunnel (Pangolin, Cloudflare) and API requests fail with CORS errors, add your production app. subdomain here:

CORS_ORIGINS=https://app.betteredmonton.org,http://localhost:3000,http://localhost
Then restart the API: docker compose restart api


Admin GUI

Variable Default Description
ADMIN_PORT 3000 Host port for the React admin dashboard.
ADMIN_URL http://localhost:3000 Public URL of the admin GUI.

Rate Limiting

Variable Default Description
RATE_LIMIT_WINDOW_MS 900000 Rate limit window in milliseconds (default: 15 minutes).
RATE_LIMIT_MAX 500 Maximum requests per window per IP. Auth endpoints have a stricter limit (10/min).

Nginx Reverse Proxy

Variable Default Description
NGINX_HTTP_PORT 80 HTTP port. All subdomains route through nginx.
NGINX_HTTPS_PORT 443 HTTPS port. SSL is typically handled by the tunnel provider (Pangolin/Cloudflare).

Redis

Shared by rate limiting, BullMQ job queues, geocoding cache, and session data.

Variable Default Description
REDIS_PASSWORD Must change. Redis requires authentication.
REDIS_URL redis://:${REDIS_PASSWORD}@redis-changemaker:6379 Full connection URL. Uses the password variable automatically.

Payments (Stripe)

Variable Default Description
ENABLE_PAYMENTS false Set to true to enable the payments feature (memberships, products, donations). Stripe API keys are stored encrypted in the database via the admin settings page.

Email / SMTP

Variable Default Description
SMTP_HOST mailhog-changemaker SMTP server. Default points to the MailHog dev container.
SMTP_PORT 1025 SMTP port. 1025 for MailHog, 587 for most production SMTP.
SMTP_USER (empty) SMTP username. Not needed for MailHog.
SMTP_PASS (empty) SMTP password.
SMTP_FROM noreply@cmlite.org "From" address on outgoing emails.
SMTP_FROM_NAME Changemaker Lite Display name for the "From" header.
EMAIL_TEST_MODE true When true, all emails go to MailHog instead of real SMTP. Set to false in production.
TEST_EMAIL_RECIPIENT admin@cmlite.org Catch-all recipient when test mode is on.

Development email

With EMAIL_TEST_MODE=true, all outgoing email is captured in MailHog at http://localhost:8025. No real emails are sent.


Listmonk (Newsletters)

Listmonk handles newsletter/marketing campaigns. Sync with the main platform is opt-in.

Variable Default Description
LISTMONK_PORT 9001 Listmonk web UI port.
LISTMONK_DB_PORT 5434 Listmonk's own PostgreSQL port (separate from the main DB). Uses 5434 to avoid conflict with the main PostgreSQL (5432 internal / 5433 host).
LISTMONK_DB_USER listmonk Listmonk database user.
LISTMONK_DB_PASSWORD Listmonk database password.
LISTMONK_DB_NAME listmonk Listmonk database name.
LISTMONK_WEB_ADMIN_USER admin Login for the Listmonk web dashboard.
LISTMONK_WEB_ADMIN_PASSWORD Password for the Listmonk web dashboard.
LISTMONK_API_USER v2-api API user for programmatic access (auto-created by init container).
LISTMONK_API_TOKEN Token for API user. Generate with openssl rand -hex 16.
LISTMONK_ADMIN_USER v2-api Same as LISTMONK_API_USER (used by the sync service).
LISTMONK_ADMIN_PASSWORD Same as LISTMONK_API_TOKEN.
LISTMONK_SYNC_ENABLED false Set to true to sync participants/locations/users to Listmonk lists.
LISTMONK_WEBHOOK_SECRET (empty) Shared secret for Listmonk webhook callbacks.
LISTMONK_PROXY_PORT 9002 Nginx proxy port for Listmonk.
Listmonk SMTP settings

Listmonk has its own SMTP configuration, separate from the main platform's:

Variable Default Description
LISTMONK_SMTP_HOST mailhog-changemaker SMTP host for Listmonk.
LISTMONK_SMTP_PORT 1025 SMTP port.
LISTMONK_SMTP_USER (empty) SMTP username.
LISTMONK_SMTP_PASSWORD (empty) SMTP password.
LISTMONK_SMTP_TLS_TYPE none TLS mode: none, STARTTLS, or TLS.
LISTMONK_SMTP_FROM Changemaker Lite <noreply@cmlite.org> From address for newsletters.

Represent API (Canadian Electoral Data)

Variable Default Description
REPRESENT_API_URL https://represent.opennorth.ca OpenNorth Represent API endpoint. Used for postal code → representative lookups. No API key required.

NocoDB (Data Browser)

Read-only database browser. Useful for inspecting data without SQL.

Variable Default Description
NOCODB_V2_PORT / NOCODB_PORT 8091 Host port for the NocoDB web UI.
NOCODB_URL http://changemaker-v2-nocodb:8080 Internal Docker URL.
NC_ADMIN_EMAIL admin@cmlite.org NocoDB admin email.
NC_ADMIN_PASSWORD NocoDB admin password.

Media Manager

Video library with upload, analytics, scheduling, and a public gallery.

Variable Default Description
ENABLE_MEDIA_FEATURES false Set to true to enable the media system.
MEDIA_API_PORT 4100 Fastify media API port.
MEDIA_API_PUBLIC_URL http://media-api:4100 Internal URL for the media API container.
MEDIA_ROOT /media/library Path to the video library inside the container.
MEDIA_UPLOADS /media/uploads Path for upload processing.
MAX_UPLOAD_SIZE_GB 10 Maximum single-file upload size in gigabytes.
PUBLIC_MEDIA_PORT 3100 Public media gallery server port.
VIDEO_PLAYER_DEBUG false Enable verbose video player logging.
Analytics & scheduling settings
Variable Default Description
VIDEO_ANALYTICS_RETENTION_DAYS 90 Days to retain analytics data. GDPR-compliant with IP hashing.
VIDEO_ANALYTICS_IP_HASHING_ENABLED true Hash viewer IPs for privacy.
VIDEO_SCHEDULE_DEFAULT_TIMEZONE UTC Default timezone for scheduled publishing.
VIDEO_SCHEDULE_NOTIFICATION_ENABLED true Notify on scheduled publish/unpublish.
VIDEO_PREVIEW_LINK_EXPIRY_HOURS 24 Preview link JWT expiry (hours).

Gitea (Git Hosting)

Self-hosted Git repository. Optional service.

Variable Default Description
GITEA_URL http://gitea-changemaker:3000 Internal container URL for Gitea.
GITEA_PORT / GITEA_WEB_PORT 3030 Gitea web UI port.
GITEA_SSH_PORT 2222 Gitea SSH port for git operations.
GITEA_DB_TYPE mysql Database type (Gitea uses its own MySQL).
GITEA_DB_HOST gitea-db:3306 Internal database host.
GITEA_DB_NAME gitea Database name.
GITEA_DB_USER gitea Database user.
GITEA_DB_PASSWD Gitea database password.
GITEA_DB_ROOT_PASSWORD MySQL root password for Gitea.
GITEA_ROOT_URL https://git.cmlite.org Public-facing URL for Gitea.
GITEA_DOMAIN git.cmlite.org Domain used in git clone URLs.
Gitea Docs Comments

Enable comments on MkDocs documentation pages, backed by Gitea Issues.

Variable Default Description
GITEA_COMMENTS_ENABLED false Enable comments on MkDocs pages.
GITEA_API_TOKEN (empty) Personal access token with repo write scope. Create in Gitea → Settings → Applications.
GITEA_COMMENTS_REPO_OWNER (empty) Gitea username that owns the docs-comments repo.
GITEA_COMMENTS_REPO_NAME docs-comments Repository name (auto-created via admin setup).
GITEA_OAUTH_CLIENT_ID (empty) OAuth2 application client ID (create in Gitea → Settings → Applications → OAuth2).
GITEA_OAUTH_CLIENT_SECRET (empty) OAuth2 application client secret.

n8n (Workflow Automation)

Variable Default Description
N8N_PORT 5678 n8n web UI port.
N8N_HOST n8n.cmlite.org Public hostname for n8n.
N8N_ENCRYPTION_KEY Encryption key for n8n credentials storage.
N8N_USER_EMAIL admin@example.com Initial n8n admin email.
N8N_USER_PASSWORD Initial n8n admin password.
GENERIC_TIMEZONE UTC Timezone for n8n cron triggers.

MkDocs (Documentation)

Variable Default Description
MKDOCS_PORT 4003 MkDocs dev server port (live preview).
MKDOCS_SITE_SERVER_PORT 4004 MkDocs static site server port.
BASE_DOMAIN https://cmlite.org Base URL for generated documentation links.
MKDOCS_PREVIEW_URL http://mkdocs:8000 Internal container URL.
MKDOCS_DOCS_PATH /mkdocs/docs Documentation source directory inside the container.

Code Server (Web IDE)

Variable Default Description
CODE_SERVER_PORT 8888 Code Server web UI port.
CODE_SERVER_URL http://code-server-changemaker:8443 Internal container URL.

Homepage (Service Dashboard)

Variable Default Description
HOMEPAGE_PORT 3010 Homepage web UI port.
HOMEPAGE_EMBED_PORT 8887 Port for iframe embedding in admin.
HOMEPAGE_VAR_BASE_URL http://localhost Base URL used in Homepage service links.

Mini QR (QR Code Generator)

Variable Default Description
MINI_QR_PORT 8089 Mini QR direct access port.
MINI_QR_URL http://mini-qr:8080 Internal container URL.
MINI_QR_EMBED_PORT 8885 Port for iframe embedding (walk sheets, cut exports).

Excalidraw (Whiteboard)

Variable Default Description
EXCALIDRAW_PORT 8090 Excalidraw web UI port.
EXCALIDRAW_URL http://excalidraw-changemaker:80 Internal container URL.
EXCALIDRAW_EMBED_PORT 8886 Port for iframe embedding.
EXCALIDRAW_WS_URL wss://draw.cmlite.org WebSocket URL for real-time collaboration.

Vaultwarden (Password Manager)

Self-hosted Bitwarden-compatible password manager. Optional service.

Variable Default Description
VAULTWARDEN_PORT 8445 Vaultwarden web UI port.
VAULTWARDEN_URL http://vaultwarden-changemaker:80 Internal container URL.
VAULTWARDEN_EMBED_PORT 8890 Port for iframe embedding in admin.
VAULTWARDEN_ADMIN_TOKEN (empty) Admin panel token (access at /admin). Generate with openssl rand -hex 32.
VAULTWARDEN_DOMAIN https://vault.cmlite.org Public-facing URL. Must use HTTPS — Bitwarden web vault enforces HTTPS for account creation. Set to your Pangolin tunnel URL.
VAULTWARDEN_SIGNUPS_ALLOWED false Allow new user self-registration. Keep false and use admin panel invites.
VAULTWARDEN_WEBSOCKET_ENABLED true Enable WebSocket notifications for real-time sync.
VAULTWARDEN_SMTP_SECURITY off SMTP security mode: off for MailHog, starttls or force_tls for production. Uses the main SMTP_* variables for host/credentials.

Initial setup

The vaultwarden-init container automatically invites the INITIAL_ADMIN_EMAIL user when starting. Check MailHog (or your SMTP) for the invitation email.


Rocket.Chat (Team Chat)

Self-hosted team chat for volunteer coordination. Requires MongoDB (auto-configured).

Variable Default Description
ENABLE_CHAT false Set to true to enable the Rocket.Chat integration. The initial default; once saved in admin Settings, the DB value is authoritative.
ROCKETCHAT_ADMIN_USER rcadmin Rocket.Chat admin username.
ROCKETCHAT_ADMIN_PASSWORD Rocket.Chat admin password.
ROCKETCHAT_URL http://rocketchat-changemaker:3000 Internal container URL.
ROCKETCHAT_EMBED_PORT 8891 Port for iframe embedding in admin.
MONGO_ROOT_USER rocketchat MongoDB admin username.
MONGO_ROOT_PASSWORD MongoDB admin password. MongoDB runs with --auth enabled.

Gancio (Event Management)

Self-hosted event management platform. Uses the shared PostgreSQL database (auto-created by init-gancio-db.sh).

Variable Default Description
GANCIO_PORT 8092 Gancio web UI port.
GANCIO_URL http://gancio-changemaker:13120 Internal container URL.
GANCIO_EMBED_PORT 8892 Port for iframe embedding in admin.
GANCIO_BASE_URL https://events.cmlite.org Public-facing URL for Gancio. Used in event links.
GANCIO_ADMIN_USER admin Gancio admin username for shift-to-event sync (OAuth login).
GANCIO_ADMIN_PASSWORD Gancio admin password.
GANCIO_SYNC_ENABLED false Set to true to enable automatic shift → Gancio event synchronization.

Jitsi Meet (Video Conferencing)

Self-hosted video conferencing with JWT authentication. Integrates with Rocket.Chat for in-channel video calls.

Variable Default Description
ENABLE_MEET false Set to true to enable the Jitsi Meet integration. The initial default; once saved in admin Settings, the DB value is authoritative.
JITSI_APP_ID changemaker JWT application ID. Must match across Jitsi Prosody, Rocket.Chat app settings, and JWT_ACCEPTED_ISSUERS/JWT_ACCEPTED_AUDIENCES.
JITSI_APP_SECRET JWT secret for signing Jitsi tokens. Generate with openssl rand -hex 32. Shared between Jitsi Prosody, Rocket.Chat, and the API.
JITSI_JICOFO_AUTH_PASSWORD Internal XMPP password for Jicofo (conference focus). Generate with openssl rand -hex 16.
JITSI_JVB_AUTH_PASSWORD Internal XMPP password for JVB (video bridge). Generate with openssl rand -hex 16.
JITSI_EMBED_PORT 8893 Port for iframe embedding in admin.
JITSI_URL http://jitsi-web-changemaker:80 Internal container URL.
JVB_ADVERTISE_IP (empty) Server's public IP address. Required in production for NAT traversal so remote participants can connect.
JVB_PORT 10000 UDP port for media traffic. Must be open in your firewall.

Production requirements

  • JVB_ADVERTISE_IP must be set to your server's public IP for calls to work outside the local network.
  • Port 10000/udp must be open in your firewall for media traffic.
  • Calls must go through the production domain (not localhost) for SSL/JWT to work.

SMS Campaigns (Termux Android Bridge)

Send SMS messages via an Android phone running the Termux API server. The phone acts as an SMS gateway.

Variable Default Description
ENABLE_SMS false Set to true to enable SMS campaigns. The initial default; once saved in admin Settings, the DB value is authoritative.
TERMUX_API_URL http://10.0.0.193:5001 URL of the Termux API server running on the Android phone.
TERMUX_API_KEY (empty) API key for authenticating with the Termux server (HMAC auth via X-API-Key header).
SMS_DELAY_BETWEEN_MS 3000 Delay between sending individual SMS messages (ms). Prevents carrier throttling.
SMS_MAX_RETRIES 3 Maximum retry attempts for failed SMS sends.
SMS_RESPONSE_SYNC_INTERVAL_MS 30000 How often to poll the phone's inbox for responses (ms).
SMS_DEVICE_MONITOR_INTERVAL_MS 30000 How often to check device health — battery, connectivity (ms).

GUI configuration

The Termux API URL and API key can also be configured from Admin → Settings → SMS. Database values override these env vars when set.


MailHog (Development Email)

Variable Default Description
MAILHOG_SMTP_PORT 1025 SMTP port for capturing emails.
MAILHOG_WEB_PORT 8025 Web UI to view captured emails.

NAR (National Address Register)

Canadian address data import for geographic canvassing.

Variable Default Description
NAR_DATA_DIR /data Path to extracted NAR data inside the container. Expects YYYYMM/Addresses/ and YYYYMM/Locations/ subdirectories. Mount via ./data:/data:ro in Docker Compose.

Download NAR data from Statistics Canada.


Geocoding

Multi-provider geocoding for address resolution. Works out of the box with free providers; optional paid providers improve accuracy.

Variable Default Description
MAPBOX_API_KEY (empty) Mapbox API key for improved geocoding accuracy. Free tier: 100k requests/month. Sign up.
GEOCODING_RATE_LIMIT_MS 1100 Delay between requests to free providers (ms). Respects rate limits.
GEOCODING_CACHE_ENABLED true Enable Redis-backed geocoding cache.
GEOCODING_CACHE_TTL_HOURS 24 Cache lifetime in hours.
GOOGLE_MAPS_API_KEY (empty) Google Maps API key. Most accurate but $0.005/request after free tier.
GOOGLE_MAPS_ENABLED false Enable Google Maps as a geocoding provider.
GEOCODING_PARALLEL_ENABLED true Enable parallel geocoding for bulk imports (~10x speedup).
GEOCODING_BATCH_SIZE 10 Number of concurrent geocoding requests during bulk operations.
BULK_GEOCODE_ENABLED true Enable bulk re-geocoding from the admin UI.
BULK_GEOCODE_MAX_BATCH 5000 Maximum locations per bulk geocoding run.

Overpass / Area Import

OpenStreetMap data import for map enrichment.

Variable Default Description
OVERPASS_API_URL https://overpass-api.de/api/interpreter Overpass API endpoint. Use a private instance for heavy usage.
OVERPASS_MIN_DELAY_MS 30000 Minimum delay between requests (ms). The public API requires 30 seconds.
AREA_IMPORT_MAX_GRID_POINTS 500 Maximum reverse-geocode grid points per area import.

Pangolin Tunnel

Expose services to the internet without port forwarding, using a self-hosted Pangolin instance.

Variable Default Description
PANGOLIN_API_URL https://api.bnkserve.org/v1 Pangolin server API endpoint.
PANGOLIN_API_KEY (empty) API key for Pangolin management.
PANGOLIN_ORG_ID (empty) Organization ID in Pangolin.
PANGOLIN_SITE_ID (empty) Site ID (populated after setup via admin GUI).
PANGOLIN_ENDPOINT https://pangolin.bnkserve.org Pangolin tunnel endpoint.
PANGOLIN_NEWT_ID (empty) Newt client ID (populated after setup).
PANGOLIN_NEWT_SECRET (empty) Newt client secret (populated after setup).

Setup flow

Configure the tunnel from Admin → Settings → Pangolin. The setup wizard walks you through creating a site, copying credentials, and connecting the Newt container. See Deployment for the full guide.


Monitoring

These services are behind the monitoring Docker Compose profile. Start them with:

docker compose --profile monitoring up -d
Variable Default Description
PROMETHEUS_PORT 9090 Prometheus web UI / query port.
GRAFANA_PORT 3005 Grafana dashboard port.
GRAFANA_ADMIN_PASSWORD admin Change in production.
GRAFANA_ROOT_URL http://localhost:3005 Public URL for Grafana (used in links).
CADVISOR_PORT 8086 cAdvisor container metrics port.
NODE_EXPORTER_PORT 9100 Prometheus node exporter port.
REDIS_EXPORTER_PORT 9121 Redis metrics exporter port.
ALERTMANAGER_PORT 9093 Alertmanager web UI port.
GOTIFY_PORT 8889 Gotify push notification port.
GOTIFY_ADMIN_USER admin Gotify admin username.
GOTIFY_ADMIN_PASSWORD admin Change in production.
GRAFANA_EMBED_PORT 8894 Port for iframe embedding Grafana in admin.
ALERTMANAGER_EMBED_PORT 8895 Port for iframe embedding Alertmanager in admin.

Bunker Ops (Fleet Management)

Remote metrics push for managing multiple Changemaker Lite instances from a central monitoring server.

Variable Default Description
INSTANCE_LABEL (empty) Unique label for this instance (used as a Prometheus metric label). Falls back to DOMAIN if empty.
BUNKER_OPS_ENABLED false Enable remote metrics push to a central VictoriaMetrics server.
BUNKER_OPS_REMOTE_WRITE_URL (empty) VictoriaMetrics remote_write endpoint (e.g., https://ops.example.com/api/v1/write).

Social, People & Analytics

Feature flags for the social graph, CRM people module, and analytics dashboard.

Variable Default Description
ENABLE_SOCIAL false Enable the social module (friendships, challenges, spotlights, referrals). The initial default; once saved in admin Settings, the DB value is authoritative.
ENABLE_PEOPLE false Enable the CRM people module. The initial default; once saved in admin Settings, the DB value is authoritative.
ENABLE_ANALYTICS false Enable the analytics dashboard with visitor tracking and geographic insights. The initial default; once saved in admin Settings, the DB value is authoritative.

GeoIP (MaxMind GeoLite2)

Geographic IP lookup for analytics visitor location tracking. Requires a free MaxMind account.

Variable Default Description
MAXMIND_ACCOUNT_ID (empty) MaxMind account ID. Sign up free.
MAXMIND_LICENSE_KEY (empty) MaxMind license key. When set, the GeoLite2-City database auto-downloads at startup.
GEOIP_DB_PATH /data/geoip/GeoLite2-City.mmdb Path to the GeoLite2 database file inside the container.

Control Panel Agent (CCP)

Remote management agent for the Changemaker Control Panel — enables centralized multi-instance management.

Variable Default Description
ENABLE_CCP_AGENT false Enable the CCP remote management agent.
CCP_URL (empty) URL of the Changemaker Control Panel server.
CCP_INVITE_CODE (empty) One-time invite code for agent registration with the control panel.
CCP_AGENT_URL (empty) How the CCP can reach this agent (must be externally accessible).
CCP_AGENT_PORT 7443 Agent listener port.

Container Registry

Settings for pulling pre-built production images from the Gitea container registry.

Variable Default Description
GITEA_REGISTRY gitea.bnkops.com/admin Registry hostname and namespace for pulling images.
IMAGE_TAG (empty) Image tag to pull. Set to a commit SHA or latest for pre-built images. Leave empty (defaults to local) to build from source.
COMPOSE_PROFILES (empty) Docker Compose profiles to activate. Set to monitoring to include Prometheus/Grafana/Alertmanager in every docker compose up -d.
GITEA_REGISTRY_USER admin Registry username for docker login and the registry status API endpoint.
GITEA_REGISTRY_PASS (empty) Registry password for the status API endpoint. For docker push/pull, use docker login gitea.bnkops.com.
GITEA_REGISTRY_API_TOKEN (empty) API token for the remote registry (gitea.bnkops.com). Used by build-release.sh --upload to publish release tarballs. Create at Gitea → User Settings → Applications. Not the same as GITEA_API_TOKEN.

Docker / Container Management

Internal settings for the admin dashboard's service status panel and container management.

Variable Default Description
DOCKER_NETWORK_NAME changemaker-lite Docker bridge network name. Used by the dashboard to auto-discover containers.
DOCKER_PROXY_URL http://docker-socket-proxy:2375 Read-only Docker socket proxy URL for container inspection.
NEWT_CONTAINER_NAME newt-changemaker Newt tunnel container name (for restart/status checks).
NEWT_COMPOSE_SERVICE newt Docker Compose service name for the Newt container.

Embed Proxy Ports

Dedicated nginx ports for iframe embedding services in the admin dashboard without requiring DNS/subdomains. Change these to avoid port conflicts when running multiple instances on one host.

Variable Default Description
NOCODB_EMBED_PORT 8881 NocoDB iframe port.
N8N_EMBED_PORT 8882 n8n iframe port.
GITEA_EMBED_PORT 8883 Gitea iframe port.
MAILHOG_EMBED_PORT 8884 MailHog iframe port.
MINI_QR_EMBED_PORT 8885 Mini QR iframe port.
EXCALIDRAW_EMBED_PORT 8886 Excalidraw iframe port.
HOMEPAGE_EMBED_PORT 8887 Homepage iframe port.
VAULTWARDEN_EMBED_PORT 8890 Vaultwarden iframe port.
ROCKETCHAT_EMBED_PORT 8891 Rocket.Chat iframe port.
GANCIO_EMBED_PORT 8892 Gancio iframe port.
JITSI_EMBED_PORT 8893 Jitsi iframe port.
GRAFANA_EMBED_PORT 8894 Grafana iframe port.
ALERTMANAGER_EMBED_PORT 8895 Alertmanager iframe port.

Gitea Docs Version History

Settings for the documentation version history feature (backed by Gitea repository commits).

Variable Default Description
GITEA_DOCS_REPO admin/changemaker.lite Gitea repository path for docs version history.
GITEA_DOCS_PREFIX mkdocs/docs Path prefix within the repository where documentation files live.
GITEA_DOCS_BRANCH v2 Git branch to query for version history.
GITEA_ADMIN_PASSWORD (empty) Gitea admin password. Used once during initial setup to create an API token, then can be cleared.

Prisma CLI (Host-Side)

Variable Default Description
DATABASE_URL postgresql://changemaker:YOUR_POSTGRES_PASSWORD@localhost:5433/changemaker_v2 Full PostgreSQL connection string. Only used when running Prisma CLI on the host (npx prisma migrate dev). Docker containers resolve the database hostname internally via Docker Compose environment variables.

Generating Secrets

Use these commands to generate all required secrets at once:

# JWT secrets (three separate values)
echo "JWT_ACCESS_SECRET=$(openssl rand -hex 32)"
echo "JWT_REFRESH_SECRET=$(openssl rand -hex 32)"
echo "JWT_INVITE_SECRET=$(openssl rand -hex 32)"

# Encryption key (must differ from JWT secrets)
echo "ENCRYPTION_KEY=$(openssl rand -hex 32)"

# Security extras (key separation)
echo "GITEA_SSO_SECRET=$(openssl rand -hex 32)"
echo "SERVICE_PASSWORD_SALT=$(openssl rand -hex 32)"

# Database and Redis passwords
echo "V2_POSTGRES_PASSWORD=$(openssl rand -hex 24)"
echo "REDIS_PASSWORD=$(openssl rand -hex 24)"

# Listmonk
echo "LISTMONK_DB_PASSWORD=$(openssl rand -hex 24)"
echo "LISTMONK_WEB_ADMIN_PASSWORD=$(openssl rand -hex 16)"
LISTMONK_TOKEN=$(openssl rand -hex 16)
echo "LISTMONK_API_TOKEN=$LISTMONK_TOKEN"
echo "LISTMONK_ADMIN_PASSWORD=$LISTMONK_TOKEN"

# Supporting services
echo "GITEA_DB_PASSWD=$(openssl rand -hex 24)"
echo "GITEA_DB_ROOT_PASSWORD=$(openssl rand -hex 24)"
echo "N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)"
echo "N8N_USER_PASSWORD=$(openssl rand -hex 16)"
echo "NC_ADMIN_PASSWORD=$(openssl rand -hex 16)"
echo "INITIAL_ADMIN_PASSWORD=$(openssl rand -base64 18)"

# Vaultwarden
echo "VAULTWARDEN_ADMIN_TOKEN=$(openssl rand -hex 32)"

# Rocket.Chat + MongoDB
echo "ROCKETCHAT_ADMIN_PASSWORD=$(openssl rand -hex 16)"
echo "MONGO_ROOT_PASSWORD=$(openssl rand -hex 24)"

# Gancio
echo "GANCIO_ADMIN_PASSWORD=$(openssl rand -hex 16)"

# Jitsi Meet
echo "JITSI_APP_SECRET=$(openssl rand -hex 32)"
echo "JITSI_JICOFO_AUTH_PASSWORD=$(openssl rand -hex 16)"
echo "JITSI_JVB_AUTH_PASSWORD=$(openssl rand -hex 16)"

Tip

Copy the output and paste the values into your .env file. The INITIAL_ADMIN_PASSWORD uses base64 encoding to ensure it contains uppercase, lowercase, and digits (meeting the password policy).


Minimal vs Full Deployment

For a basic deployment with campaigns, map, and admin:

Required variables
V2_POSTGRES_PASSWORD=...
REDIS_PASSWORD=...
JWT_ACCESS_SECRET=...
JWT_REFRESH_SECRET=...
JWT_INVITE_SECRET=...
ENCRYPTION_KEY=...
INITIAL_ADMIN_PASSWORD=...
Start services
docker compose up -d v2-postgres redis api admin

For the complete platform including media, newsletters, monitoring, and all services:

Additional variables needed
# Everything above, plus:
ENABLE_MEDIA_FEATURES=true
ENABLE_PAYMENTS=true
ENABLE_CHAT=true
ENABLE_MEET=true
ENABLE_SMS=true
LISTMONK_SYNC_ENABLED=true
GANCIO_SYNC_ENABLED=true
LISTMONK_DB_PASSWORD=...
LISTMONK_WEB_ADMIN_PASSWORD=...
LISTMONK_API_TOKEN=...
NC_ADMIN_PASSWORD=...
GITEA_DB_PASSWD=...
GITEA_DB_ROOT_PASSWORD=...
N8N_ENCRYPTION_KEY=...
N8N_USER_PASSWORD=...
VAULTWARDEN_ADMIN_TOKEN=...
ROCKETCHAT_ADMIN_PASSWORD=...
MONGO_ROOT_PASSWORD=...
GANCIO_ADMIN_PASSWORD=...
JITSI_APP_SECRET=...
JITSI_JICOFO_AUTH_PASSWORD=...
JITSI_JVB_AUTH_PASSWORD=...
JVB_ADVERTISE_IP=your.public.ip.here
EMAIL_TEST_MODE=false
SMTP_HOST=smtp.your-provider.com
SMTP_PORT=587
SMTP_USER=you@example.com
SMTP_PASS=your-smtp-password
Start services
docker compose up -d
docker compose --profile monitoring up -d