Blog/ Other providers

How to Set Up mailcow: A Realistic Walkthrough

Nafiul HasanNafiul Hasan· 9 min read
Diagram of a mailcow dockerized setup: host server, Docker containers for Postfix, Dovecot and Rspamd, and the DNS records pointing at it

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
  1. 01The short answer
  2. 02Before you start: what mailcow actually needs
  3. 03Which ports have to be open?
  4. 04What DNS records does mailcow need?
  5. 05Installing mailcow, step by step
  6. 06How TLS certificates are handled
  7. 07mailcow vs Mail-in-a-Box: which is easier?
  8. 08What to do when it doesn't work
  9. 09The maintenance you are actually signing up for
  10. 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

mailcow's documentation explicitly says not to install it on a NAS (Synology, QNAP), OpenVZ, Virtuozzo, LXC or other container platforms. Full virtualisation — KVM, ESXi, Hyper-V — and bare metal are supported. If your cheap VPS is OpenVZ, stop and buy a KVM one.

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.
Requirementmailcow's documented minimum (September 2026)
CPU1 GHz
RAM6 GiB, plus 1 GiB swap, on the default config
Disk20 GiB before any mail is stored
Architecturex86_64 or ARM64
OSDebian 11–13, Ubuntu 22.04+, AlmaLinux 8/9, Rocky Linux 9; Alpine 3.19+ with manual adjustments
Host typeBare 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.

ServicePortWhy it matters
SMTP25Inbound mail from the internet
SMTPS / Submission465, 587Your clients sending mail
IMAP / IMAPS143, 993Clients reading mail
POP3 / POP3S110, 995Only if you use POP3
ManageSieve4190Server-side filter rules
HTTP / HTTPS80, 443Admin UI, SOGo, ACME validation

Docker bypasses your INPUT chain

mailcow's docs warn that on a dockerised host, iptables INPUT rules do not restrict access to the containers — you need the FORWARD chain, and ideally DOCKER-USER. They recommend disabling firewalld or ufw where possible and moving your ruleset there. A ufw rule you assume is protecting port 143 may be doing nothing.

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.

RecordExample valuePurpose
mail IN A1.2.3.4The server itself
autodiscover IN CNAMEmail.example.org.Outlook client autoconfiguration
autoconfig IN CNAMEmail.example.org.Thunderbird client autoconfiguration
@ IN MX 10mail.example.org.Where mail for the domain is delivered
@ IN TXTv=spf1 mx a -allSPF — which hosts may send as you
dkim._domainkey IN TXTv=DKIM1; k=rsa; t=s; s=email; p=…DKIM — generated in the mailcow UI
_dmarc IN TXTv=DMARC1; p=reject; rua=mailto:[email protected]DMARC policy and report address

Installing mailcow, step by step#

  1. 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. 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. 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. 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. 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. 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. 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.

Illustration of mail routing paths: inbound SMTP on port 25 reaching the server, and outbound mail leaving it authenticated by SPF, DKIM and DMARC records
Three of the seven steps are DNS, not software. That ratio is the honest shape of self-hosted mail.

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

SKIP_IP_CHECK=y stops the ACME client verifying that names point at your server. It does not make a broken DNS zone work — it sends the failures to Let's Encrypt instead of catching them locally, which is a fast route to a rate limit. Fix the DNS.

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.

Dimensionmailcow: dockerizedMail-in-a-Box
HostDebian, Ubuntu, AlmaLinux or Rocky; no container hostsA completely fresh Ubuntu 22.04 x64 machine; containers unsupported
PackagingDocker Compose stack you can extendTurn-key installer that owns the machine
Configurabilitymailcow.conf plus container overridesStated goal is almost no configuration options
DNSYou publish the recordsCan run its own DNS for the domain
Best forTuning Postfix, Rspamd or DovecotHaving 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 nightly backup cron entry, from mailcow's documentation
Schedule5 4 * * *
Working dircd /opt/mailcow-dockerized/
DestinationMAILCOW_BACKUP_LOCATION=/mnt/mailcow_backups
Commandhelper-scripts/backup_and_restore.sh backup mysql crypt redis --delete-days 3

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

Nafiul Hasan

Written by

Nafiul Hasan

Nafiul 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.

EntrepreneurAI Automation System BuilderAI EnthusiastBuilds AI Enterprise Solutions10+ years experience
More from Nafiul
Ready when you are

Your server delivers the mail. Who handles the inbox?

Connect a mailcow mailbox over IMAP and let AI Emaily triage and draft — with approval before send, undo, and a full audit trail.

  • 7-day free trial
  • Cancel anytime
  • Every provider