Why Stalwart for a multi-domain client fleet
Managing email for multiple clients runs into the same obstacle: every popular solution forces either a separate instance per domain or a shared setup with only partial isolation. Stalwart was built from the ground up for multi-tenancy: a domain is a first-class object in its data model, not a configuration variant. Adding a client means creating a domain through the API or the web interface — no binary swap, no container restart, no risk of data bleed between clients.
For an agency managing 5 to 50 clients, this is the difference between infrastructure that grows linearly (one extra instance per client) and infrastructure that scales flat — one VPS, one instance, N clients.
What Stalwart brings in practice
- Single binary, no Docker required — one statically compiled Go file, no system dependencies, deployable directly on any Linux distribution.
- Native multi-tenancy — domains, mailboxes, aliases and quotas managed as objects, with strict data isolation between clients.
- JMAP (RFC 8620) as a first-class protocol — the modern email synchronisation protocol, alongside classic IMAP4 and POP3.
- Built-in WebAdmin — HTTPS administration interface on port 8080, no third-party tool to deploy.
- JMAP API for automation — scriptable domain and account creation, suited to agency client onboarding workflows.
- Native ACME/Let's Encrypt support — automatic TLS renewal without Certbot or a mandatory reverse proxy.
- AGPL-3.0 licence — verifiable source code, no proprietary dependency for the community edition.
Prerequisites before installation
Stalwart is significantly lighter than Mailcow. For light usage (1 to 5 domains, a few dozen mailboxes), plan for 1 vCPU and 1 GB of RAM. For a fleet of several dozen active client domains, 2 vCPU and 2 GB of RAM is the recommended configuration — the figure cited in the official documentation for multi-domain use.
On the network side, four inbound ports must be open: 25 (SMTP, MX reception), 465 (SMTPS/submission), 993 (IMAPS) and 443 (HTTPS — WebAdmin and JMAP). Port 4190 is needed for Sieve (server-side filters). Your VPS must have a dedicated IPv4 and a configured rDNS pointing to the server hostname — essential for deliverability. Finally, a domain name with DNS zone access is required to set MX, SPF, DKIM and DMARC records.
Installing Stalwart Mail Server
Download the binary
Connect to your VPS via SSH. Download the latest stable release from the official repository:
curl -fsSL https://github.com/stalwartlabs/stalwart/releases/latest/download/stalwart-linux-x86_64.tar.gz | tar -xz -C /usr/local/bin/
chmod +x /usr/local/bin/stalwartFor an ARM server (Ampere, AWS Graviton), replace x86_64 with aarch64.
Run the installation wizard
Stalwart includes an interactive wizard that configures data directories, generates initial TLS certificates and creates the first admin account:
sudo stalwart --initThe wizard asks for the server hostname (e.g. mail.your-domain.com), the data path (default /opt/stalwart-mail), TLS mode (ACME recommended) and the admin password. After init, configuration files are placed in /opt/stalwart-mail/etc/.
Create the systemd unit
To make Stalwart start automatically, create the service unit:
sudo tee /etc/systemd/system/stalwart-mail.service << 'EOF'
[Unit]
Description=Stalwart Mail Server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/stalwart --config /opt/stalwart-mail/etc/config.toml
Restart=on-failure
User=stalwart
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload && sudo systemctl enable --now stalwart-mailCreate the dedicated user first: sudo useradd -r -s /bin/false stalwart && sudo chown -R stalwart /opt/stalwart-mail.
Open ports in the firewall
On Ubuntu/Debian with UFW:
sudo ufw allow 25/tcp comment 'SMTP'
sudo ufw allow 465/tcp comment 'SMTPS'
sudo ufw allow 993/tcp comment 'IMAPS'
sudo ufw allow 443/tcp comment 'HTTPS WebAdmin/JMAP'
sudo ufw allow 4190/tcp comment 'Sieve'
sudo ufw reloadIf your VPS is behind a cloud firewall (Hetzner, OVH…), replicate these rules in the control panel.
Add the first domain via WebAdmin
Open https://mail.your-domain.com:8080 in your browser and log in with the admin account created in step 2. Under Management → Domains, click Add Domain, enter your-domain.com and confirm. Stalwart automatically generates the DNS records to set (MX, SPF, DKIM, DMARC) and displays them in the interface — copy them into your DNS zone.
Create mailboxes and verify
Under Management → Accounts, create a user account and assign it to the domain you added. Test reception with:
swaks --to [email protected] --server mail.your-domain.com --port 25Then test IMAP connectivity from Thunderbird or any mail client — server mail.your-domain.com, port 993, SSL/TLS. For an additional client, repeat step 5 with a new domain: no service restart is needed.
Post-installation configuration
Reverse proxy. If you want to route WebAdmin and JMAP through Nginx (to share port 443 with other services), configure a stream block for mail protocols (25, 465, 993) and an HTTPS server block for /jmap and WebAdmin. Stalwart also accepts direct connections without a proxy — the choice depends on your architecture.
Backup. Stalwart data lives in /opt/stalwart-mail/data/. A daily snapshot of that directory — compressed and transferred off-site — is sufficient for a full restore. With the {{vps.power.name}} plan from ServOrbit, weekly backups are included; enable daily backups for an RPO suited to email workloads.
Additional domains. Each client domain is added through the WebAdmin or the JMAP API. The stalwart binary also exposes a CLI subcommand for batch operations — useful for automated onboarding of new clients.
Hardening: restrict WebAdmin access
WebAdmin listens on 0.0.0.0:8080 by default. In production, restrict access to your admin IPs:
sudo ufw deny 8080
sudo ufw allow from <your-admin-ip> to any port 8080Also enable two-factor authentication (TOTP) for the admin account under Security → Authentication in WebAdmin. For remote access over an untrusted network, prefer an SSH tunnel rather than exposing port 8080 directly.
Troubleshooting common errors
Literal exceeds the maximum request size of X bytes (IMAP). This message appears when Thunderbird or an IMAP client attempts to upload a large attachment via the APPEND command. Stalwart drops the connection, then the client parses the remaining data stream as IMAP commands. Raise the limit in /opt/stalwart-mail/etc/config.toml at the imap.request.max-size key and restart the service.
DKIM record rejected by registrar. If your DNS provider (Vultr, some registrars) fails to create the DKIM RSA key because it exceeds 255 characters, split it into two quoted segments in the TXT value: "v=DKIM1; k=rsa; p=MIIBIj..." "AQAB...". Stalwart concatenates them on read.
Punycode domain rejected at creation. Versions before v0.16 rejected internationalised domains already encoded as A-labels (e.g. xn--mysite-o2a.com). Enter the domain in Unicode (mysité.com) and let Stalwart handle the conversion.
Service fails to start after upgrade. Check that your configuration file is compatible with the new version: stalwart --check-config /opt/stalwart-mail/etc/config.toml. Configuration schema migrations are documented in the release notes on GitHub.
IMAP connections refused from a mobile client. Verify that the TLS certificate is valid and not expired (openssl s_client -connect mail.your-domain.com:993) and that port 993 is open in both UFW and the VPS network firewall.
Going further
Stalwart covers mail infrastructure — reception, sending and storage. For your emails to land in the inbox rather than spam, SPF, DKIM and DMARC records must be correctly set and tested: see our guide on professional email deliverability.
If your cPanel fleet sends transactional email (order confirmations, alerts) and you want to centralise outbound without moving mailboxes, the Postfix SMTP relay guide covers that complementary architecture. For agencies migrating a client portfolio from Google Workspace or Microsoft 365 to self-hosted servers, the Mailcow article details IMAP migration steps.