Install Mailcow self-hosted email server on VPS

Install Mailcow on VPS: Self-Hosted Email Server

October 2, 2026 · ~12 min read

Mailcow Dockerized is an all-in-one email server suite running multiple Docker containers — Postfix (SMTP), Dovecot (IMAP/POP3), Rspamd (anti-spam), ClamAV (anti-virus), Roundcube webmail, and SOGo — in a single deployment. Running Mailcow on a VPS gives you 100% control over your email without relying on third-party services.

Why Use Mailcow Instead of an External Email Service?

System Requirements

ComponentMinimumRecommended
OSUbuntu 22.04 LTSUbuntu 22.04 / Debian 12
RAM3 GB4–8 GB
CPU2 cores4 cores
Disk20 GB50+ GB SSD
Docker20.10+24.x+
Required ports25, 80, 110, 143, 443, 465, 587, 993, 995, 4190
Important: Many VPS providers block port 25 (SMTP) by default. Contact your provider to unblock it before starting. Also ensure your PTR record (reverse DNS) resolves to your mail hostname, e.g. mail.yourdomain.com.

Step 1: Prepare DNS Records

Set up DNS records before installation (allow 30 minutes to 24 hours for propagation):

# A Record — point mail subdomain to your VPS IP
mail.yourdomain.com.   A    YOUR.VPS.IP

# MX Record — define the mail server for your domain
yourdomain.com.        MX   10   mail.yourdomain.com.

# PTR Record (Reverse DNS) — request from your hosting provider
YOUR.VPS.IP            PTR  mail.yourdomain.com.

# SPF Record
yourdomain.com.        TXT  "v=spf1 mx ~all"

# DMARC Record
_dmarc.yourdomain.com. TXT  "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
Note: The DKIM record is generated after Mailcow is installed — you don't need to set it up in advance.

Step 2: Install Docker and Docker Compose

# Update the system
apt update && apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com | bash

# Verify installation
docker --version
docker compose version

Step 3: Set the System Hostname

Mailcow uses the system hostname when sending email — it must match your A record exactly.

# Set hostname (must match your A record)
hostnamectl set-hostname mail.yourdomain.com

# Verify
hostname -f
# Expected output: mail.yourdomain.com

Step 4: Clone Mailcow and Generate Configuration

# Clone from GitHub
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized

# Auto-generate configuration
./generate_config.sh
# The script will ask for your mail server hostname
# Answer: mail.yourdomain.com
# Select timezone: Asia/Bangkok (or your timezone)

After generate_config.sh runs, a mailcow.conf file is created. Key values to review:

nano mailcow.conf

# Key settings to verify:
MAILCOW_HOSTNAME=mail.yourdomain.com
TZ=Asia/Bangkok
HTTP_PORT=80
HTTPS_PORT=443
SKIP_CLAMD=n       # Enable ClamAV (n = do not skip)
SKIP_RSPAMD=n      # Enable Rspamd
SKIP_SOLR=y        # Disable Solr if RAM is limited
Tip: If your VPS has less than 4 GB of RAM, set SKIP_CLAMD=y and SKIP_SOLR=y to reduce memory usage.

Step 5: Start Mailcow

# Pull Docker images (may take 5–10 minutes)
docker compose pull

# Start all services
docker compose up -d

# Check status
docker compose ps

After a moment, access the web admin panel at https://mail.yourdomain.com

Step 6: Add Your Domain and First Mailbox

  1. Go to Web UI → Configuration → Mail Setup
  2. Add Domain: click Add Domain → enter yourdomain.com
  3. Add Mailbox: click Add Mailbox → fill in the email address
  4. Click Generate DKIM Keys and copy the DNS TXT record to your DNS provider

Step 7: Add the DKIM DNS Record

# The generated record looks like this:
dkim._domainkey.yourdomain.com.  TXT  "v=DKIM1; k=rsa; t=s; s=email; p=MIIBIjAN..."

# Verify DKIM is published
dig +short TXT dkim._domainkey.yourdomain.com

Step 8: Test Email Delivery and Score

# Send a test email via CLI
docker exec -it mailcowdockerized-postfix-mailcow-1 \
  sendmail -f [email protected] [email protected] <<EOF
