Prerequisites #
In this tutorial I’m using:
-
A Hetzner Cloud “CAX11” cloud server with 2 (Arm64) CPU cores, 4GB RAM and 40GB disk space.
-
Debian 12 Bookworm as server OS
-
The domain “jueklu.net” that’s hosted on AWS Route 53
Hetzner Cloud #
Firewall Ports #
- Open the following ports for inbound:
Service | Protocol | Port |
Postfix SMTP | TCP | 25 |
Postfix SMTPS | TCP | 465 |
Postfix Submission | TCP | 587 |
Dovecot IMAP | TCP | 143 |
Dovecot IMAPS | TCP | 993 |
Dovecot POP3 | TCP | 110 |
Dovecot POP3S | TCP | 995 |
Dovecot ManageSieve | TCP | 4190 |
HTTP | TCP | 80 |
HTTPS | TCP | 443 |
Port Details
Port Description
SMTP (Simple Mail Transfer Protocol):
- Port 25 (TCP) for SMTP: Receiving emails from other servers
- Port 587 (TCP) for Submission: For secure email submission from email clients
- Port 465 (TCP) for SMTPS: SMTP over SSL, less common but used by some clients
IMAP (Internet Message Access Protocol):
- Port 143 (TCP) for IMAP: Accessing emails from email clients
- Port 993 (TCP) for IMAPS: IMAP over SSL, for secure email access
POP3 (Post Office Protocol version 3):
- Port 110 (TCP) for POP3: Downloading emails from the server
- Port 995 (TCP) for POP3S: POP3 over SSL, for secure email downloading
- Port 4190 (TCP) for managing sieve scripts via the ManageSieve protocol
HTTP/HTTPS (for accessing the mailcow UI and webmail):
- Port 80 (TCP) for HTTP: Web interface
- Port 443 (TCP) for HTTPS: Web interface secure

- Apply the firewall to the cloud server
Reverse DNS Entry #
# Hetzner Cloud: Projects
https://console.hetzner.cloud/projects
- Go to
Networking
>Edit Reverse DNS

Port 25 and 465 #
Per default port 25 and 465 are blocked for the Hetzner cloud servers. They can be opened via the support menu (after the first bill) or after a few days if you send request per mail.
AWS Route 53: DNS Entries #
Go to Route 53
> Hosted zones
A Record (IPv4) #
Add an A record for the subdomain “mail” (mail.jueklu.net) that points to the IPv4 address of the mail server.
# Name Type Value
mail.jueklu.net A 135.181.97.75

CNAME Records #
Add CNAME records for “autodiscover” and “autoconfig” that point to your “mail” subdomain “mail.jueklu.net.” These are used by email clients for automatic discovery of mail server settings.
# Name Type Value
autodiscover CNAME mail.jueklu.net.
autoconfig CNAME mail.jueklu.net.

MX Record (Mail Exchange) #
Add an MX record that is used for routing emails.
# Name Type Value
(blank) MX 10 mail.jueklu.net.

