Installation¶
Changemaker Lite runs as a set of Docker containers orchestrated by Docker Compose. The config.sh wizard handles all configuration — or you can set things up manually.
Prerequisites¶
- Docker 24+ and Docker Compose v2
- OpenSSL (for secret generation)
- A Linux server (Ubuntu 22.04+ recommended) or macOS for development
- At least 2 GB RAM for core services, 4 GB for the full stack
- A domain name (optional for development, recommended for production)
Quick Start¶
Clone the repository:
Run the configuration wizard:
Start all services:
Open http://localhost:3000 and sign in with the admin credentials you configured. Database migrations and seeding run automatically on first startup.
Change your password
If you used the wizard's generated password, change it immediately from the admin dashboard.
Configuration Wizard (config.sh)¶
The wizard performs 14 steps to produce a fully configured .env file and prepare the system for startup. Each step is interactive with sensible defaults.
Step 1: Prerequisites Check¶
Verifies that Docker, Docker Compose v2, and OpenSSL are installed. Exits immediately if any are missing, with links to installation guides.
Step 2: Environment File Setup¶
- If no
.envexists, copies.env.exampleas the starting point - If
.envalready exists, offers to back it up (timestamped copy) and create a fresh one, or update values in place
Step 3: Domain Configuration¶
Prompts for your root domain (default: cmlite.org) and derives 14 environment variables from it:
| Variable | Example Value |
|---|---|
DOMAIN |
example.org |
BASE_DOMAIN |
https://example.org |
GITEA_ROOT_URL |
https://git.example.org |
GITEA_DOMAIN |
git.example.org |
N8N_HOST |
n8n.example.org |
SMTP_FROM |
noreply@example.org |
INITIAL_ADMIN_EMAIL |
admin@example.org |
NC_ADMIN_EMAIL |
admin@example.org |
EXCALIDRAW_WS_URL |
wss://draw.example.org |
LISTMONK_SMTP_FROM |
Changemaker Lite <noreply@example.org> |
HOMEPAGE_VAR_BASE_URL |
https://example.org |
VAULTWARDEN_DOMAIN |
https://vault.example.org |
GANCIO_BASE_URL |
https://events.example.org |
TEST_EMAIL_RECIPIENT |
admin@example.org |
Also updates mkdocs/mkdocs.yml with the new site_url and repo_url, and asks whether this is a production deployment (sets NODE_ENV=production).
Step 4: Admin Credentials¶
Prompts for the initial super-admin email and password. The password is validated against the security policy:
- Minimum 12 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one digit
- Requires password confirmation
Step 5: Secret Generation¶
Auto-generates 21 unique secrets — no placeholder passwords remain after this step:
| Category | Count | Secrets |
|---|---|---|
| JWT & Encryption | 3 | JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, ENCRYPTION_KEY (64-char hex) |
| Database | 2 | V2_POSTGRES_PASSWORD, REDIS_PASSWORD (24-char alphanumeric) |
| Listmonk | 3 | LISTMONK_DB_PASSWORD, LISTMONK_WEB_ADMIN_PASSWORD, LISTMONK_API_TOKEN |
| NocoDB | 1 | NC_ADMIN_PASSWORD |
| Gitea | 2 | GITEA_DB_PASSWD, GITEA_DB_ROOT_PASSWORD |
| n8n | 2 | N8N_ENCRYPTION_KEY, N8N_USER_PASSWORD |
| Monitoring | 2 | GRAFANA_ADMIN_PASSWORD, GOTIFY_ADMIN_PASSWORD |
| Vaultwarden | 1 | VAULTWARDEN_ADMIN_TOKEN (64-char hex) |
| Rocket.Chat | 1 | ROCKETCHAT_ADMIN_PASSWORD |
| Gancio | 1 | GANCIO_ADMIN_PASSWORD |
| Jitsi Meet | 3 | JITSI_APP_SECRET (64-char hex), JITSI_JICOFO_AUTH_PASSWORD, JITSI_JVB_AUTH_PASSWORD |
Step 6: Email Configuration¶
Choose between:
- MailHog (default) — captures all outgoing emails at
http://localhost:8025for development - Production SMTP — configures host, port, user, and password. Optionally shares credentials with Listmonk for newsletter delivery
Step 7: Feature Flags¶
Enable or disable 9 optional platform features:
| Flag | Environment Variable | What It Enables |
|---|---|---|
| Media Manager | ENABLE_MEDIA_FEATURES=true |
Video library, analytics, scheduled publishing |
| Listmonk Sync | LISTMONK_SYNC_ENABLED=true |
Newsletter subscriber sync from platform participants |
| Payments | ENABLE_PAYMENTS=true |
Stripe-based products, donations, and plans |
| Rocket.Chat | ENABLE_CHAT=true |
Team communication platform |
| Gancio Events | GANCIO_SYNC_ENABLED=true |
Shift-to-event sync with Gancio |
| Jitsi Meet | ENABLE_MEET=true |
Video conferencing (also prompts for server public IP) |
| SMS Campaigns | ENABLE_SMS=true |
Termux Android bridge for SMS (also prompts for API URL) |
| Docs Comments | GITEA_COMMENTS_ENABLED=true |
Gitea-backed page comments on documentation |
| Bunker Ops | BUNKER_OPS_ENABLED=true |
Fleet metrics push to central server (also prompts for remote write URL) |
Step 8: Tunnel Configuration (Pangolin)¶
Optionally configures Pangolin tunnel credentials for secure public access:
PANGOLIN_API_URL— API endpoint (default:https://api.bnkserve.org/v1)PANGOLIN_API_KEY— Authentication keyPANGOLIN_ORG_ID— Organization identifier
Complete tunnel setup is done from the admin GUI at Settings > Tunnel after services are running.
Step 9: CORS Origins¶
Automatically calculates allowed origins from your domain:
http://app.DOMAIN,https://app.DOMAIN,http://DOMAIN,https://DOMAIN,http://localhost:3000,http://localhost,http://localhost:4003
Step 10: Nginx Config Generation¶
Renders all .conf.template files in nginx/conf.d/ by substituting ${DOMAIN} with your configured domain. This produces the nginx configuration files that handle subdomain routing.
Step 11: Homepage Services YAML¶
Generates configs/homepage/services.yaml with 27 service entries (both production and local development URLs) for the Homepage service dashboard.
Step 12: Container Directory Permissions¶
Creates and sets permissions (775) on 12 directories needed by containers:
| Directory | Purpose |
|---|---|
configs/code-server/.config |
Code Server configuration |
configs/code-server/.local |
Code Server local data |
mkdocs/.cache |
MkDocs build cache |
mkdocs/site |
MkDocs built site output |
assets/uploads |
Listmonk uploads |
assets/images |
Shared images |
assets/icons |
Homepage icons |
media/local/inbox |
Media upload inbox |
media/local/thumbnails |
Video thumbnails |
media/public |
Public media files |
local-files |
n8n local files |
data |
NAR import data |
Step 13: Upgrade Watcher (Optional)¶
Installs a systemd path watcher that enables the admin GUI's "Check for Updates" and "Start Upgrade" buttons. This step requires sudo and is optional — you can install it later or use the CLI upgrade script directly.
The watcher installs two systemd units:
changemaker-upgrade.path— watches fordata/upgrade/trigger.jsonchangemaker-upgrade.service— runsscripts/upgrade-watcher.shwhen triggered
Step 14: Summary & Next Steps¶
Displays a configuration summary showing all choices made, then prints startup commands.
What Gets Modified¶
After the wizard completes, the following files have been created or modified:
| File | Action |
|---|---|
.env |
Created (or updated) with all configuration values |
mkdocs/mkdocs.yml |
Updated site_url and repo_url with domain |
nginx/conf.d/*.conf |
Generated from .conf.template files |
configs/homepage/services.yaml |
Generated with all service URLs |
| 12 directories | Created with container-friendly permissions |
| systemd units (optional) | Installed to /etc/systemd/system/ |
Manual Setup (Alternative)¶
If you prefer to configure by hand instead of using the wizard:
At minimum, set these required secrets:
# Generate cryptographic secrets
V2_POSTGRES_PASSWORD=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | head -c 24)
REDIS_PASSWORD=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | head -c 24)
JWT_ACCESS_SECRET=$(openssl rand -hex 32)
JWT_REFRESH_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
Set your admin credentials (password must meet the 12+ char complexity requirement):
Then configure optional sections:
- Domain: Set
DOMAINand all derived variables (see Step 3 table above) - SMTP: Set
SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,EMAIL_TEST_MODE=false - Feature flags: Enable features as needed (see Step 7 table above)
- Tunnel: Set
PANGOLIN_API_URL,PANGOLIN_API_KEY,PANGOLIN_ORG_ID
See Environment Variables for every available option.
Full Stack Startup¶
After configuration, start the entire platform:
That's it. Docker handles the startup order automatically:
- PostgreSQL and Redis start first (with healthchecks)
- API waits for both to be healthy, then auto-runs database migrations and seeding
- Admin GUI waits for the API
- Nginx, media, communication, and all other services start in parallel
- Init containers (nocodb-init, listmonk-init, etc.) run once and exit
Watch the startup progress:
Once you see Starting server on port 4000, open http://localhost:3000 and log in.
Include Monitoring¶
The monitoring stack (Prometheus, Grafana, Alertmanager) uses a Docker Compose profile and isn't included by default:
Start Only Core Services¶
If you prefer a minimal startup (lower resource usage):
Manual migrations
The API container runs migrations and seeding automatically on startup via its entrypoint script. You only need to run them manually if you're developing locally without Docker:
See Services Overview for the complete service catalog.
Verifying Installation¶
After starting services, verify everything is healthy:
# Check running containers
docker compose ps
# API health check
curl -s http://localhost:4000/api/health | python3 -m json.tool
# View API logs
docker compose logs api --tail 20
# Check for containers in restart loops
docker compose ps | grep -i restarting
You should see the API return {"status":"ok"} and all started containers in a "running" state.
Next Steps¶
- Services Overview — complete service catalog with ports and startup commands
- Environment Variables — complete
.envreference - First Steps — create your first campaign and add locations
- Updates & Upgrades — keep your installation up to date