Maddy Mail Server on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Maddy Mail Server on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Maddy is a composable, all in one mail server that replaces the traditional stack of separate SMTP, submission, IMAP and authentication daemons with a single self contained Go binary. It is a Mail Transfer Agent, a Mail Submission Agent, an IMAP server and a local authentication and DKIM engine in one process, configured entirely from one plain text file.
The image installs Maddy 0.9.5 from the official prebuilt release tarball, run under systemd as an unprivileged maddy user with just the CAP_NET_BIND_SERVICE capability so it can bind the standard privileged mail ports. Maddy accepts inbound mail as an MX on port 25, offers authenticated message submission over implicit TLS on port 465 and STARTTLS on port 587, and serves mailboxes over IMAP with implicit TLS on port 993 and STARTTLS on port 143. There is no web interface: the configuration (/etc/maddy/maddy.conf) plus the maddy command line are the whole management surface. Mail and hashed credentials are stored in an embedded database on a dedicated data disk.
Secure by default — no shared credentials. The image ships with no mailbox and no password of any kind. On the first boot of every VM a one shot service generates a fresh per instance self signed TLS certificate, sets the server hostname and primary domain to this instance, and creates a single administrator mailbox with a strong random password written to a root only file. Submission and IMAP both require authentication, an unauthenticated submission is rejected, and the server is configured as an MX for your own domains rather than an open relay.
What is included:
-
Maddy 0.9.5 from the official prebuilt release binary, run under systemd as the unprivileged
maddyuser (maddy.service) -
An SMTP MTA on port 25, authenticated submission on ports 465 (implicit TLS) and 587 (STARTTLS), and IMAP on ports 993 (implicit TLS) and 143 (STARTTLS)
-
A single administrator mailbox and a strong random password generated on first boot and stored in
/root/maddy-credentials.txt(mode0600), so no credential ships in the image -
A per instance self signed TLS certificate generated on first boot, ready to be replaced with a certificate for your real domain
-
Mail and hashed credentials stored in an embedded SQLite database on a dedicated data disk at
/var/lib/maddy, cleanly separated from the operating system disk -
The whole configuration in one readable file,
/etc/maddy/maddy.conf, and mailbox management with the simplemaddycommand line
Prerequisites
-
Active Azure subscription, SSH public key, VNet + subnet in target region
-
Subscription to the Maddy Mail Server listing on Azure Marketplace
-
Network Security Group rules allowing TCP 22 (admin), TCP 25 (inbound mail if you receive mail for your domain), and TCP 465, 587, 993 and 143 (submission and IMAP for your mail clients)
-
A domain you control, with the ability to publish MX, SPF, DKIM, DMARC and reverse DNS records, for a production mail server
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for a small mailbox server. Increase the size for higher mailbox counts or message throughput.
Step 1: Deploy from the Azure Portal
Search Maddy Mail Server in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow TCP 22 for administration, TCP 465, 587, 993 and 143 for submission and IMAP from your mail clients, and TCP 25 if this server will receive mail for your domain. Give the VM a public IP if it needs to send or receive mail from the internet.
Step 2: Deploy from the Azure CLI
RG="mail-prod"; LOCATION="eastus"; VM_NAME="maddy1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/maddy-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 465 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 993 --priority 1002
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1003
Open ports 587, 143 and 25 as well if your clients or senders need them.
Step 3: First boot and the admin mailbox
On first boot the image sets the server hostname and primary domain to this VM's hostname, generates a per instance self signed TLS certificate, creates the administrator mailbox admin@<hostname> with a strong random password, writes the credentials to /root/maddy-credentials.txt, and starts maddy. This completes within seconds. SSH in as azureuser and read the credentials:
sudo cat /root/maddy-credentials.txt
The file is 0600 root:root and holds the admin mailbox address, the per instance password, the primary domain, and the submission and IMAP endpoints. This is the only place the password exists, so store it somewhere safe.

Step 4: Confirm the service is running
maddy.service is active, maddy version reports 0.9.5, and ss confirms it is listening on the mail ports: 25 for SMTP, 465 and 587 for submission, and 993 and 143 for IMAP.
systemctl is-active maddy.service
maddy version
sudo ss -tlnp | grep -E ':25 |:465 |:587 |:993 |:143 '

