Production Deployment (Docker Compose)
Relevant source files
The following files were used as context for generating this wiki page:This document outlines the process for deploying the Email Platform to a production environment using the docker-compose.prod.yml file. This method provides a full-stack deployment, including the core application, databases, monitoring, and a reverse proxy with automated HTTPS certificate management via Let's Encrypt. The production setup is designed to be run on a VPS or cloud server with a dedicated public IP address.
The deployment is orchestrated through Docker Compose, which defines and runs a multi-container application. The production configuration includes services for web, API, database, caching, monitoring, and optional anti-abuse tools. An automated deployment script, scripts/deploy.sh, is also provided to streamline updates.
Sources: deployment_guide.md:1-3, docker-compose.prod.yml, README.md:29-33
Prerequisites
Before deploying, ensure the following requirements are met:
- Server: A VPS or cloud server (e.g., DigitalOcean, AWS EC2) with a public static IP. The recommended configuration is 2 vCPUs and 4GB RAM. Ubuntu 22.04 LTS is the recommended OS.
- Domain: A registered domain name (e.g.,
yourdomain.com). - DNS Management: Access to manage DNS records for your domain.
- Software: Docker and Docker Compose must be installed on the server.
Sources: deployment_guide.md:5-12
Production Architecture
The production environment is composed of several containerized services that are managed by Docker Compose. These services communicate over a shared bridge network named email_network.
Sources: docker-compose.prod.yml:171-173
Service Overview
The following diagram illustrates the services and their primary interactions within the production stack.
This diagram shows the flow of user traffic and email through the various services defined in the production Docker Compose file.
Sources: docker-compose.prod.yml, blueprint.md:95-106
Core Components
| Service | Image | Description |
|---|---|---|
caddy | caddy:2-alpine | A reverse proxy that provides automatic HTTPS for the web, api, prometheus, and grafana services using Let's Encrypt. |
postgres | postgres:16-alpine | The primary database for the application, storing user data, domains, inboxes, and message metadata. |
redis | redis:7-alpine | Used for caching and as a message broker for background jobs via BullMQ. |
api | Custom build | The backend service (Node.js/Fastify) that handles business logic, serves the REST API, and runs the inbound SMTP server on port 2525. |
web | Custom build | The frontend React application, served by Caddy. |
postfix | Custom build | An outbound SMTP relay server used by the API to send emails. It is configured with OpenDKIM for signing outgoing mail. |
dovecot | Custom build | An IMAP server allowing users to connect with standard email clients. It authenticates against the PostgreSQL database. |
Sources: docker-compose.prod.yml:13-109, README.md:29-33
Monitoring and Security
| Service | Image | Description |
|---|---|---|
prometheus | prom/prometheus:v2.45.0 | Scrapes metrics from the API's /metrics endpoint for monitoring application performance. |
grafana | grafana/grafana:10.0.3 | A visualization tool for Prometheus data. It is pre-configured with dashboards. |
clamav | clamav/clamav:latest | (Optional) An anti-virus engine to scan email attachments. It is commented out by default. |
rspamd | rspamd/rspamd:latest | (Optional) A spam filtering system. It is commented out by default. |
Sources: docker-compose.prod.yml:126-168, deployment_guide.md:166-184
Configuration
DNS Setup
Before deployment, you must configure DNS records to point your domain to the server's public IP.
| Type | Host | Value | Priority | Note |
|---|---|---|---|---|
| A | mail | <YOUR_SERVER_IP> | Points mail.yourdomain.com to your server. | |
| A | api | <YOUR_SERVER_IP> | Points api.yourdomain.com to your server. | |
| A | app | <YOUR_SERVER_IP> | Points app.yourdomain.com to the Web UI. | |
| MX | @ | mail.yourdomain.com | 10 | Directs email for your domain to your server. |
For improved email deliverability when sending outbound mail, SPF and DMARC records are also recommended.
Sources: deployment_guide.md:15-28
Environment Variables
Production deployment is configured via a .env file in the project's root directory. The docker-compose.prod.yml file uses these variables to configure the services.
| Variable | Description | Example |
|---|---|---|
DOMAIN | Your primary domain name for HTTPS. | yourdomain.com |
ACME_EMAIL | The email address for Let's Encrypt notifications. | admin@yourdomain.com |
POSTGRES_PASSWORD | A secure password for the PostgreSQL database. | $(openssl rand -base64 32) |
GRAFANA_PASSWORD | A secure password for the Grafana admin user. | $(openssl rand -base64 16) |
OUTBOUND_ENABLED | Set to true to enable outbound email features. | true |
OUTBOUND_SMTP_HOST | SMTP host for outbound relay (e.g., Amazon SES). | email-smtp.us-east-1.amazonaws.com |
OUTBOUND_SMTP_PORT | SMTP port for the outbound relay. | 587 |
OUTBOUND_SMTP_USER | Username for the SMTP relay service. | YOUR_SES_SMTP_USER |
OUTBOUND_SMTP_PASS | Password for the SMTP relay service. | YOUR_SES_SMTP_PASS |
OUTBOUND_SMTP_SECURE | Set to true if the relay uses TLS. | true |
Sources: deployment_guide.md:73-88, docker-compose.prod.yml:6-11
The API service also uses environment variables from services/api/.env, which can be generated using the scripts/generate_env.sh script. Key production settings for the API include:
ALLOW_AUTO_DOMAIN_CREATION="false": Disables automatic domain creation in production.TRUST_PROXY="true": Necessary for the API to correctly identify client IPs behind the Caddy reverse proxy.
Sources: docker-compose.prod.yml:69,72, deployment_guide.md:46-64
Deployment Process
The application is deployed using a single Docker Compose command. This command builds the custom images for api, web, postfix, and dovecot if they don't exist, and starts all defined services in detached mode.
docker-compose -f docker-compose.prod.yml up -d --build
Sources: deployment_guide.md:91-93
After the initial deployment, you should check the Caddy logs to ensure SSL certificates have been issued successfully and test the API's health endpoint.
# Check Caddy logs for SSL status
docker-compose -f docker-compose.prod.yml logs caddy
# Test API health
curl -I https://api.yourdomain.com/health
Sources: deployment_guide.md:96-100
Automated Updates
The project includes a deploy.sh script to automate the process of updating a running production instance.
# Grant execute permissions (one-time)
chmod +x scripts/deploy.sh
# Run the script to update the application
./scripts/deploy.sh
Sources: deployment_guide.md:204-210
The script performs the following actions:
- Pulls the latest code from the
mainbranch of the git repository. - Rebuilds and restarts all containers using
docker-compose.prod.yml. - Waits 10 seconds for services to stabilize.
- Runs database migrations using
prisma migrate deployinside theapicontainer. - Restarts the
apiservice to ensure it picks up any schema changes.
Sources: scripts/deploy.sh:8-28
The following sequence diagram illustrates the automated deployment flow.
Sources: scripts/deploy.sh
Post-Deployment
- Check Service Status: Ensure all containers are running with
docker-compose -f docker-compose.prod.yml ps. - Change Default Passwords: The default admin user is created on first boot. Log in and change the password immediately. If using Grafana, change its default password as well.
- Set up Backups: A backup script is provided at
scripts/backup.sh. It is recommended to configure a cron job to run this script periodically.
Sources: deployment_guide.md:133-138, 146-159