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:
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:
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:
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 |
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:
curl -fsSL https://get.docker.com -o get-docker.sh
less get-docker.sh
If the script is suitable for that host, run it:
sudo sh get-docker.sh
Enable Docker and check both tools:
sudo systemctl enable --now docker
sudo docker --version
sudo docker compose version
Clone Mailcow into /opt and generate its configuration:
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:
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:
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:
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:
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:
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 |
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:
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:
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:
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:
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:
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.