How to Self-Host Haraka with Docker Compose
What Is Haraka?
Haraka is a high-performance, open-source SMTP server built on Node.js. It handles thousands of concurrent SMTP connections using an asynchronous, event-driven architecture with a powerful plugin system of 60+ plugins for spam filtering, DKIM signing, SPF/DMARC validation, and more. Haraka functions as an MTA (Mail Transfer Agent) for inbound mail or an MSA (Mail Submission Agent) on port 587 — it is not a complete email solution with mailboxes. Pair it with Dovecot or WildDuck for IMAP/POP3 access. Official site.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 500 MB of free disk space
- 512 MB of RAM minimum
- A domain name with properly configured MX, SPF, DKIM, and DMARC DNS records
- Port 25 open (many hosting providers block this by default — check with your provider)
Docker Compose Configuration
Create a directory for Haraka and the configuration files:
mkdir -p ~/haraka/config && cd ~/haraka
Create docker-compose.yml:
services:
haraka:
image: instrumentisto/haraka:3.1.3
container_name: haraka
ports:
- "25:25"
- "587:587"
volumes:
- ./config/smtp.ini:/etc/haraka/config/smtp.ini:ro
- ./config/plugins:/etc/haraka/config/plugins:ro
- ./config/host_list:/etc/haraka/config/host_list:ro
- ./config/smtp_forward.ini:/etc/haraka/config/smtp_forward.ini:ro
- ./config/tls:/etc/haraka/config/tls:ro
environment:
- HARAKA_INSTALL_PLUGINS=
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: haraka-redis
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
redis_data:
Create config/smtp.ini:
[main]
; Bind to all interfaces on ports 25 and 587
listen=[::0]:25,[::0]:587
; Your server's public IP
public_ip=YOUR_SERVER_PUBLIC_IP
; Drop privileges after binding ports
user=nobody
group=nogroup
; Connection timeouts
inactivity_timeout=300
; Cluster mode (one worker per CPU core)
nodes=cpus
Create config/plugins (list of enabled plugins):
# DNS validation
mail_from.is_resolvable
rcpt_to.in_host_list
# Queue - forward to downstream SMTP
queue/smtp_forward
Create config/host_list (domains you accept mail for):
yourdomain.com
Create config/smtp_forward.ini (forward to your IMAP server):
[main]
host=your-imap-server
port=25
enable_tls=true
Start the stack:
docker compose up -d
Initial Setup
- Verify Haraka is running:
docker compose logs haraka - Test SMTP connectivity:
telnet your-server-ip 25 - You should see a
220 ESMTP Harakabanner - Configure your DNS records:
- MX record: Point to your server’s hostname
- SPF record:
v=spf1 ip4:YOUR_SERVER_IP ~all - DKIM: Generate keys and configure the
dkim_signplugin - DMARC:
v=DMARC1; p=quarantine; rua=mailto:[email protected]
Configuration
Core Settings
| File | Purpose |
|---|---|
smtp.ini | Server bind address, ports, public IP, cluster mode |
plugins | List of enabled plugins (one per line) |
host_list | Domains accepted for inbound mail |
smtp_forward.ini | Downstream SMTP server for mail delivery |
tls/ | TLS certificate and key files |
Essential Plugins
Enable these in config/plugins for a production setup:
# Authentication
auth/auth_enc_file
# DNS validation
spf
dkim_verify
dkim_sign
dmarc
# Spam filtering
dnsbl
mail_from.is_resolvable
rcpt_to.in_host_list
# Rate limiting (requires Redis)
limit
# Antivirus (requires ClamAV)
# clamd
# Spam scoring (requires Rspamd)
# rspamd
# Queue
queue/smtp_forward
Plugin Categories
| Category | Plugins | Purpose |
|---|---|---|
| Authentication | auth_enc_file, auth_ldap, auth_proxy | User login for mail submission |
| DNS Validation | spf, dkim_verify, dkim_sign, dmarc, fcrdns | Sender verification |
| Anti-Spam | dnsbl, rspamd, spamassassin, karma | Spam detection and scoring |
| Antivirus | clamd | ClamAV integration |
| Rate Limiting | limit | Connection and message rate limits (uses Redis) |
| Queue | smtp_forward, lmtp, rabbitmq | Mail delivery to downstream servers |
TLS Configuration
Create TLS certificate files in config/tls/:
mkdir -p config/tls
# Copy your certificate and key
cp /path/to/cert.pem config/tls/tls_cert.pem
cp /path/to/key.pem config/tls/tls_key.pem
Create config/tls.ini:
[main]
key=tls/tls_key.pem
cert=tls/tls_cert.pem
Pairing with an IMAP Server
Haraka handles SMTP only — you need a separate IMAP/POP3 server for mailbox access. Common pairings:
| IMAP Server | Integration Method |
|---|---|
| Dovecot | Forward via LMTP (plugin: queue/lmtp) |
| WildDuck | Plugin: haraka-plugin-wildduck |
| Mailcow | Forward via SMTP to Mailcow’s Postfix |
For a complete self-hosted email stack, see Best Self-Hosted Email Servers.
Reverse Proxy
SMTP does not typically use HTTP reverse proxies. Expose ports 25 and 587 directly. If you need a mail proxy, use HAProxy with TCP mode.
Backup
Back up these files:
config/directory — all configuration files and TLS certificatesredis_datavolume — rate limiting and greylisting state (if using Redis plugins)
Haraka itself is stateless — it forwards mail to a downstream server. Back up your IMAP server’s storage separately.
See Backup Strategy for automated approaches.
Troubleshooting
Port 25 Blocked by Hosting Provider
Symptom: Cannot receive inbound mail; connections to port 25 time out. Fix: Most cloud providers (AWS, GCP, Azure, many VPS providers) block outbound port 25 by default. Contact your provider to request unblocking. Hetzner typically allows it after account verification.
Mail Rejected as Spam by Recipients
Symptom: Outbound mail bounces or lands in spam folders.
Fix: Verify DNS records: SPF, DKIM, DMARC, and PTR (reverse DNS). Use mail-tester.com to score your setup. Enable dkim_sign plugin and generate proper DKIM keys. Set a PTR record matching your server’s hostname.
Authentication Failures on Port 587
Symptom: Email clients cannot authenticate for sending.
Fix: Ensure an auth plugin is enabled (e.g., auth/auth_enc_file). Create the password file with hashed credentials. Verify TLS is working — most auth plugins require TLS/STARTTLS before accepting credentials.
High Connection Count / DDoS
Symptom: Server becomes unresponsive under high connection load.
Fix: Enable the limit plugin with Redis to rate-limit connections per IP. Configure max_unrecognized_commands in smtp.ini to quickly disconnect malicious clients.
Resource Requirements
- RAM: ~100 MB idle, ~300 MB under load with plugins
- CPU: Low-Medium — Node.js handles connections asynchronously
- Disk: Minimal — Haraka is stateless; mail is forwarded, not stored
Verdict
Haraka excels at one thing: processing SMTP at scale with a flexible plugin system. If you need a high-performance MTA that can handle thousands of concurrent connections with custom filtering logic, Haraka is a strong choice. It’s particularly well-suited as the inbound SMTP layer in a larger mail stack (paired with Dovecot or WildDuck for mailboxes). For a complete, turnkey email solution, Mailcow or Mailu are better choices — they bundle SMTP, IMAP, webmail, and admin UI in a single stack. Haraka is for users who want granular control over their SMTP pipeline.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments