# ============================================================================== # Changemaker Lite v2 — Tenant .env (CCP-rendered) # Instance: {{name}} ({{slug}}) # Generated by CCP on {{now}} # ============================================================================== # This file is a near-mirror of changemaker.lite/.env.example with Handlebars # overlay for tenant-specific values (DOMAIN, secrets, COMPOSE_PROJECT_NAME). # Static defaults match .env.example so docker-compose.yml.hbs (a mirror of # docker-compose.prod.yml) has every ${VAR} it references. # # Keeping this in sync with .env.example after upstream additions: copy the # new key + default, replace any tenant-specific value with the matching # Handlebars expression. Most additions need no Handlebars. # ============================================================================== # --- General --- NODE_ENV=production DOMAIN={{domain}} COMPOSE_PROJECT_NAME={{composeProject}} TZ=UTC USER_ID=1000 GROUP_ID=1000 DOCKER_GROUP_ID=984 # --- V2 PostgreSQL --- V2_POSTGRES_USER=changemaker V2_POSTGRES_PASSWORD={{secrets.postgresPassword}} V2_POSTGRES_DB=changemaker_v2 V2_POSTGRES_PORT={{ports.postgres}} # --- JWT Auth --- JWT_ACCESS_SECRET={{secrets.jwtAccessSecret}} JWT_REFRESH_SECRET={{secrets.jwtRefreshSecret}} JWT_INVITE_SECRET={{secrets.jwtInviteSecret}} JWT_ACCESS_EXPIRY=15m # Reduced from 7d → 24h on 2026-04-12 (P2-3 hardening). Combined with # device-fingerprint binding in the JWT payload, this tightens the # exploitation window for stolen refresh tokens. JWT_REFRESH_EXPIRY=24h # Encryption key for DB-stored secrets (SMTP password, etc.) ENCRYPTION_KEY={{secrets.encryptionKey}} # Gitea SSO cookie signing secret + service password salt — REQUIRED 2026-04-12 # (P2-2). Distinct from JWT secrets; empty values will fail Zod validation on # boot. Both ≥32 chars, distinct from each other and from JWT_* secrets. GITEA_SSO_SECRET={{secrets.giteaSsoSecret}} SERVICE_PASSWORD_SALT={{secrets.servicePasswordSalt}} # --- Initial Super Admin User --- INITIAL_ADMIN_EMAIL={{secrets.adminEmail}} INITIAL_ADMIN_PASSWORD={{secrets.initialAdminPassword}} # --- API --- API_PORT=4000 API_URL=https://api.{{domain}} CORS_ORIGINS=https://app.{{domain}},http://localhost:{{ports.admin}},http://localhost # --- Admin GUI --- ADMIN_PORT=3000 ADMIN_URL=https://app.{{domain}} # --- Nginx --- NGINX_HTTP_PORT={{ports.nginx}} NGINX_HTTPS_PORT=443 # --- Embed Proxy Ports --- # Dedicated nginx ports for iframe embedding without DNS/subdomain. # CCP allocates these per-instance via {{ports.embed}} base + offset. NOCODB_EMBED_PORT={{math ports.embed "+" 0}} N8N_EMBED_PORT={{math ports.embed "+" 1}} GITEA_EMBED_PORT={{math ports.embed "+" 2}} MAILHOG_EMBED_PORT={{math ports.embed "+" 3}} MINI_QR_EMBED_PORT={{math ports.embed "+" 4}} EXCALIDRAW_EMBED_PORT={{math ports.embed "+" 5}} HOMEPAGE_EMBED_PORT={{math ports.embed "+" 6}} VAULTWARDEN_EMBED_PORT={{math ports.embed "+" 9}} ROCKETCHAT_EMBED_PORT={{math ports.embed "+" 10}} GANCIO_EMBED_PORT={{math ports.embed "+" 11}} JITSI_EMBED_PORT={{math ports.embed "+" 15}} GRAFANA_EMBED_PORT={{math ports.embed "+" 12}} ALERTMANAGER_EMBED_PORT={{math ports.embed "+" 16}} # --- Docker / Container Management --- DOCKER_NETWORK_NAME=changemaker-lite DOCKER_PROXY_URL=http://docker-socket-proxy:2375 NEWT_CONTAINER_NAME=newt-changemaker NEWT_COMPOSE_SERVICE=newt # --- SMTP / Email --- {{#if emailTestMode}} SMTP_HOST=mailhog-changemaker SMTP_PORT=1025 SMTP_USER= SMTP_PASS= EMAIL_TEST_MODE=true {{else}} SMTP_HOST={{smtpHost}} SMTP_PORT={{smtpPort}} SMTP_USER={{smtpUser}} SMTP_PASS= EMAIL_TEST_MODE=false {{/if}} SMTP_FROM={{smtpFrom}} SMTP_FROM_NAME={{name}} TEST_EMAIL_RECIPIENT={{secrets.adminEmail}} # --- Listmonk --- LISTMONK_PORT=9001 LISTMONK_DB_PORT=5434 LISTMONK_DB_USER=listmonk LISTMONK_DB_PASSWORD={{secrets.listmonkAdminPassword}} LISTMONK_DB_NAME=listmonk LISTMONK_WEB_ADMIN_USER=admin LISTMONK_WEB_ADMIN_PASSWORD={{secrets.listmonkAdminPassword}} LISTMONK_API_USER=v2-api LISTMONK_API_TOKEN={{secrets.listmonkApiToken}} LISTMONK_ADMIN_USER=v2-api LISTMONK_ADMIN_PASSWORD={{secrets.listmonkApiToken}} LISTMONK_SYNC_ENABLED={{#if enableListmonk}}true{{else}}false{{/if}} LISTMONK_WEBHOOK_SECRET= LISTMONK_PROXY_PORT=9002 LISTMONK_SMTP_HOST=mailhog-changemaker LISTMONK_SMTP_PORT=1025 LISTMONK_SMTP_USER= LISTMONK_SMTP_PASSWORD= LISTMONK_SMTP_TLS_TYPE=none LISTMONK_SMTP_FROM={{name}} # --- Represent API (Canadian electoral data) --- REPRESENT_API_URL=https://represent.opennorth.ca # --- NocoDB v2 (read-only data browser) --- NOCODB_V2_PORT=8091 NOCODB_URL=http://changemaker-v2-nocodb:8080 NOCODB_PORT=8091 NC_ADMIN_EMAIL={{secrets.adminEmail}} NC_ADMIN_PASSWORD={{secrets.nocodbAdminPassword}} NC_PUBLIC_URL=https://db.{{domain}} # --- Redis --- REDIS_PASSWORD={{secrets.redisPassword}} REDIS_URL=redis://:${REDIS_PASSWORD}@redis-changemaker:6379 # --- Payments (Stripe) --- ENABLE_PAYMENTS={{#if enablePayments}}true{{else}}false{{/if}} # --- Media Management --- ENABLE_MEDIA_FEATURES={{#if enableMedia}}true{{else}}false{{/if}} MEDIA_API_PORT=4100 MEDIA_API_PUBLIC_URL=https://media.{{domain}} VITE_MEDIA_API_URL=http://changemaker-media-api:4100 ENABLE_HLS_TRANSCODE=false MEDIA_ROOT=/media/library MEDIA_UPLOADS=/media/uploads MAX_UPLOAD_SIZE_GB=10 PUBLIC_MEDIA_PORT=3100 VIDEO_PLAYER_DEBUG=false VIDEO_ANALYTICS_RETENTION_DAYS=90 VIDEO_ANALYTICS_IP_HASHING_ENABLED=true VIDEO_SCHEDULE_DEFAULT_TIMEZONE=UTC VIDEO_SCHEDULE_NOTIFICATION_ENABLED=true VIDEO_PREVIEW_LINK_EXPIRY_HOURS=24 # --- Container Registry --- GITEA_REGISTRY=gitea.bnkops.com/admin IMAGE_TAG={{imageTag}} COMPOSE_PROFILES={{#if enableMonitoring}}monitoring{{/if}}{{#if enableCcpAgent}}{{#if enableMonitoring}},{{/if}}ccp-agent{{/if}} GITEA_REGISTRY_USER=admin GITEA_REGISTRY_PASS= GITEA_REGISTRY_API_TOKEN= # --- Gitea (Local Platform Instance) --- GITEA_URL=http://gitea-changemaker:3000 GITEA_PORT=3030 GITEA_WEB_PORT=3030 GITEA_SSH_PORT=2222 GITEA_ADMIN_USER=admin GITEA_ADMIN_PASSWORD={{secrets.giteaAdminPassword}} GITEA_DB_TYPE=mysql GITEA_DB_HOST=gitea-db:3306 GITEA_DB_NAME=gitea GITEA_DB_USER=gitea GITEA_DB_PASSWD={{secrets.giteaAdminPassword}} GITEA_DB_ROOT_PASSWORD={{secrets.giteaAdminPassword}} GITEA_ROOT_URL=https://git.{{domain}} GITEA_DOMAIN=git.{{domain}} # --- Gitea Docs Comments --- GITEA_COMMENTS_ENABLED=false GITEA_API_TOKEN= GITEA_COMMENTS_REPO_OWNER= GITEA_COMMENTS_REPO_NAME=docs-comments GITEA_OAUTH_CLIENT_ID= GITEA_OAUTH_CLIENT_SECRET= # Docs source (Gitea repo containing the mkdocs/ tree) GITEA_DOCS_REPO=admin/changemaker.lite GITEA_DOCS_PREFIX=mkdocs/docs GITEA_DOCS_BRANCH=v2 # --- n8n --- N8N_URL=http://n8n-changemaker:5678 N8N_PORT=5678 N8N_HOST=n8n.{{domain}} N8N_ENCRYPTION_KEY={{secrets.n8nEncryptionKey}} N8N_USER_EMAIL={{secrets.adminEmail}} N8N_USER_PASSWORD={{secrets.nocodbAdminPassword}} GENERIC_TIMEZONE=UTC # --- MkDocs --- MKDOCS_PORT=4003 MKDOCS_SITE_SERVER_PORT=4004 BASE_DOMAIN=https://{{domain}} MKDOCS_PREVIEW_URL=http://mkdocs:8000 MKDOCS_DOCS_PATH=/mkdocs/docs # --- Code Server --- CODE_SERVER_PORT=8888 CODE_SERVER_URL=http://code-server-changemaker:8443 USER_NAME=coder # --- Homepage --- HOMEPAGE_PORT=3010 HOMEPAGE_VAR_BASE_URL=http://localhost # --- Mini QR --- MINI_QR_PORT=8089 MINI_QR_URL=http://mini-qr:8080 # --- Excalidraw (Collaborative Whiteboard) --- EXCALIDRAW_PORT=8090 EXCALIDRAW_URL=http://excalidraw-changemaker:80 EXCALIDRAW_WS_URL=wss://draw.{{domain}} # --- Vaultwarden (Password Manager) --- VAULTWARDEN_PORT=8445 VAULTWARDEN_URL=http://vaultwarden-changemaker:80 VAULTWARDEN_ADMIN_TOKEN={{secrets.vaultwardenAdminToken}} VAULTWARDEN_DOMAIN=https://vault.{{domain}} VAULTWARDEN_SIGNUPS_ALLOWED=false VAULTWARDEN_WEBSOCKET_ENABLED=true VAULTWARDEN_SMTP_SECURITY=off # --- MailHog --- MAILHOG_SMTP_PORT=1025 MAILHOG_WEB_PORT=8025 # --- NAR (National Address Register) --- NAR_DATA_DIR=/data # --- Overpass / Area Import --- OVERPASS_API_URL=https://overpass-api.de/api/interpreter OVERPASS_MIN_DELAY_MS=30000 AREA_IMPORT_MAX_GRID_POINTS=500 # --- Geocoding --- MAPBOX_API_KEY= GEOCODING_RATE_LIMIT_MS=1100 GEOCODING_CACHE_ENABLED=true GEOCODING_CACHE_TTL_HOURS=24 GOOGLE_MAPS_API_KEY= GOOGLE_MAPS_ENABLED=false GEOCODING_PARALLEL_ENABLED=true GEOCODING_BATCH_SIZE=10 BULK_GEOCODE_ENABLED=true BULK_GEOCODE_MAX_BATCH=5000 # --- Pangolin Tunnel --- PANGOLIN_API_URL=https://api.bnkserve.org/v1 PANGOLIN_API_KEY= PANGOLIN_ORG_ID= PANGOLIN_SITE_ID= {{#if enablePangolin}} PANGOLIN_ENDPOINT={{pangolin.endpoint}} PANGOLIN_NEWT_ID={{pangolin.newtId}} PANGOLIN_NEWT_SECRET={{pangolin.newtSecret}} {{else}} PANGOLIN_ENDPOINT=https://pangolin.bnkserve.org PANGOLIN_NEWT_ID= PANGOLIN_NEWT_SECRET= {{/if}} # --- Prisma CLI (host-side only, NOT used by Docker containers) --- DATABASE_URL=postgresql://changemaker:{{secrets.postgresPassword}}@localhost:{{ports.postgres}}/changemaker_v2 # --- Rocket.Chat (Team Chat) --- ENABLE_CHAT={{#if enableChat}}true{{else}}false{{/if}} ROCKETCHAT_ADMIN_USER=rcadmin ROCKETCHAT_ADMIN_PASSWORD={{secrets.rocketchatAdminPassword}} ROCKETCHAT_URL=http://rocketchat-changemaker:3000 MONGO_ROOT_USER=rocketchat MONGO_ROOT_PASSWORD={{secrets.mongoRootPassword}} # --- Gancio (Event Management) --- GANCIO_PORT=8092 GANCIO_URL=http://gancio-changemaker:13120 GANCIO_BASE_URL=https://events.{{domain}} GANCIO_ADMIN_USER=admin GANCIO_ADMIN_PASSWORD={{secrets.gancioAdminPassword}} GANCIO_SYNC_ENABLED={{#if enableGancio}}true{{else}}false{{/if}} # --- Jitsi Meet (Video Conferencing) --- ENABLE_MEET={{#if enableMeet}}true{{else}}false{{/if}} JITSI_APP_ID=changemaker JITSI_APP_SECRET={{secrets.jitsiAppSecret}} JITSI_JICOFO_AUTH_PASSWORD={{secrets.jitsiJicofoAuthPassword}} JITSI_JVB_AUTH_PASSWORD={{secrets.jitsiJvbAuthPassword}} JITSI_URL=http://jitsi-web-changemaker:80 JVB_ADVERTISE_IP={{jvbAdvertiseIp}} JVB_PORT=10000 # --- SMS Campaigns (Termux Android Bridge) --- ENABLE_SMS={{#if enableSms}}true{{else}}false{{/if}} TERMUX_API_URL= TERMUX_API_KEY= SMS_DELAY_BETWEEN_MS=3000 SMS_MAX_RETRIES=3 SMS_RESPONSE_SYNC_INTERVAL_MS=120000 SMS_DEVICE_MONITOR_INTERVAL_MS=300000 # --- Social, People & Analytics --- ENABLE_SOCIAL={{#if enableSocial}}true{{else}}false{{/if}} ENABLE_PEOPLE={{#if enablePeople}}true{{else}}false{{/if}} ENABLE_ANALYTICS={{#if enableAnalytics}}true{{else}}false{{/if}} # --- Control Panel Agent --- # Tenants registered with CCP have these populated; CCP-provisioned tenants # get them set by the provisioner. Leaving blank if neither applies. ENABLE_CCP_AGENT=true CCP_URL= CCP_INVITE_CODE= CCP_AGENT_URL= CCP_AGENT_PORT=7443 # --- Monitoring (only used with --profile monitoring) --- PROMETHEUS_PORT=9090 GRAFANA_PORT=3005 GRAFANA_ADMIN_PASSWORD={{secrets.grafanaAdminPassword}} GRAFANA_ROOT_URL=https://grafana.{{domain}} CADVISOR_PORT=8086 NODE_EXPORTER_PORT=9100 REDIS_EXPORTER_PORT=9121 ALERTMANAGER_PORT=9093 GOTIFY_PORT=8889 GOTIFY_ADMIN_USER=admin GOTIFY_ADMIN_PASSWORD=admin # --- Bunker Ops (Fleet Management) --- INSTANCE_LABEL={{slug}} BUNKER_OPS_ENABLED=false BUNKER_OPS_REMOTE_WRITE_URL= # --- GeoIP (MaxMind GeoLite2) --- MAXMIND_ACCOUNT_ID= MAXMIND_LICENSE_KEY= # --- CCP-specific (admin GUI iframe embeds + dev-mode helpers) --- # These are CCP-only — not in canonical .env.example. Kept here because # admin/vite uses them at build time and the embed proxies reference them. PORT=4000 VITE_API_URL=http://changemaker-v2-api:4000 HOMEPAGE_URL=http://homepage-changemaker:3000 MAILHOG_URL=http://mailhog-changemaker:8025 LISTMONK_URL=http://listmonk-app:9000 CODE_SERVER_EMBED_PORT={{math ports.embed "+" 7}} MKDOCS_EMBED_PORT={{math ports.embed "+" 8}} MKDOCS_SITE_EMBED_PORT={{math ports.embed "+" 14}} LISTMONK_EMBED_PORT={{math ports.embed "+" 13}} ENABLE_DEV_TOOLS={{#if enableDevTools}}true{{else}}false{{/if}}