Magnetite
Back to Blog

Self-Hosted Email: Mailcow on Hetzner Cloud - A Comprehensive Guide

Deploy a self-hosted email server on Ubuntu using Hetzner Cloud and Mailcow. This guide provides a step-by-step walkthrough, covering everything from server provisioning to DKIM setup and backups.

Louis NewmanLouis Newman
5 min read

Setting Up Custom Email Infrastructure with Mailcow on Hetzner Cloud

This guide walks through deploying a self-hosted email server on Ubuntu using the Hetzner Cloud platform. Mailcow enables you to run email services with your own domain while also offering calendar and contact synchronization capabilities.

Resources:

  • Domains: https://www.cloudflare.com/
  • Hetzner: https://hetzner.cloud/?ref=BOsLzJQOOow0
  • Google sheet template for domains & DNS: https://docs.google.com/spreadsheets/d/1JPd1wRFpUEfbi7ePyyymkSsQlML98HRbzupQL_G5zfc/edit?usp=sharing
  • Documentation: https://docs.mailcow.email/
  • Main Site: https://mailcow.email
  • Source Code: https://github.com/mailcow/mailcow-dockerized
  • Support Forum: https://community.mailcow.email

What You'll Need

  • A registered domain
  • Where to host email server:
  • - example.com - Individual domains: - domain-example.com
  • Basic understanding of Docker containers
Note: Hetzner initially restricts ports 25 and 465 for anti-spam measures. These restrictions are lifted once you've paid your initial invoice, serving as basic user verification.

Step 1: Provisioning Your Cloud Instance

  • Access your Hetzner Cloud account
  • Start a fresh project with any name you prefer
  • Pick your server's geographic location and specifications (refer to guidance below)
  • Hit "Add Server" and choose Ubuntu 24.04 (Debian 12 works too for better stability)
  • Select your required hardware tier under Type - I went with ccx13
  • In the Cloud config section, add: #include https://get.docker.com (auto-installs Docker)
  • Add your SSH key (see SSH key generation guides if needed)
  • - https://docs.github.com/en/enterprise/2.16/user/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
  • Enter your full hostname like mail.example.com
  • Complete with "Create & Buy Now"

Selecting Server Specs: Pick the data center nearest to your location or primary users. Remember that Mailcow needs minimum 7GB RAM. As a comprehensive groupware platform, you'll want at least a CX31 or CPX31 instance (CX series may not be available in all regions).

Step 2: Configure Your DNS Settings

Set up a DNS entry for mail.example.com with both IPv4 (A record) and IPv6 (AAAA record) addresses. Configure your domain's MX record to reference this mail subdomain. Additionally, create autodiscover.example.com and autoconfig.example.com as CNAME records pointing to mail.example.com.

Example DNS setup:


Name Type Value

mail IN A 10.0.0.1 mail IN AAAA 2001:db8:1234::1 autodiscover IN CNAME mail autoconfig IN CNAME mail

@ IN MX 10 mail

Check Mailcow's documentation for additional DNS configurations in advanced setups.

Step 3: System Updates and Docker Compose Installation

After the server initializes, establish an SSH connection using your private key. Update the system packages:


apt update && apt upgrade -y

Consider rebooting after updates complete, particularly if kernel patches were applied.

Step 4: Download Mailcow

Navigate to the /opt directory:


cd /opt

Clone the repository:


git clone https://github.com/mailcow/mailcow-dockerized

Step 5: Configure and Launch Mailcow

Ensure you have Docker Compose v2 (verify with docker compose version).

Navigate to the Mailcow directory:


cd /opt/mailcow-dockerized

Generate configuration:


./generate_config.sh

Input your domain (like mail.example.com) when prompted.

Download container images:


docker compose pull

Start the services:


docker compose up -d

Step 6: Configure Reverse DNS

  • Open your Hetzner Cloud project
  • Navigate to your server's NETWORKING section
  • - For IPv4: Click the menu dots, choose "Edit Reverse DNS", input your domain (mail.example.com) - For IPv6: Click the menu dots, choose "Edit Reverse DNS", enter ::1 in the IP field alongside your domain

Step 7: Initial Access

Browse to https://mail.example.org and authenticate with:

  • User: admin
  • Pass: moohoo
Critical: Update this password immediately to prevent unauthorized access.

Step 8: Configure Your Domain

Navigate to Configuration → Mail setup and register your domain under the "Domain" section.

Step 9: Enable DKIM Authentication

Go to Configuration → Configuration & Details, then find DKIM in the sidebar. Use the "Select domains with missing keys" option to auto-populate your domain. Generate a 2048-bit key and add it. Copy the resulting public key and create a DNS TXT record named dkim._domainkey with this value.


"v=DMARC1; p=reject; rua=mailto:dmarc@.com; ruf=mailto:dmarc@.com; fo=1; adkim=s; aspf=s"

"v=spf1 ip4: ip6: -all"

Step 10: Set Up User Mailboxes

Return to Configuration → Mail setup to create mailboxes. Access webmail through SOGo at https://mail.example.com/SOGo.

Step 11: Implementing Backups

Protecting your email data through regular backups is crucial.

Manual Backup Process

  • SSH into your server
  • Navigate to /opt/mailcow-dockerized/helper-scripts
  • Execute:

./backup_and_restore.sh backup all --delete-days 7

Specify backup destination when prompted

The --delete-days 7 flag removes backups older than a week. Adjust or remove based on your retention needs.

Scheduled Backups

  • SSH to your server
  • Open cron configuration: crontab -e
  • Choose nano editor (option 1) if prompted
  • Add this line (customize as needed):

0 5   * MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups /opt/mailcow-dockerized/helper-scripts/backup_and_restore.sh backup all --delete-days 7

Backup Best Practices

Follow standard backup protocols - maintain copies in separate locations from your server (consider using Hetzner Storagebox for offsite storage).

Step 12: Maintaining Your Installation

Mailcow typically releases monthly updates, with additional patches for security issues. Monitor the releases page for update information.

Update Procedure

Always verify you have recent backups before updating. Consider creating a server snapshot through Hetzner for quick rollback capability.

  • SSH to your server
  • Change to /opt/mailcow-dockerized
  • Execute:

./update.sh

The updater checks for script updates first - rerun if it self-updates

Confirm when prompted to proceed with updates

When asked about removing old components, choose "no" initially (can remove manually later if everything works)

Allow all services to complete their startup and internal migrations - avoid interrupting the process to prevent data issues

About the Author

Louis Newman
Louis Newman

Former Royal Marines Commando turned founder on a mission to make sales an act of service. After 2 years building AI SDRs at Luna.ai and sending millions of cold emails, Louis discovered that giving real value upfront beats any pitch. Now building Magnetite to help every business deliver their expertise at scale through automated service-based lead magnets.