Subject: Test from Mailcow
Hello from my Mailcow server!
EOF

Test your email score at mail-tester.com — you should achieve 9–10/10.

Step 9: Keeping Mailcow Updated

# Update to the latest version
cd /opt/mailcow-dockerized
./update.sh

# Or update manually
git pull origin master
docker compose pull
docker compose up -d --remove-orphans

Verify Mailcow Is Running Correctly

# Check all containers
docker compose ps

# View Postfix logs
docker compose logs postfix-mailcow --tail=50

# Check Rspamd dashboard
# Visit https://mail.yourdomain.com/rspamd (via admin UI)

# Test SMTP connection
telnet mail.yourdomain.com 25
# Expected: 220 mail.yourdomain.com ESMTP Postfix

# Test IMAP connection
openssl s_client -connect mail.yourdomain.com:993
# Expected: * OK Dovecot ready

# Check mail queue
docker exec -it mailcowdockerized-postfix-mailcow-1 postqueue -p
Tip: Use MXToolbox Email Health to check blacklists, SPF, DKIM, DMARC, and PTR in one place.

Common Issues and Fixes

Error: "Connection refused on port 25"

Port 25 is likely blocked by your hosting provider or ISP, especially on new VPS instances. You must request that they unblock it.

# Check if port 25 is listening locally
netstat -tlnp | grep :25

# Test from an external machine
telnet YOUR.VPS.IP 25

# If Postfix is running but port 25 is unreachable externally,
# contact your provider to remove the outbound port 25 block.

Error: "550 5.7.1 Message rejected as spam"

Your email is being rejected because DKIM/SPF/DMARC is misconfigured, or your IP is blacklisted.

# Verify DKIM is published
dig +short TXT dkim._domainkey.yourdomain.com

# Verify SPF
dig +short TXT yourdomain.com | grep spf

# Check blacklists at mxtoolbox.com
# Or use Rspamd's built-in DKIM check
docker exec -it mailcowdockerized-rspamd-mailcow-1 \
  rspamadm dkim_check --domain yourdomain.com

Error: "certificate verify failed" in webmail

The SSL certificate hasn't been issued yet, or it has expired. Mailcow uses Let's Encrypt and handles renewal automatically.

# Force certificate renewal
docker exec -it mailcowdockerized-acme-mailcow-1 \
  /root/acme.sh --renew --domain mail.yourdomain.com --force

# Check certificate expiry
echo | openssl s_client -connect mail.yourdomain.com:443 2>/dev/null | \
  openssl x509 -noout -dates

Error: "ClamAV process died" — container in restart loop

ClamAV requires at least 1.5 GB of RAM. Either add more RAM to your VPS or disable ClamAV.

# Disable ClamAV (edit mailcow.conf)
nano mailcow.conf
# Change SKIP_CLAMD=n → SKIP_CLAMD=y

docker compose up -d --remove-orphans

Error: "docker: 'compose' is not a docker command"

The Docker Compose plugin is not installed. Mailcow requires Docker 20.10+ with the compose plugin.

# Install docker compose plugin
apt install docker-compose-plugin -y

# Verify
docker compose version

Frequently Asked Questions

What VPS specs does Mailcow need to run well?

For 1–10 users, we recommend at least 4 GB RAM, 2 CPU cores, and 50 GB SSD storage. For 50+ users or heavy workloads, 8 GB RAM and 100+ GB disk is more appropriate. ClamAV alone consumes around 1–1.5 GB of RAM, so factor that in.

Does Mailcow handle SSL automatically?

Yes. Mailcow includes an acme-mailcow container that obtains and renews Let's Encrypt certificates automatically every 60 days. As long as port 80 is open and your domain's A record points to your VPS, SSL is fully hands-off.

Can I use Mailcow for transactional emails (e.g. OTP, password resets)?

Yes. Mailcow supports SMTP submission — configure your application to send via port 587 (STARTTLS) or 465 (SSL) using the credentials of any mailbox you create. It works well for low-to-medium volume transactional email. For high-volume sending, consider a dedicated relay service to avoid deliverability issues.