What you take on when you host your own mail
Running mailcow means your domain's mail lives on a machine you control: the mailboxes, the spam filter and the passwords never sit with a third party. The trade is that you look after it. You keep the software up to date, watch the mail queue, and fix things when another provider starts refusing your messages.
mailcow makes that lighter. One docker compose project brings up Postfix (sending and receiving), Dovecot (the mailboxes), Rspamd and ClamAV (spam and virus checks), SOGo (webmail, calendar and ActiveSync for phones), plus a database, a cache and a web server. You manage domains and mailboxes from a browser.
How much server does mailcow need?
Plan on memory first; the processor barely matters, since mailcow asks for just 1 GHz. These figures come from mailcow's own requirements page:
| Who will use it | Memory mailcow suggests |
|---|---|
| Absolute minimum, default settings | 6 GiB plus 1 GiB of swap |
| A household or a private setup | 6 GiB plus 1 GiB of swap is fine for most |
| A small team of roughly 5 to 10 | 8 GiB recommended |
| A company with 15 phones on ActiveSync and about 50 open IMAP sessions | 16 GiB |
Phones drive memory. Each SOGo worker, the part that syncs calendars and mail to phones, can reach about 350 MiB, and mailcow starts 20 of them by default. Short on memory? Set SKIP_CLAMD=y (no virus scanner) or SKIP_FTS=y (no full-text search) in mailcow.conf.
Port 25 and reverse DNS, settled before you order
A mail server that cannot talk on port 25 cannot deliver mail to anyone else, and many hosts block it. On our dedicated servers port 25 is open and outbound mail is allowed. The only time we close outbound 25 is on a single address that gets listed for actually sending spam, and then for 30 days; a listing of a whole range or a policy listing never triggers it.
Receiving servers also look up your address backwards and expect to find your mail server's name. mailcow's documentation asks for the PTR record of each address you send from, IPv4 and IPv6 alike, to match your MAILCOW_HOSTNAME. Here reverse DNS is yours to edit from the dashboard, with no ticket and no charge.
We check addresses against the public blocklists before we hand them out, keep checking afterwards, and swap one that turns up listed. That gives you a clean start, nothing more.
Nobody can promise that your mail reaches the inbox. The big mailbox providers look at how long an address has sent clean mail, and a fresh server has no record yet. Get SPF, DKIM, DMARC and reverse DNS right, send a test to a checker, and grow your volume slowly.
The server that fits
Every server on our dedicated servers page is a whole machine for you alone, handed over within 30 minutes of payment approval when it is already racked. For mailcow, this is how we would choose:
- For a family or a handful of people: one of the small cartridge servers with 8 GB or more. The 20 GiB figure holds no messages, so check the disk on the card against what your mailboxes will hold.
- For a business with phones syncing all day: one of the everyday or two-processor servers with 16 GB or more. Our enterprise servers add a hardware RAID controller, so a mirrored pair of disks holds the mail, and a console you can open even when the system will not boot.
- Skip the ARM cartridge: it installs Ubuntu 16.04 or 18.04 only, and mailcow lists Ubuntu 22.04 or newer as its supported Ubuntu releases.
Need a specific memory size or disk layout? Build it to order and keep the machine when you outgrow it: memory and disks can be added later without changing your IP address.
Set up DNS before you install
Do this first. Say your server is mail.example.org and your domain is example.org:
- An A record for
mailpointing at the server, plus an AAAA record if you use IPv6. This one is needed only for the server's own name. - An MX record on
example.orgpointing tomail.example.org, and CNAME records forautodiscoverandautoconfigpointing there too, so mail apps set themselves up. - SPF as a TXT record, for example
v=spf1 mx a -all, which allows only your MX to send for the domain. - DKIM: mailcow generates the key in its admin panel; publish it as
dkim._domainkey. - DMARC at
_dmarc:v=DMARC1; p=rejectplus arua=address where reports should go.
Up and running in an evening
Out of the box, mailcow's admin panel opens with the username admin and the password moohoo, on every address the server has. So you will keep the web panel private until that password is gone.
- Reinstall the server from your control panel with Ubuntu 22.04 or newer (24.04 where your server offers it), or Debian 12 or 13, all of which mailcow lists as fully compatible. Log in as root and check the clock with
timedatectl status: 'System clock synchronized' should say yes (if not, runtimedatectl set-ntp true). - Install Docker and the tools mailcow needs, then download mailcow and run
./generate_config.sh(first block). It asks for the server's full name, such asmail.example.org(not your mail domain), your time zone, and a branch: pick the stable one. Themailcow.confit writes holds passwords and is created readable by root only. - Open
mailcow.confand setHTTP_BIND=127.0.0.1andHTTPS_BIND=127.0.0.1. mailcow's documentation notes that binding an IPv4 address drops the IPv6 bindings, so the panel answers on neither public address yet. - While
mailcow.confis open, make your IPv6 choice. Either set IPv6 up properly on the server now, with its own reverse DNS, or turn it off in mailcow withENABLE_IPV6=false. - Start mailcow and run
docker compose psuntil mysql-mailcow is listed as running, then run the reset script (second block). Say y when it asks you to confirm. It replacesmoohoowith a random password, clears any two-factor login on the admin account, and shows the password once; save it in your password manager. If it complains that MySQL is not up, give it a moment and run it again. - Empty both BIND settings again and restart the stack. Sign in at
https://mail.example.org/admin, switch on two-factor login, add your domain and create the DKIM key.
apt update
apt install -y git openssl curl gawk coreutils grep jq
curl -sSL https://get.docker.com/ | CHANNEL=stable sh
systemctl enable --now docker
umask 0022
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
./generate_config.sh
cd /opt/mailcow-dockerized
docker compose pull
docker compose up -d
./helper-scripts/mailcow-reset-admin.sh
# after emptying HTTP_BIND and HTTPS_BIND in mailcow.conf:
docker compose down
docker compose up -d
While the web ports were private, the Let's Encrypt container could not complete its check. After the restart, docker compose logs acme-mailcow tells you whether your certificate came through.
Keeping the server locked down
Do not reach for ufw here. mailcow's documentation warns that ufw and firewalld cause problems with it, and that INPUT rules have no effect on its services because Docker publishes them. If you want your own rules, the documented place is Docker's DOCKER-USER chain, saved with iptables-persistent so they survive a restart.
- Ports 80, 443, 25, 465, 587, 993, 143, 995, 110 and 4190 have to reach the internet for mail and webmail to work.
- The database, Redis and doveadm ports are bound to 127.0.0.1 out of the box. Keep them there.
- Protect SSH with keys and turn off password logins. SSH is not in Docker, so ordinary host rules do apply to it.
- Rules written with iptables only cover IPv4. If the server has IPv6, repeat them with ip6tables.
IPv6 is free with our servers. Since its 2025-09 release mailcow turns IPv6 on by itself when the host has it, and its config file warns that a badly set up IPv6 host can end up as an open relay. That is why the install steps make you choose before the first start. Changing your mind later means editing ENABLE_IPV6 and restarting the whole stack (docker compose down, docker compose up -d).
If a rule ever locks you out, rack servers and blades have a console that still shows you the screen, as do two cartridge models, the m510 and m710x. Keeping your own software patched is your part: you manage the server, and we keep the hardware and the network running.
Backups you can actually restore
mailcow comes with backup_and_restore.sh in its helper-scripts folder. backup all covers every part the script knows (mysql, vmail, crypt, rspamd, redis and postfix) in a dated folder, and --delete-days prunes old copies. Setting MAILCOW_BACKUP_LOCATION stops it asking where to write, which is what lets it run from cron. Below is our example, adapted from the cron line in mailcow's docs: theirs saves only mysql, crypt and redis to /mnt/mailcow_backups and keeps three days, ours saves everything to /opt/backup and keeps thirty.
mkdir -p /opt/backup
crontab -e
# add these two lines:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
5 4 * * * cd /opt/mailcow-dockerized/; MAILCOW_BACKUP_LOCATION=/opt/backup /opt/mailcow-dockerized/helper-scripts/backup_and_restore.sh backup all --delete-days 30
Then get the copies off the server, to another machine or another city, so a dead disk takes nothing with it. For updates, run ./update.sh --check in the mailcow folder to see what is new, then ./update.sh to apply it. Running other self-hosted tools for the same team? Our guide to a self-hosted Nextcloud server covers files and sharing.
Questions people ask
- Is 8 GB of RAM enough for mailcow?
- For a small group, yes: mailcow recommends 8 GiB when roughly 5 to 10 people use it. The bare minimum is 6 GiB with 1 GiB of swap. If many phones sync over ActiveSync, plan for 16 GiB.
- Do you block port 25 on dedicated servers?
- No. Port 25 is open and outbound mail is allowed. Outbound 25 is closed for 30 days only on a single address that is listed for actually sending spam, never because of a range-wide or policy listing.
- Can I set the reverse DNS for my mail server myself?
- Yes. Reverse DNS is editable from your dashboard, without a ticket. Point the PTR of each sending address at your mailcow hostname, as mailcow's documentation asks, for IPv6 too if you use it.
- What should I do with mailcow's default login?
- Replace it before the panel is public. mailcow ships with admin and moohoo. Start it with the web ports held on loopback, let the reset script swap in a random password, and only then publish the panel and switch on two-factor login.
- Will Gmail and Outlook accept mail from my new server?
- We cannot promise that, and neither can anyone else. Clean addresses, correct reverse DNS and SPF, DKIM and DMARC records give you a fair start, but the big providers also weigh how long an address has been sending good mail.