How to Self-Host Stalwart Mail Server

What Is Stalwart?

Stalwart is a modern, all-in-one mail server written in Rust. It supports JMAP, IMAP, POP3, and SMTP in a single binary with a built-in web admin UI, spam filtering, full-text search, and encryption at rest. Unlike Mailu or Mailcow, Stalwart needs no external database, no Redis, and no separate components — everything runs in one container with embedded RocksDB storage. It also includes CalDAV and CardDAV support. Official site.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 1 GB of RAM minimum (2 GB recommended)
  • 10 GB of free disk space
  • A domain name with DNS access
  • Port 25 open and not blocked by your hosting provider
  • A reverse DNS (PTR) record set to your mail hostname

Docker Compose Configuration

Create a docker-compose.yml file:

services:
  stalwart:
    image: stalwartlabs/stalwart:v0.15.5
    container_name: stalwart
    ports:
      - "25:25"       # SMTP (inbound mail)
      - "465:465"     # SMTPS (implicit TLS submission)
      - "587:587"     # SMTP Submission (STARTTLS)
      - "143:143"     # IMAP
      - "993:993"     # IMAPS (implicit TLS)
      - "4190:4190"   # ManageSieve
      - "443:443"     # HTTPS (JMAP, web client, REST API)
      - "8080:8080"   # Web Admin UI (HTTP)
    volumes:
      - stalwart-data:/opt/stalwart
    restart: unless-stopped

volumes:
  stalwart-data:

That’s the entire stack. No PostgreSQL, no Redis, no separate services. Start it:

docker compose up -d

Initial Setup

1. Retrieve Admin Credentials

Stalwart generates admin credentials on first start. Get them from the logs:

docker logs stalwart

Look for a line showing the admin username and password.

2. Access the Web Admin

Open http://your-server-ip:8080/login in your browser. Log in with the admin credentials from step 1.

3. Configure Your Hostname

In the web admin, go to Settings > Server > Network and set your mail hostname (e.g., mail.example.com).

4. Add Your Domain

Go to Management > Directory > Domains and add your domain (e.g., example.com).

5. Configure TLS

Under Settings > TLS, either:

  • Upload your TLS certificate and private key, or
  • Enable ACME (Let’s Encrypt) for automatic certificate provisioning

6. Create User Accounts

Go to Management > Directory > Accounts and create your email accounts.

7. Configure DNS Records

Set up these DNS records:

TypeNameValue
MXexample.commail.example.com (priority 10)
Amail.example.comYour server’s public IP
PTR(reverse DNS)mail.example.com
TXT (SPF)example.comv=spf1 mx ~all
TXT (DKIM)Generated in admin UICopy from Stalwart’s DKIM settings
TXT (DMARC)_dmarc.example.comv=DMARC1; p=none; rua=mailto:[email protected]

Stalwart can generate DKIM keys automatically through the web admin.

Configuration

All configuration happens through the web admin UI or via TOML configuration files stored in the /opt/stalwart volume.

Spam Filtering

Stalwart includes a built-in spam filter with:

  • Statistical spam classifier (Bayesian)
  • DNS blocklists (DNSBL)
  • Phishing detection
  • Greylisting
  • Sender reputation tracking
  • Spam traps

Configure spam settings under Settings > Spam Filter in the admin UI.

Built-in full-text search supports 17 languages out of the box using an embedded search engine. No Elasticsearch or external search service needed.

Authentication Providers

Stalwart supports multiple authentication backends:

  • Internal directory (default — stored in RocksDB)
  • LDAP
  • SQL databases (PostgreSQL, MySQL, SQLite)
  • OAuth2

Configure under Settings > Authentication in the admin UI.

Advanced Configuration (Optional)

External Database Backend

For large deployments, you can replace RocksDB with an external database:

# In the TOML config at /opt/stalwart/etc/config.toml
[store."postgresql"]
type = "postgresql"
host = "db.example.com"
port = 5432
database = "stalwart"
user = "stalwart"
password = "your-password"

Supported backends: PostgreSQL, MySQL, SQLite, FoundationDB, S3, Azure Blob Storage, Redis.

Clustering

Stalwart supports clustering for high availability via peer-to-peer coordination or through Kafka, Redpanda, NATS, or Redis. Configure under Settings > Cluster in the admin UI.

CalDAV and CardDAV

Stalwart includes built-in CalDAV (calendar) and CardDAV (contacts) support. No additional configuration needed — these are available on the HTTPS port (443) after TLS is configured.

Reverse Proxy

If you’re running Stalwart behind an existing reverse proxy, expose only the web admin and JMAP ports through the proxy. Email protocols (SMTP, IMAP) should connect directly to Stalwart:

ports:
  - "25:25"       # Direct — SMTP
  - "465:465"     # Direct — SMTPS
  - "587:587"     # Direct — Submission
  - "993:993"     # Direct — IMAPS
  - "127.0.0.1:8080:8080"  # Through reverse proxy — Web Admin

Then proxy https://mail.example.com to http://localhost:8080 in your reverse proxy (Reverse Proxy Setup).

Backup

All data lives in a single volume:

# Back up the entire Stalwart data directory
docker run --rm -v stalwart-data:/data -v $(pwd):/backup alpine \
  tar czf /backup/stalwart-backup-$(date +%Y%m%d).tar.gz /data

This includes configuration, the RocksDB database, mail blobs, full-text search indexes, TLS certificates, and Sieve scripts. See Backup Strategy.

Troubleshooting

Admin Password Lost

Symptom: Can’t log into the web admin. Fix: Reset the admin password via the CLI:

docker exec -ti stalwart /opt/stalwart/bin/stalwart-cli -u https://localhost:443 server admin-password reset

Emails Going to Spam

Symptom: Outbound emails land in spam folders. Fix: Verify DNS records (SPF, DKIM, DMARC, PTR) are all correctly configured. Use mail-tester.com to check your score. The PTR (reverse DNS) record is the most commonly forgotten.

Port 25 Blocked

Symptom: Cannot receive email from external servers. Fix: Contact your VPS provider to unblock port 25. Many cloud providers (AWS, GCP, Azure) block it by default. Hetzner and OVH typically allow it.

JMAP Client Not Connecting

Symptom: JMAP email clients can’t connect. Fix: JMAP runs over HTTPS on port 443. Ensure TLS is properly configured in the admin UI. The JMAP endpoint is at https://mail.example.com/jmap.

Upgrade from v0.14.x to v0.15.x

Symptom: Server fails to start after upgrading. Fix: v0.15.x includes breaking changes. Check the migration guide before upgrading. Back up your data volume first.

Resource Requirements

  • RAM: 512 MB idle, 1-2 GB under load
  • CPU: Low — Rust is extremely efficient
  • Disk: 2 GB for the application, plus mail storage

Stalwart is the lightest full-featured mail server available. It uses a fraction of the resources that Mailcow or Mailu require.

Verdict

Stalwart is the most modern and resource-efficient self-hosted mail server available. The single-binary Rust architecture means no juggling PostgreSQL, Redis, and multiple containers — everything runs in one container with one volume. The built-in web admin, JMAP support, CalDAV/CardDAV, and spam filtering make it genuinely competitive with commercial solutions.

Choose Stalwart if you want a modern mail server that’s easy to deploy and light on resources. Choose Mailcow if you want a more established solution with a larger community. Choose docker-mailserver if you prefer CLI-only management without a web UI.

Fair warning: Stalwart is newer than Mailu and Mailcow, so the community is smaller and you’ll find fewer guides online. But development is very active and the architecture is sound.