Debian Prerequisites #
Create Swap File #
# Create swapfile
sudo fallocate -l 4G /swapfile
# Change permissions
sudo chmod 600 /swapfile
# Mark the file as swap space
sudo mkswap /swapfile
# Enable the Swapfile
sudo swapon /swapfile
# Add fstab entry
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Install Docker & Docker Compose #
- Install the Docker ARM version for Debian 12
#!/bin/bash
# REF:https://docs.docker.com/engine/install/debian/#install-using-the-repository
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Mailcow Setup #
Install Dependencies #
# Update package index
sudo apt update
# Install dependencies
sudo apt install curl git -y
Docker Compose #
- Clone Mailcow repository
# Change directory
cd /opt
# Clone the Mailcow repository
git clone https://github.com/mailcow/mailcow-dockerized
- Generate configuration
# Change directory
cd /opt/mailcow-dockerized
# Generate configuration file
./generate_config.sh
# Mail server hostname (FQDN) - this is not your mail domain, but your mail servers hostname:
mail.jueklu.net # Enter the FQDN
# Timezone [Europe/Vienna]:
Europe/Vienna # Enter timezone
# Available Branches:
# - master branch (stable updates) | default, recommended [1]
# - nightly branch (unstable updates, testing) | not-production ready [2]
# Choose the Branch with it´s number [1/2]
1 # Select master branch
# Detecting if your IP is listed on Spamhaus Bad ASN List...
# Check completed! Your IP is clean
# Check the configuration, optional change HTTPS & HTTPS ports
cat mailcow.conf
- Create / start container
# Create / start Docker stack
sudo docker compose up -d
# Check
docker ps --format '{{.Names}}'
# Shell output:
mailcowdockerized-ipv6nat-mailcow-1
mailcowdockerized-watchdog-mailcow-1
mailcowdockerized-acme-mailcow-1
mailcowdockerized-rspamd-mailcow-1
mailcowdockerized-ofelia-mailcow-1
mailcowdockerized-nginx-mailcow-1
mailcowdockerized-dovecot-mailcow-1
mailcowdockerized-postfix-mailcow-1
mailcowdockerized-php-fpm-mailcow-1
mailcowdockerized-solr-mailcow-1
mailcowdockerized-redis-mailcow-1
mailcowdockerized-mysql-mailcow-1
mailcowdockerized-clamd-mailcow-1
mailcowdockerized-dockerapi-mailcow-1
mailcowdockerized-netfilter-mailcow-1
mailcowdockerized-olefy-mailcow-1
mailcowdockerized-sogo-mailcow-1
mailcowdockerized-unbound-mailcow-1
mailcowdockerized-memcached-mailcow-1
Mailcow Configuration #
Webinterface #
# Access the Mailcow webinterface
https://mail.jueklu.net
# Default user:
admin
# Default PW:
moohoo
Admin PW & 2FA #
Go to System
> Configuration
> Access
-
Click
Edit
to change the admin password -
Click “Two-factor authentication:”
Please select
to add 2FA

Add Mail Domain #
Go to E-Mail
> Configuration
-
Select the
Domains
tab -
Click
+ Add domain

-
Add the domain “jueklu.net”
-
Click
Add domain and restart SOGo

Remainings DNS Entrys #
- Click on
DNS
to open the DNS status for the new domain

- This provides a overview for the missing DNS entries. Copy the text for the DKIM DNS entry:

DKIM DNS Entry #
-
Record name:
dkim._domainkey
-
Record type:
TXT
-
Value: Copy from Mailcow

Note: On AWS Route 53 it was necessary to split up the DKIM value into two parts in quotation marks, separated by a space. Like “part1” “part2”
For example:
"v=DKIM1; k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrL1y615QbUJEdHPfOINx" "6tBw4fFJ5YizSa/en5B5JUxpOUDGiFZWSYti4Ed+I0Y3ERUUE"
Otherwise Route 53 shows the following error:
Error occurred
Bad request.
(InvalidChangeBatch 400: CharacterStringTooLong (Value is too long)
DMARC DNS Entry #
-
Record name:
_dmarc
-
Record type:
TXT
# Value: If an email fails the DKIM and SPF tests, mark it as spam:
v=DMARC1; p=quarantine; adkim=s; aspf=s;

SPF DNS Entry #

# Add the following entry
v=spf1 a mx -all
# Link
http://www.open-spf.org/SPF_Record_Syntax/
SRV DNS Entry #
# Route 53 SRV Syntax
priority weight port target
# Example
0 0 443 mail.jueklu.net

TLSA DNS Entry #
TLSA is not supported by AWS Route 53.
Check Mailcow DNS #
Open and close the DNS section of the domain, it should look like this:

Create a Mailbox #
Go to E-Mail
> Configuration
> Mailboxes
- Click
+ Add Mailbox

-
Define the “username” (username@domain.com)
-
Define a password
-
Click
Add
to create the mailbox

Create Alias #
Optional create one or more aliases for the mailbox.
Go to E-Mail
> Configuration
> Alisas
- Click
+ Add alias


SOGO Webmail #
# Access the SoGo webinterface
https://mail.jueklu.net/SOGo/

Test Configuration #
https://mail-tester.com



Links #
# Hetzner Cloud: Pricing
https://www.hetzner.com/cloud/
# Hetzner Cloud: Login
https://accounts.hetzner.com/login
# Hetzner Cloud: Server Overview
https://console.hetzner.cloud/projects
# Mailcow Github
https://github.com/mailcow/mailcow-dockerized
# Mailcow Official Documentation
https://docs.mailcow.email/
# Mailcow Official Documentation: Ports
https://docs.mailcow.email/getstarted/prerequisite-system/#default-ports
# Mailcow Official Documentation: DNS
https://docs.mailcow.email/getstarted/prerequisite-dns/#references