Installation
Cleanmails runs as a Docker Compose stack on any Linux VPS. This page covers the full manual installation process. For the fastest path, see Quick Deploy.
System Requirements
| Component | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 22.04 / Debian 12 | Ubuntu 22.04 LTS |
| CPU | 1 vCPU | 4 vCPU |
| RAM | 1 GB | 4 GB |
| Disk | 5 GB SSD | 50 GB SSD |
Manual Installation
1. Install Docker
curl -fsSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker2. Create the application directory
mkdir -p /opt/cleanmails
cd /opt/cleanmails3. Create the environment file
# Domain
DOMAIN=app.yourdomain.com
# Database
DB_PASSWORD=$(openssl rand -hex 16)
DATABASE_URL=postgres://cleanmails:${DB_PASSWORD}@postgres:5432/cleanmails?sslmode=disable
# Redis
REDIS_URL=redis://redis:6379
# Security (REQUIRED — auto-generated by installer)
ENCRYPTION_KEY=$(openssl rand -hex 32)
JWT_SECRET=$(openssl rand -hex 32)
# App
BASE_URL=https://app.yourdomain.com
API_PORT=8080
GIN_MODE=release
ALLOWED_ORIGINS=https://app.yourdomain.comRun openssl rand -hex 32 to generate the ENCRYPTION_KEY and JWT_SECRET. Never reuse keys across instances. The ENCRYPTION_KEY encrypts all sender passwords and integration tokens using AES-256-GCM.
4. Create docker-compose.prod.yml
Copy the production docker compose file from your download. It includes six services:
| Service | Purpose |
|---|---|
postgres | PostgreSQL 16 database |
redis | Redis 7 for task queue (Asynq) |
api | Go API server (Gin framework) |
worker | Background job processor |
frontend | Next.js React dashboard |
caddy | Reverse proxy + auto SSL |
5. Build Docker images
# Build the API server
docker build -t cleanmails-api:latest -f Dockerfile.api .
# Build the background worker
docker build -t cleanmails-worker:latest -f Dockerfile.worker .
# Build the frontend
docker build -t cleanmails-frontend:latest -f Dockerfile.frontend .6. Configure firewall
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 25/tcp
echo "y" | ufw enable7. Start the stack
docker compose -f docker-compose.prod.yml up -d8. Verify
# Check all containers are running
docker compose -f docker-compose.prod.yml ps
# Check health endpoint
curl http://localhost:8080/health
# Check logs
docker compose -f docker-compose.prod.yml logs -f apiSSL Configuration
The included Caddy container handles SSL automatically. Point your domain's A record to your server IP. The installer generates a Caddyfile that routes:
yourdomain.com {
handle /api/* {
reverse_proxy api:8080
}
handle /health {
reverse_proxy api:8080
}
handle /t/* {
reverse_proxy api:8080
}
handle /unsubscribe/* {
reverse_proxy api:8080
}
handle {
reverse_proxy frontend:3000
}
header {
X-Content-Type-Options nosniff
X-Frame-Options DENY
Strict-Transport-Security "max-age=31536000"
}
}Caddy will auto-provision a Let's Encrypt certificate on first request.
Updating
cd /opt/cleanmails
bash scripts/update.shThe update script downloads the latest release from S3, rebuilds all Docker images, and restarts the stack with zero downtime. You can also trigger updates from the admin panel (Settings → System → Check for Updates).