Skip to main content
How to Setup a Mail Server with Mailcow - Virtarix Blog

How to Set Up a Mail Server with Mailcow

November 11, 2025 · Blog / Technical Guides

Mailcow combines Postfix, Dovecot, webmail, spam filtering, and administration tools in a Docker-based mail-server suite. You manage the mailboxes and configuration, along with the DNS, updates, backups, and delivery problems that come with running an email server on a VPS.

This general walkthrough uses a Linux host where the provider permits mail-server workloads and the required network traffic. Confirm that before installation, along with control of your domain's DNS and the server's reverse DNS.

Check the requirements

Memory, storage and networking

Mailcow's documented baseline for its default configuration is 6 GiB RAM plus 1 GiB swap, with 20 GiB of disk space before storing email. Allow additional space for mailboxes, indexes, logs, updates, and temporary backup files. Concurrent clients, antivirus scanning, and search indexing can increase memory use substantially.

Use a supported physical or fully virtualised host. Do not assume that a nested container or lightweight container-based VPS can run the complete stack. Disabling ClamAV or full-text search changes functionality and may reduce memory demand; it does not establish that a small server will handle your workload.

You also need a stable public IP address, working time synchronisation, and access to the required inbound and outbound ports. If you publish IPv6 records, verify that mail delivery and reverse DNS work over IPv6 too.

Operating system and Docker

Choose an operating system from the Mailcow system requirements and install a compatible Docker Engine and Compose plugin. Check the support requirements for the Mailcow release you intend to install rather than copying minimum versions from an older guide.

The package commands below use apt on Debian or Ubuntu. Install the command-line dependencies and the DNS lookup utility used later:

Install Mailcow command-line dependencies
sudo apt update
sudo apt install -y git openssl curl gawk coreutils grep jq dnsutils

Review and apply outstanding operating-system updates before deployment. Schedule any required reboot and confirm the host is healthy afterward.

Prepare DNS

Create an A record for the mail hostname, such as mail.example.com, pointing to the server. Add an AAAA record only if you intend to operate the service over working IPv6. Your domain's MX record should name the mail hostname, not an IP address.

An SPF record such as v=spf1 mx ~all authorises the domain's MX hosts to send mail. Review all legitimate senders before using it; domains with other sending services need an SPF record that accounts for those services too. Publish one SPF record per domain.

You will add DKIM and DMARC after configuring the domain. If you use Cloudflare, keep mail-host records DNS-only; its ordinary web proxy does not proxy SMTP or IMAP. See the Cloudflare setup guide for DNS administration.

Prepare the host and firewall

Check for services already listening on Mailcow's standard ports:

Check for occupied Mailcow ports
sudo ss -tlpn | grep -E -w '25|80|110|143|443|465|587|993|995|4190'

Identify each conflicting service before stopping or reconfiguring it. An existing web server or mail service may be serving users. Plan the change and its rollback before replacing it.

Set the shell mask used during setup:

Set the shell file-creation mask to 0022
umask 0022

Mailcow publishes container ports through Docker. Host firewall rules that affect only the INPUT chain may not restrict forwarded container traffic. A list of ufw allow commands is therefore insufficient to prove the stack is protected. Follow Mailcow's firewall guidance for your Docker backend, preserve administrator access, and test the allowed and denied paths from another host.

Review the services you will expose:

Service TCP ports Purpose
SMTP 25 Mail transfer between servers
Submission 465, 587 Authenticated sending from mail clients
IMAP 143, 993 Mailbox access, with the configured TLS mode
POP3 110, 995 POP3 mailbox access if used
ManageSieve 4190 Client management of filtering rules
HTTP and HTTPS 80, 443 Web access and the configured certificate-validation flow
Swipe to view the full table

Configure exposure to match the services and client modes you support. Check the upstream outbound requirements too, including DNS, image downloads, updates, and filter data. Do not disable a working firewall without a replacement ruleset and a recovery path.

Install Docker and prepare Mailcow

Use Docker's documented installation procedure for your distribution. For a disposable test host, Docker also provides a convenience script. Download and inspect it before deciding whether to run it with administrator privileges:

