How to Set Up mailcow: A Realistic Walkthrough

The short answer
Install mailcow on a clean Debian or Ubuntu VM with at least 6 GiB RAM, a static IP and a matching PTR record. Clone mailcow-dockerized under umask 0022, run generate_config.sh, then docker compose up -d. Add MX, SPF, DKIM and DMARC records, then budget for monthly updates and regular backups.
How to set up mailcow: system requirements, DNS records, the Docker install, DKIM, TLS, and the update and backup routine you inherit.
On this page
- 01The short answer
- 02Before you start: what mailcow actually needs
- 03Which ports have to be open?
- 04What DNS records does mailcow need?
- 05Installing mailcow, step by step
- 06How TLS certificates are handled
- 07mailcow vs Mail-in-a-Box: which is easier?
- 08What to do when it doesn't work
- 09The maintenance you are actually signing up for
- 10A faster way to handle the mail once it is flowing
If you want to know how to set up mailcow, the install is the easy part. Four commands and about fifteen minutes of pulling images, and you have a running mail server with Postfix, Dovecot, Rspamd, ClamAV, SOGo and an admin UI behind one Docker Compose file.
Everything around it takes longer: a host that meets the requirements, DNS that resolves before certificates are requested, a PTR record you may not control, and a maintenance routine you now own. Every command below was checked against mailcow's documentation at docs.mailcow.email in September 2026; mailcow ships monthly releases, so re-check version-specific details there before running anything on a server that matters.
The short answer#
mailcow is a dockerised bundle, not a single program. You give it a dedicated host, a hostname, and control of your DNS; it gives you a complete mail stack and a web UI to run it from.
The sequence: prepare a supported host with the ports open, publish the DNS records, clone the repository, generate a config, bring the stack up, then add your domain and mailboxes in the admin UI and publish the DKIM record it generates.
Do not install mailcow on a container host
Before you start: what mailcow actually needs#
The resource floor is higher than most self-hosting guides admit. mailcow documents a minimum of 6 GiB RAM plus 1 GiB swap on the default configuration, and names ClamAV and Flatcurve — the full-text search engine — as the greedy ones.
You also need port 25 inbound and outbound. Many providers block it by default, and that is the most common reason a self-hosted mail server never sends a message.
- A fully qualified hostname for the server itself, such as mail.example.org.
- A static IP, with a PTR (reverse DNS) record set at your provider that matches that hostname — for IPv4 and IPv6 if you run both.
- Control of the DNS zone for every domain you plan to host.
| Requirement | mailcow's documented minimum (September 2026) |
|---|---|
| CPU | 1 GHz |
| RAM | 6 GiB, plus 1 GiB swap, on the default config |
| Disk | 20 GiB before any mail is stored |
| Architecture | x86_64 or ARM64 |
| OS | Debian 11–13, Ubuntu 22.04+, AlmaLinux 8/9, Rocky Linux 9; Alpine 3.19+ with manual adjustments |
| Host type | Bare metal or full virtualisation — not OpenVZ, LXC or a NAS |
Which ports have to be open?#
mailcow publishes a specific port list, and the ACME client needs port 80 in particular. A firewall that quietly drops 80 will leave you with a working mail server and no valid certificate.
| Service | Port | Why it matters |
|---|---|---|
| SMTP | 25 | Inbound mail from the internet |
| SMTPS / Submission | 465, 587 | Your clients sending mail |
| IMAP / IMAPS | 143, 993 | Clients reading mail |
| POP3 / POP3S | 110, 995 | Only if you use POP3 |
| ManageSieve | 4190 | Server-side filter rules |
| HTTP / HTTPS | 80, 443 | Admin UI, SOGo, ACME validation |
Docker bypasses your INPUT chain
What DNS records does mailcow need?#
Publish these before you start the stack. The ACME client checks that names resolve to your server's address before adding them to the certificate, so DNS still propagating means a certificate with missing names.
The mail A record applies to your primary mailcow hostname. Additional domains need only the MX record pointing at that same hostname.
| Record | Example value | Purpose |
|---|---|---|
| mail IN A | 1.2.3.4 | The server itself |
| autodiscover IN CNAME | mail.example.org. | Outlook client autoconfiguration |
| autoconfig IN CNAME | mail.example.org. | Thunderbird client autoconfiguration |
| @ IN MX 10 | mail.example.org. | Where mail for the domain is delivered |
| @ IN TXT | v=spf1 mx a -all | SPF — which hosts may send as you |
| dkim._domainkey IN TXT | v=DKIM1; k=rsa; t=s; s=email; p=… | DKIM — generated in the mailcow UI |
| _dmarc IN TXT | v=DMARC1; p=reject; rua=mailto:[email protected] | DMARC policy and report address |
Installing mailcow, step by step#
- 1
Install the prerequisite packages
On Debian or Ubuntu: apt update && apt install -y git openssl curl gawk coreutils grep jq. Other distributions need the equivalents.
- 2
Clone the repository with the right umask
As root: umask 0022, then cd /opt, then git clone https://github.com/mailcow/mailcow-dockerized and cd into it. The umask sets the file permissions the containers expect; skipping it causes permission errors later that are hard to trace back here.
- 3
Generate the configuration
Run ./generate_config.sh. It builds mailcow.conf, which holds your hostname, timezone and the flags that control optional components. This is the file you edit, not the compose file.
- 4
Review mailcow.conf before starting
Open it and check the hostname and timezone. If you plan to terminate TLS on an existing reverse proxy, set SKIP_LETS_ENCRYPT=y now rather than after the ACME client has already tried and failed.
- 5
Pull the images and start the stack
docker compose pull, then docker compose up -d. The first pull is several gigabytes. Data lives in Docker volumes, so containers can be recreated or deleted without losing mail.
- 6
Log in to the admin UI
Go to https://YOUR_MAILCOW_HOSTNAME/admin. The default credentials are admin / moohoo. Change the password immediately — this is a public-facing host and that password is in every copy of the documentation.
- 7
Add your domain, then generate the DKIM key
Add the domain in the UI, generate its DKIM key there, and publish the TXT record at dkim._domainkey. Only then add mailboxes — mail sent before the record is live goes out unsigned, and receiving providers treat it accordingly.

