Deploy Self-Hosted Email Solution
Running your own email server gives you complete control over your data, eliminates reliance on third-party providers, and lets you use custom domains without paying per-user subscriptions. I've deployed Mailcow on a small VPS, and it's transformed how I think about email sovereignty. In this guide, I'll walk you through deploying a production-ready self-hosted email solution from scratch.
Why Self-Host Email?
When you use Gmail or Outlook, you're trusting your messages to corporations who scan your content and profile your behavior. Self-hosting email means you own the entire stack: the mail server, the webmail interface, the spam filters, even the backup strategy. I prefer this model because it aligns with my philosophy of digital independence.
The downside? You need stable infrastructure. Self-hosted email requires a static IP, reliable uptime, proper DNS configuration, and careful attention to spam reputation. If you're running on residential internet or a flaky VPS, your mail won't reach inboxes. For most homelabbers, I recommend a dedicated VPS from a provider like RackNerd (which offers affordable, reliable KVM VPS starting at $10/year) rather than self-hosting from home.
Choosing Your Email Stack
I've tested both Mailcow and Mailu, and they're the two most viable self-hosted email systems for homelab enthusiasts. Mailcow runs on Docker, offers a powerful admin panel, and includes built-in support for SOGo (webmail), Roundcube, and mobile sync. Mailu is lighter weight but slightly less polished. I prefer Mailcow because its UI is cleaner and it handles certificate renewal automatically.
Both assume you have:
- A dedicated VPS or server with a public IPv4 address
- A domain name you control (with ability to modify DNS records)
- Ports 25, 110, 143, 465, 587, 993, and 995 open (or at least 25, 465, 587, 993)
- Docker and Docker Compose installed
- At least 4GB RAM and 30GB storage (for Mailcow with a few users)
Prerequisites: DNS and Domain Setup
Before you deploy, your DNS records must be correct. Email delivery relies entirely on DNS. You'll need:
- MX record: Points to your mail server's hostname (e.g.,
mail.example.com) - A/AAAA records: Resolve your hostname to your server's IP
- SPF record: Tells receivers which servers are allowed to send mail for your domain
- DKIM records: Cryptographic signatures that prove you sent the message
- DMARC record: Policy that tells receivers how to handle SPF/DKIM failures
- PTR record: Reverse DNS; many providers call this "rDNS" and require a support ticket
Get your reverse DNS set up first. This is the biggest gotcha I've seen. Your mail server's IP must have a PTR record pointing back to a hostname that resolves to that IP. Without it, major providers (Gmail, Outlook, Yahoo) will reject your mail. Contact your VPS provider and request PTR setup for your IP.
Deploying Mailcow with Docker Compose
I'm using Mailcow because it's the easiest to get working. Here's the deployment process:
First, clone the Mailcow repository and generate configuration:
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
bash generate_config.sh
The script will ask for your domain (e.g., example.com), hostname (e.g., mail.example.com, and timezone. Answer carefully—changing these later is a pain.
Next, review and edit the generated .env file. Key settings I always check:
# Edit the configuration
nano .env
# Key variables to verify:
# MAILCOW_HOSTNAME=mail.example.com
# DOMAIN=example.com
# SKIP_CLAMD=y (unless you have 8GB+ RAM; ClamAV is heavy)
# SKIP_SOLR=y (Solr is optional; I disable it for smaller deployments)
# SKIP_IP_CHECK=n (leave as-is unless you're behind NAT)
# TZ=UTC (adjust to your timezone)
Now pull the Docker images and start the stack:
# Pull all images (this takes a few minutes)
docker compose pull
# Start the stack in the background
docker compose up -d
# Watch logs to ensure everything started
docker compose logs -f
Wait 2–3 minutes for Mailcow to initialize. You'll see a lot of database setup messages. When you see something like mailcow-dockerized-mysql-1 | Ready for start up, the containers are ready.
Access the admin panel at https://mail.example.com/admin. Default login is admin with password moohoo (you must change this immediately). The web interface will guide you through adding domains, users, and aliases.
Configuring DNS Records for Email Delivery
Now that Mailcow is running, you need to add DNS records so other mail servers can find and validate your email:
1. MX Record
example.com MX 10 mail.example.com.
2. SPF Record (TXT)
example.com TXT "v=spf1 ip4:YOUR.SERVER.IP mx ~all"
Replace YOUR.SERVER.IP with your actual public IP address. This tells receivers: "Mail for my domain comes from this IP or from my MX server."
3. DKIM Record
Log into Mailcow's admin panel → Domains → your domain → DKIM keys. Click "Generate DKIM keys" and copy the long string. Add a TXT record:
dkim._domainkey.example.com TXT "v=DKIM1; k=rsa; p=VERY_LONG_PUBLIC_KEY_HERE"
4. DMARC Record
_dmarc.example.com TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
This tells receivers to quarantine (hold) emails that fail SPF/DKIM validation and send reports to your admin address.
After adding these records, wait 15–30 minutes for propagation, then test at MXToolbox or DMARCian.
Creating Users and Testing Email
In the Mailcow admin panel, add a mailbox:
- Go to Mailboxes → Add Mailbox
- Set local part (e.g.,
johnfor[email protected]) - Set name and password
- Enable POP3 and IMAP if you want to use desktop or mobile clients
- Save
Once created, log into the webmail at https://mail.example.com using your new address and password. Send yourself a test email from your main account (Gmail, etc.) to confirm delivery works.
To test outbound mail from your server, send an email to [email protected] and check the score. A good score is 8/10 or higher. Common issues:
- SPF fail: Your SPF record is missing or malformed
- DKIM fail: Your DKIM key isn't in DNS yet or the signature is broken
- Poor PTR: Your reverse DNS doesn't match your hostname
- Low spam score: New IPs are often flagged by Gmail. Wait 2–3 weeks for reputation to build
Mobile and Desktop Client Setup
To use Mailcow with Thunderbird, Apple Mail, or mobile clients, configure IMAP/SMTP:
- IMAP: mail.example.com, port 993 (SSL/TLS)
- SMTP: mail.example.com, port 587 (STARTTLS) or 465 (SSL)
- Username: your full email address (e.g., [email protected])
- Password: your Mailcow password
Most modern clients auto-detect these settings. If not, configure manually.
Maintenance and Backups
Self-hosted email requires ongoing care. Set up automated backups by adding this to your crontab:
# Backup Mailcow daily at 2 AM
0 2 * * * cd /opt/mailcow-dockerized && docker compose exec -T mysql mysqldump -u mailcow -p$MYSQL_PASSWORD mailcow > /backups/mailcow-$(date +\%Y\%m\%d).sql
Also keep your Docker images updated. I run this monthly:
cd /opt/mailcow-dockerized
docker compose pull
docker compose up -d
Monitor logs regularly for errors:
docker compose logs postfix | tail -50
docker compose logs dovecot | tail -50
Firewall Rules
Use UFW to restrict access. Allow only required ports:
ufw default deny incoming
ufw allow 22/tcp
ufw allow 25/tcp
ufw allow 80/tcp
ufw allow 143/tcp
ufw allow 443/tcp
ufw allow 465/tcp
ufw allow 587/tcp
ufw allow 993/tcp
ufw allow 995/tcp
ufw enable
Port 25 must be open to the world so other mail servers can deliver mail to you. Ports 143, 465, 587, 993, 995 can be restricted to your IP range if you're only connecting from home, but for flexibility, I leave them open.
Next Steps
You now have a working self-hosted email server. Next, consider:
- Setting up a reliable VPS for stability if you haven't already
- Adding fail2ban to block brute-force attacks on ports 143, 587, and 993
- Configuring Sieve filters in Mailcow for automatic email organization
- Enabling two-factor authentication in Mailcow for the admin account
- Setting up monitoring with Uptime Kuma to alert you if your mail server goes down
Self-hosted email is demanding but rewarding. You own your data, control your reputation, and gain deep knowledge of how email actually works. If you're serious about digital sovereignty, this is non-negotiable infrastructure.