Streaming & Messaging Azure

Stalwart Mail Server on Ubuntu 24.04 on Azure User Guide

| Product: Stalwart Mail Server on Ubuntu 24.04 LTS on Azure

Overview

Stalwart is the all in one open source mail and collaboration server. A single memory safe Rust binary speaks SMTP, IMAP, JMAP and POP3, runs a built in spam and phishing filter, signs outgoing mail with DKIM and verifies SPF, DMARC and ARC on inbound mail, runs Sieve server side filtering scripts, and serves a web administration console for managing domains, accounts and queues. Because Stalwart keeps its settings, accounts and message store in an embedded RocksDB datastore, there is no separate database to run and far fewer daemons to patch than the traditional Postfix, Dovecot, SpamAssassin and OpenDKIM stack.

The cloudimg image ships Stalwart fully installed with its web admin console fronted by nginx, so a complete private mail platform is running within minutes of launch. On the first boot of every VM a one shot service provisions the server, generates a unique administrator password, regenerates the TLS private key, and writes the login to a root only file. The RocksDB datastore lives on a dedicated Azure data disk mounted at /opt/stalwart/data, kept separate from the operating system disk.

What is included:

  • Stalwart 0.16.8 installed from the official prebuilt Linux binary at /opt/stalwart/bin/stalwart, run as the stalwart system service
  • The embedded RocksDB datastore (no external database required) on a dedicated Azure data disk at /opt/stalwart/data
  • The web admin console and JMAP interface served on port 80 through nginx (the Stalwart HTTP listener is bound to the loopback address 127.0.0.1:8080)
  • HTTPS 443 served natively by Stalwart, with mail listeners on SMTP 25, submission over STARTTLS 587, submission over TLS 465 and IMAP over TLS 993
  • A per instance self signed TLS certificate for the mail listeners, generated on first boot
  • A unique administrator account generated on first boot, recorded in a root only 0600 file, with no default or shared credential in the image
  • stalwart.service and nginx.service as systemd units, enabled and active
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a reasonable starting point for a small mailbox count; size up for busier mail. NSG inbound rules: allow 22/tcp from your management network for SSH, 80/tcp and 443/tcp for the web admin and HTTPS, 25/tcp for inbound mail, 465/tcp and 587/tcp for mail submission, and 993/tcp for IMAP.

Receiving mail on a real domain also needs public DNS records (MX, SPF, DKIM and DMARC) that point at your VM. Stalwart generates the exact records for you in the admin console, as shown later in this guide.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Stalwart by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). After creation, add inbound rules for 443, 25, 465, 587 and 993. Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name stalwart \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

Then open the mail and web ports in the network security group:

az network nsg rule create --resource-group <your-rg> --nsg-name <your-nsg> \
  --name allow-mail --priority 1010 --access Allow --protocol Tcp --direction Inbound \
  --destination-port-ranges 80 443 25 465 587 993

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Stalwart and nginx are already installed and running. The first boot provisioning has generated your unique administrator login.

Step 4 - Confirm the services are running

systemctl is-active stalwart.service nginx.service
sudo ss -tlnp | grep -E ':25|:465|:587|:993|:443|:8080|:80'

Both services report active. nginx listens on port 80 and fronts the web admin, while the Stalwart HTTP listener is bound only to the loopback address 127.0.0.1:8080. The mail listeners are bound on SMTP 25, submission 465 and 587, and IMAP over TLS 993, with HTTPS on 443 served natively by Stalwart.

stalwart.service and nginx.service both active, with the SMTP 25, submission 465 and 587, IMAP 993 and HTTPS 443 mail listeners bound and the Stalwart HTTP listener on loopback 127.0.0.1:8080 behind nginx on port 80

Step 5 - Retrieve your admin login

The administrator password is generated uniquely on the first boot of your VM and written to a root only file:

sudo cat /root/stalwart-credentials.txt

This file contains stalwart.admin.user (the administrator account, admin@example.org), stalwart.admin.pass and the web admin URL. The file is mode 0600 and owned by root, so only an administrator can read it. Store the password somewhere safe. The binary reports version 0.16.8, and the RocksDB datastore that holds your mail lives on the dedicated Azure data disk mounted at /opt/stalwart/data.

The Stalwart binary reporting version 0.16.8, the RocksDB datastore on the dedicated Azure data disk at /opt/stalwart/data, and the root only 0600 credentials file with the per VM admin account and password redacted

Step 6 - Confirm the health endpoint and web admin

nginx serves an unauthenticated health endpoint for load balancers and probes, and serves the web admin single page application on port 80:

curl -s -o /dev/null -w 'healthz -> HTTP %{http_code}\n' http://localhost/healthz/live
curl -s -o /dev/null -w 'admin   -> HTTP %{http_code}\n' http://localhost/admin/

/healthz/live returns HTTP 200 without authentication, so it is safe for an Azure Load Balancer health probe. The web admin at /admin/ also returns HTTP 200 and loads the console in the browser, where you sign in.

The Stalwart health endpoint returning HTTP 200 through nginx on port 80 and the web admin single page application also served with HTTP 200 on port 80

Step 7 - Verify authentication from the command line

Stalwart's JMAP session endpoint authenticates the administrator account. The check below reads your per VM password from the credentials file so it is never printed, authenticates against /jmap/session (HTTP 200), and confirms a wrong password is rejected (HTTP 401):