Step 5: Send and receive a test message
You can prove the mail path end to end without any external DNS by submitting a message as the admin mailbox and retrieving it over IMAP. The image ships a small helper that authenticates to the submission port over TLS, sends a message to the admin mailbox, then retrieves it over IMAP and checks the body. It also confirms that an unauthenticated submission and a wrong IMAP password are both rejected.
sudo python3 /opt/maddy/roundtrip-check.py
A successful run prints a single OK line confirming the authenticated submission was delivered, retrieved over IMAP, and that unauthenticated access was refused. To connect a real mail client, use the admin mailbox address as the username, the per instance password, your server address with port 465 (implicit TLS) or 587 (STARTTLS) for sending, and port 993 (implicit TLS) or 143 (STARTTLS) for IMAP. Because the shipped certificate is self signed, either install your own certificate (Step 7) or allow the self signed certificate in your client for testing.

Step 6: Review the configuration and authentication model
Everything Maddy does is in one file, /etc/maddy/maddy.conf. The submission and IMAP endpoints both reference the local authentication database, so both require credentials. Credentials are hashed in an embedded database and are managed with the maddy creds command; there is no shared or default account.
sudo grep -E 'auth |submission |imap |storage.imapsql|auth.pass_table' /etc/maddy/maddy.conf
sudo -u maddy maddy creds list

Step 7: Set your real domain and TLS certificate
For production, change the hostname and primary domain in the configuration to a domain you own, then install a real TLS certificate. The example below uses <your-domain> and <mx-hostname> as placeholders.
# 1) edit /etc/maddy/maddy.conf and set:
# $(hostname) = <mx-hostname> e.g. mx1.example.org
# $(primary_domain) = <your-domain> e.g. example.org
# 2) install a certificate for <mx-hostname> at:
# /etc/maddy/certs/<mx-hostname>/fullchain.pem
# /etc/maddy/certs/<mx-hostname>/privkey.pem
# (for example with certbot, then copy or symlink the files and make them
# readable by the maddy user), then apply the change:
sudo systemctl restart maddy
Maddy reloads TLS certificates from disk automatically, so certificate renewals are picked up without downtime. Point your registrar and DNS at this instance as described in Step 9.
Step 8: Add mailboxes
Each mailbox needs a credential and a matching IMAP storage account. Usernames are full email addresses. Create both for every mailbox you add.
# create a credential (you will be prompted for a password), then the IMAP account:
sudo -u maddy maddy creds create you@<your-domain>
sudo -u maddy maddy imap-acct create you@<your-domain>
Remove a mailbox with maddy creds remove and maddy imap-acct remove. Run maddy creds --help and maddy imap-acct --help to see all subcommands.
Step 9: Publish DNS records for delivery
A public mail server needs correct DNS to send and receive reliably. Publish, for the domain you set in Step 7:
-
An MX record for
<your-domain>pointing at<mx-hostname>, and an A record for<mx-hostname>pointing at this VM's public IP -
An SPF record authorising this server to send for your domain
-
A DKIM record — Maddy generates a DKIM key for your domain on first outbound signing; publish the public key it produces
-
A DMARC record for your policy
-
A reverse DNS (PTR) record for the VM's public IP matching
<mx-hostname>, which most receivers require for delivery
Reverse DNS for an Azure public IP is set on the IP resource, not in your own DNS zone.
Step 10: Security recommendations
-
Restrict the NSG to your use case. Allow submission (465, 587) and IMAP (993, 143) only from the networks your clients use. Open port 25 only if this server receives mail for your domain.
-
Replace the self signed certificate. The shipped certificate is per instance and self signed for immediate testing. Install a certificate for your real hostname (Step 7) so clients and other mail servers trust the connection.
-
Keep authentication required. Submission and IMAP require credentials by default. Do not disable authentication, and use strong per mailbox passwords.
-
Protect the credentials file.
/root/maddy-credentials.txtis0600 root:root. Keep it restricted, and rotate the admin password withmaddy creds passwordif it is ever exposed. -
Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
Step 11: Support and Licensing
Maddy Mail Server is an open source project distributed under the GNU General Public License v3.0. This cloudimg image bundles the unmodified official Maddy release binary. cloudimg provides the packaging, the systemd hardening, the secure by default configuration, the per instance first boot provisioning of the domain, certificate and admin mailbox, the paired deploy guide, and 24/7 support with a guaranteed 24 hour response SLA.
cloudimg is not affiliated with or endorsed by the Maddy project. Maddy is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find Maddy Mail Server on Ubuntu 24.04 LTS on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.