How TLS certificates are handled#
mailcow ships its own ACME client in a container called acme-mailcow. With no additional domains configured it requests a certificate for your MAILCOW_HOSTNAME, and adds autodiscover and autoconfig names per mail domain only after checking they resolve to the server's IPv4 or IPv6 address.
Port 80 must be reachable for this to work — the docs state that plainly. ADDITIONAL_SAN in mailcow.conf adds further names, including wildcard patterns like smtp.* that expand per mail domain.
To force a reissue, create a file named force_renew in data/assets/ssl/ and restart acme-mailcow; it is deleted automatically. To use your own certificates, copy them to data/assets/ssl/cert.pem and key.pem — the docs are explicit that symbolic links will not work.
SKIP_IP_CHECK is not a fix
mailcow vs Mail-in-a-Box: which is easier?#
Both install a full mail stack from a script. They differ in what they will let you change afterwards.
| Dimension | mailcow: dockerized | Mail-in-a-Box |
|---|---|---|
| Host | Debian, Ubuntu, AlmaLinux or Rocky; no container hosts | A completely fresh Ubuntu 22.04 x64 machine; containers unsupported |
| Packaging | Docker Compose stack you can extend | Turn-key installer that owns the machine |
| Configurability | mailcow.conf plus container overrides | Stated goal is almost no configuration options |
| DNS | You publish the records | Can run its own DNS for the domain |
| Best for | Tuning Postfix, Rspamd or Dovecot | Having it decided for you |
What to do when it doesn't work#
- Nothing arrives from outside: check inbound port 25 is open and that your MX points at a hostname with an A record, not a CNAME.
- Mail lands in spam everywhere: check the PTR record first. A mismatch between reverse DNS and the hostname mailcow announces in HELO is the usual cause, and you fix it at your IP provider, not in mailcow.
- Certificate errors in clients: confirm port 80 is reachable and that autodiscover and autoconfig resolve. Names failing the check are silently left out of the certificate.
- The UI loads but nothing sends: your provider is probably blocking outbound 25. Test that before assuming a mailcow fault; the fix is a relayhost or a different provider.
- Verify externally, not by eye. mailcow's docs point at MXToolbox for DNS, SMTP and blocklists, port25.com for DKIM and SPF, and Mail-tester for all three.
The maintenance you are actually signing up for#
mailcow releases monthly, versioned YYYY-MM, with lettered hotfixes. Updates run through ./update.sh in the repository root, which fetches changes, merges your config, pulls new images and restarts the stack.
Useful flags: --check shows what would change without applying it, --gc cleans up old image tags, --ours resolves merge conflicts in favour of your local edits, and --prefetch downloads images ahead of a maintenance window. Nightly builds exist and are explicitly not for production.
Backups run from helper-scripts/backup_and_restore.sh, which the docs tell you not to copy elsewhere. Pick components — vmail, crypt, redis, rspamd, postfix, mysql, or all — and point MAILCOW_BACKUP_LOCATION at a destination. Back up crypt alongside vmail: without the encryption keys, the archive is not recoverable.
A faster way to handle the mail once it is flowing#
mailcow solves delivery. It does not solve what eats your day afterwards — triaging what arrived and writing the replies. SOGo gives you competent webmail, but triage stays manual.
That is the job we build AI Emaily for, and it sits on top of a mailcow server rather than replacing it: connect the mailbox over IMAP and SMTP (see /docs/connect-imap), and the agent categorises, drafts and closes loops while your server keeps doing the delivery. Drafts wait for your approval before anything sends, every action is undoable and audited, and your mail is never used to train a model. We build AI Emaily; there is a 7-day free trial on Pro and Autopilot.
It does not replace anything mailcow does. Your MX record, your DKIM keys and your update routine are unchanged.
Frequently asked
See it in AI Emaily
Keep reading

Written by
Nafiul HasanNafiul Hasan is an entrepreneur and AI automation system builder with 10+ years of experience turning messy, manual workflows into reliable automated systems. He designs and ships AI enterprise solutions end-to-end — the agent logic, the data plumbing, and the product people actually use — and founded AI Emaily to give busy professionals their attention back. He writes here from the builder's seat: what works, what breaks, and how to put AI to work without giving up control.