PASS=$(sudo grep '^stalwart.admin.pass=' /root/stalwart-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'correct password -> HTTP %{http_code}\n' -u "admin@example.org:$PASS" http://localhost/jmap/session
curl -s -o /dev/null -w 'wrong password   -> HTTP %{http_code}\n' -u 'admin@example.org:definitely-wrong-pass' http://localhost/jmap/session

The correct per VM password prints HTTP 200 (authenticated); a wrong password prints HTTP 401 (rejected), which confirms the temporary provisioning back door has been removed.

The admin authentication round trip against the Stalwart JMAP session endpoint: the correct per VM password returns HTTP 200 and a wrong password is rejected with HTTP 401

Step 8 - Sign in to the web admin

Browse to http://<vm-public-ip>/ in your browser. Enter your administrator account name admin@example.org and continue, then enter the password from Step 5 on the sign in page and select Sign in. You land on the Stalwart admin console, where you manage domains, accounts, queues, reports and server settings.

The Stalwart web admin sign in page served on first boot, showing the Stalwart logo and the username and password fields with the Sign in button

Step 9 - Review your accounts and mailboxes

Open Directory then Accounts to see the mailboxes on your server. The provisioning creates the single administrator account admin@example.org. From here you create user accounts and mailboxes, groups, mailing lists and roles. Each account is a mailbox any IMAP or JMAP client can sign in to.

The Directory Accounts view in the Stalwart web admin, listing the per instance administrator account admin@example.org with the option to create user accounts and mailboxes

Step 10 - Add your real domain

The image is provisioned with the temporary domain example.org so the server is complete on first boot. To serve mail for your own domain, open Domains then Domains and create your real domain (for example mail.yourcompany.com). Stalwart generates the DKIM keys for the new domain automatically and manages its DNS, DKIM and TLS certificate settings from this view.

The Domains management view in the Stalwart web admin, listing the domain with its Enabled state and its certificate and DNS management settings

Step 11 - Publish your DNS records

Open the domain's actions menu and choose View Zone File to see the exact DNS records to publish at your DNS provider. Stalwart shows the DKIM public keys (both ed25519 and RSA), the SPF record, the MX record, the DMARC policy and the service SRV records. Publish these at your DNS host so other mail servers can verify and deliver to you, and so your outgoing mail is DKIM signed and SPF and DMARC aligned.

The DNS Zone File view for a domain in the Stalwart web admin, showing the generated DKIM ed25519 and RSA public keys, the SPF record, the MX record, the DMARC policy and the SRV records to publish in DNS

Step 12 - Create mailboxes and connect a mail client

Under Directory then Accounts, create a mailbox for each user on your domain and set a password. Then connect any standards compliant mail client (for example Thunderbird, Apple Mail or a JMAP client) using your VM's public IP or hostname:

  • IMAP over TLS on port 993
  • Submission over STARTTLS on port 587, or submission over implicit TLS on port 465
  • JMAP over HTTPS on port 443

The client signs in with the mailbox address and password you set. Because the appliance ships a self signed certificate until you install a trusted one (Step 13), your client may prompt to trust the certificate on first connection.

Step 13 - Set your hostname and enable Let's Encrypt TLS

For production, set your server hostname and replace the self signed certificate with a trusted one. In the admin console, set the server hostname to a name that resolves to your VM, then enable Stalwart's built in ACME support so it obtains and renews a Let's Encrypt certificate automatically. Point a DNS A record at your VM's public IP first, so the ACME HTTP challenge on port 80 can validate. Once ACME is enabled, HTTPS on 443 and the mail listeners on 465, 587 and 993 present the trusted certificate.

Step 14 - Sending mail: outbound port 25 on Azure

Important: Azure blocks OUTBOUND port 25 by default for most subscriptions. Receiving mail and IMAP access work out of the box, but direct outbound delivery to other mail servers on port 25 will not, until you either:

  • request an outbound port 25 exception from Azure for your subscription, or
  • relay outbound mail through a smart host on port 587, such as SendGrid or Amazon SES.

To relay through a smart host, add an outbound relay host in the Stalwart admin console pointing at your provider's submission endpoint on port 587 with your provider credentials. cloudimg support can walk you through either option. Inbound mail, IMAP and JMAP are unaffected.

Step 15 - Confirm data lives on the dedicated disk

Stalwart's RocksDB datastore, which holds your mailboxes, message blobs, accounts, DKIM keys and full text index, is stored under /opt/stalwart/data on the dedicated Azure data disk, so it survives OS changes and can be resized independently:

findmnt /opt/stalwart/data

The mount is backed by a separate Azure data disk captured into the image and re-provisioned on every VM.

Maintenance

  • Password: the admin password is set on first boot. Change it in the web admin under Directory then Accounts, or by editing the administrator account.
  • Spam and phishing filter: the built in filter is enabled by default. Tune its rules and thresholds in the admin console under the settings for spam filtering.
  • Sieve filtering: create server side Sieve scripts for mailbox rules (sorting, forwarding, vacation replies) from the admin console.
  • TLS and certificates: the appliance generates a self signed certificate per instance. For production, set a real hostname and enable Let's Encrypt ACME (Step 13) so the mail and HTTPS listeners present a trusted certificate.
  • DKIM, SPF, DMARC and ARC: Stalwart signs outgoing mail with DKIM and verifies SPF, DMARC and ARC on inbound mail. Publish the DNS records from Step 11 so remote servers trust your mail and your domain is aligned.
  • Queues and reports: monitor the mail queue and delivery reports from the admin console under Emails and Reports.
  • Upgrades: the binary lives at /opt/stalwart/bin/stalwart; replace it with a newer release and restart stalwart.service. Your data under /opt/stalwart/data is preserved.
  • Storage and backups: all Stalwart state lives under /opt/stalwart/data on the data disk; snapshot or back up that volume to protect your mailboxes, message store and DKIM keys.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.