Self-Hosting
Docker Deployment
Deploy with Docker Compose
Quick Start
- Download docker-compose.yml
- Configure environment variables
- Run
docker compose up -d
Minimal .env
# Required
JWT_SECRET="$(openssl rand -base64 32)"
DB_PASSWORD="your-secure-password"
# Domains (point these to your server)
API_DOMAIN="api.yourdomain.com"
DASHBOARD_DOMAIN="app.yourdomain.com"
LANDING_DOMAIN="www.yourdomain.com"
WIKI_DOMAIN="docs.yourdomain.com"
USE_HTTPS="true"
# AWS SES
AWS_SES_REGION="us-east-1"
AWS_SES_ACCESS_KEY_ID="your-key"
AWS_SES_SECRET_ACCESS_KEY="your-secret"
SES_CONFIGURATION_SET="plunk-tracking"See Environment Variables for all options.
Services
| Service | Purpose |
|---|---|
plunk | All apps + nginx (API, Web, Landing, Wiki, SMTP) |
postgres | PostgreSQL 16 database |
redis | Redis 7 queue |
minio | S3-compatible storage |
ntfy | Notifications |
Ports
| Port | Service |
|---|---|
| 80 | Nginx (HTTP) |
| 465 | SMTP (implicit TLS) |
| 587 | SMTP (STARTTLS) |
| 9000 | Minio API |
Running Individual Services
Set SERVICE environment variable:
SERVICE=api # API only
SERVICE=worker # Worker only
SERVICE=web # Dashboard only
SERVICE=all # Everything (default)SMTP TLS Certificates
For TLS on ports 465/587, provide certificates via one of these methods:
Traefik acme.json (Dokploy, Coolify)
Mount the acme.json file and set SMTP_DOMAIN:
environment:
SMTP_DOMAIN: "smtp.yourdomain.com"
volumes:
- /path/to/acme.json:/certs/acme.json:roPlunk automatically extracts the certificate for SMTP_DOMAIN from acme.json.
PEM Files
Mount certificate files directly:
volumes:
- /path/to/privkey.pem:/certs/privkey.pem:ro
- /path/to/fullchain.pem:/certs/fullchain.pem:roIf no certificates are mounted, SMTP runs without TLS.
Building from Source
docker build -t plunk:custom .