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

  1. Verify Haraka is running: docker compose logs haraka
  2. Test SMTP connectivity: telnet your-server-ip 25
  3. You should see a 220 ESMTP Haraka banner
  4. 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_sign plugin
    • DMARC: v=DMARC1; p=quarantine; rua=mailto:[email protected]

Configuration

Core Settings

FilePurpose
smtp.iniServer bind address, ports, public IP, cluster mode
pluginsList of enabled plugins (one per line)
host_listDomains accepted for inbound mail
smtp_forward.iniDownstream 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

CategoryPluginsPurpose
Authenticationauth_enc_file, auth_ldap, auth_proxyUser login for mail submission
DNS Validationspf, dkim_verify, dkim_sign, dmarc, fcrdnsSender verification
Anti-Spamdnsbl, rspamd, spamassassin, karmaSpam detection and scoring
AntivirusclamdClamAV integration
Rate LimitinglimitConnection and message rate limits (uses Redis)
Queuesmtp_forward, lmtp, rabbitmqMail 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 ServerIntegration Method
DovecotForward via LMTP (plugin: queue/lmtp)
WildDuckPlugin: haraka-plugin-wildduck
MailcowForward 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 certificates
  • redis_data volume — 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.

Comments