Download and inspect the Docker convenience script
curl -fsSL https://get.docker.com -o get-docker.sh
less get-docker.sh

If the script is suitable for that host, run it:

Run the reviewed Docker installation script
sudo sh get-docker.sh

Enable Docker and check both tools:

Start Docker and check Engine and Compose
sudo systemctl enable --now docker
sudo docker --version
sudo docker compose version

Clone Mailcow into /opt and generate its configuration:

Clone and configure Mailcow
cd /opt
sudo git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
sudo ./generate_config.sh

Enter the fully qualified mail hostname when prompted. Review mailcow.conf, including the hostname, timezone, network bindings, and enabled components. Keep the generated credentials private. The use of sudo here matches a repository created by root; do not change the ownership of the entire tree to work around an unexplained permission error.

Download and start the containers

From /opt/mailcow-dockerized, pull the images and start the stack:

Pull images and start Mailcow
sudo docker compose pull
sudo docker compose up -d

Startup time depends on the host and downloads. Watch the logs and service status instead of assuming the stack is ready after a fixed delay:

Inspect Mailcow startup
sudo docker compose ps
sudo docker compose logs -f

Press Ctrl+C to stop following logs; this does not stop the containers. Investigate services that exit or restart repeatedly. Use the Compose service name to inspect one component:

Inspect the Mailcow web service logs
sudo docker compose logs nginx-mailcow

A running container is only one check. Verify that the web interface responds, certificates are valid, and mail services accept the intended connections.

Configure the domain and mailboxes

Secure the administrator account

Open the configured HTTPS hostname. Resolve unexpected certificate warnings before entering credentials. Confirm the address, DNS records, certificate issuance, and the certificate's hostname rather than treating every warning as normal.

For installations that use the documented initial account, the username is admin and the initial password is moohoo. Change that password immediately and enable two-factor authentication before allowing routine administrative access. Check the installation documentation if your release uses a different initial-login process.

Set reverse DNS

Ask the IP provider to set the PTR record to the mail hostname. The hostname should resolve back to the intended address. Check it with:

Check the mail server reverse DNS
dig -x YOUR_SERVER_IP +short

Replace YOUR_SERVER_IP with the actual address. Repeat the forward and reverse checks for every address family used to send mail.

Add the domain and authentication records

In Mailcow's mail configuration, add the domain whose mailboxes you will host, for example example.com. Set quotas from your available storage and recovery plan; do not rely on default quotas as a capacity calculation.

Generate a DKIM key for that domain and publish the public key at the selector Mailcow specifies. With selector dkim, the TXT record name is dkim._domainkey.example.com. Copy the complete value and keep the private key on the server.

For DMARC reporting, an initial record might be:

Example DMARC monitoring record
v=DMARC1; p=none; rua=mailto:dmarc@example.com

Create the reporting mailbox or use an authorised reporting service. Review SPF/DKIM alignment and reports for every legitimate sender before moving to quarantine or reject. A fixed waiting period does not prove that enforcement is safe.

Create mailboxes

Add each mailbox under its domain, assign a strong password, and set an appropriate quota. Check that the mailbox is active and that its display name is correct. Test with a dedicated mailbox before migrating users or changing an existing domain's MX records.

Test sending and receiving

Sign in to SOGo webmail and test delivery both to and from an external account you control. Inspect the received message headers for SPF, DKIM, and DMARC results. Successful authentication helps receivers evaluate a message but does not guarantee inbox placement.

For an email client, use the settings enabled on your installation:

Setting Example
Incoming server mail.example.com, IMAP port 993, TLS
Outgoing server mail.example.com, submission port 587, STARTTLS
Username Full mailbox email address
Password The mailbox password or supported app credential
Swipe to view the full table

External services such as mail-tester.com or check-auth@verifier.port25.com may help diagnose authentication, where available. Use a test message without private content and treat their results as diagnostics rather than a delivery guarantee.

Inspect recent Postfix logs and the queue using the Compose service name:

Inspect Postfix delivery and queue status
sudo docker compose logs --tail=100 postfix-mailcow
sudo docker compose exec postfix-mailcow postqueue -p

status=sent means Postfix handed the message to the next destination successfully. It does not confirm the recipient read it or that it reached their inbox. Investigate queue age, repeated deferrals, and the receiver's response; a non-empty queue alone is not necessarily a failure.

Troubleshoot specific symptoms

A container keeps restarting

Read that service's logs, then check available memory, disk space, port conflicts, and permissions on the exact paths mentioned. Use the ownership and mode expected by the affected component. Recursively changing the whole Mailcow tree can damage volume data or hide the original problem.

Mail is delayed or rejected

Read the SMTP response and queue details. A connection timeout can have several causes, including routing, filtering, or a remote outage. Check the network path and the provider's mail policy. Authentication failures, relay-policy rejections, DNS problems, and receiver reputation decisions require different fixes.

Verify the full mailbox username and submission settings for client-send failures. For remote rejection, inspect forward/reverse DNS and message authentication alongside the receiver's error. Avoid repeatedly resending a large queue before understanding the cause.

HTTPS or certificate issuance fails

Inspect the ACME service:

Read Mailcow certificate-service logs
sudo docker compose logs acme-mailcow

Check DNS, the challenge method, and the required inbound port. A reverse proxy needs a configuration compatible with Mailcow's certificate setup. Use the documented external-certificate procedure if you manage certificates elsewhere.

A mailbox or web interface is unavailable

Check the relevant services:

Check mailbox and web service status
sudo docker compose ps dovecot-mailcow nginx-mailcow

Confirm the account is active, the DNS record points to the intended host, and the client can reach the configured port. DNS cache expiry follows record TTLs and resolver behavior; there is no fixed propagation time for every change.

Legitimate messages are marked as spam

Inspect Rspamd's symbols, scores, and configured actions for sample messages. Use the documented learning workflow and make a narrow adjustment only after identifying the cause. Broad sender allowlists and large threshold increases can admit unwanted mail; a familiar From address is not proof of authenticity.

Maintain and recover the installation

Use the supported updater

Read the release notes, preserve your local configuration changes, and take a usable backup before upgrading. From the Mailcow directory, inspect available updates and then run the project updater during a maintenance window:

Check and apply a Mailcow update
sudo ./update.sh --check
sudo ./update.sh

Follow the prompts and resolve conflicts deliberately. Pulling images and restarting containers alone may miss repository or configuration changes handled by the updater. Check service health and mail flow after the update.

Back up data and configuration

Mailcow provides a backup helper:

Back up Mailcow with its helper script
sudo ./helper-scripts/backup_and_restore.sh backup all

The helper asks for a backup destination unless one is supplied through its supported configuration. Check the files it creates and its coverage for your release. Preserve custom configuration, certificates, and other required files that are outside that coverage. Store an independent copy off the server and protect it as sensitive mailbox data.

Test recovery on an isolated host with compatible software. Verify mailbox contents, authentication, domains, and configuration before treating the backup as usable. Docker volumes surviving a container update is not a substitute for an independent backup.

Monitor capacity and access

Track memory, disk growth, queue age, failed delivery, certificate expiry, and backup results. Choose alert thresholds that leave time to respond to your measured growth. Apply security fixes promptly according to their urgency.

Review administrator access and mailbox ownership when people join or leave. Retain or remove mail under your organisation's retention policy rather than deleting accounts after an arbitrary period. Configure and check log rotation for the actual logging paths and Docker settings.

Review Mailcow's included authentication-abuse controls and their logs. Blocking repeated failures can reduce abuse, but it does not replace strong credentials, limited administrative access, and patching.

Use the official Mailcow documentation for release-specific configuration. Before moving real users, complete the DNS, access, mail-flow, and recovery checks on the installation you will operate.

Peter French
About the Author Peter French is the Managing Director at Virtarix, with over 17 years in the tech industry. He has co-founded a cloud storage business, led strategy at a global cloud computing leader, and driven market growth in cybersecurity and data protection.