Skip to main content

Mail Server

Initial

Mailcow setup

Dockerized Setup Guide (Home Server + VPS Proxy + Tailscale)

This guide installs Mailcow on your home server (behind CGNAT), with your VPS handling public-facing TLS/proxying via Caddy (web UI/webmail) and HAProxy (raw mail ports), connected over Tailscale. Sourced from the current official Mailcow docs (docs.mailcow.email) as of mid-2026.

1
-

0. Updates

Architecture overview
sudoInternet
   apt
   update
 &&VPS sudo(public aptIP)
   upgrade├── -yCaddy   → HTTPS termination for mail.seabee.me (webmail/admin UI)
   │              reverse_proxy → home server Tailscale IP:8005 (plain HTTP)
   └── HAProxy → raw TCP forward for 25 / 465 / 587 / 993 / 995 / 4190
                  → home server Tailscale IP (same ports)
                        │
                        ▼ (Tailscale tunnel)
                Home server (behind CGNAT)
                   └── Mailcow (Docker): Postfix, Dovecot, SOGo, Rspamd, ClamAV, etc.

Mailcow itself runs entirely on your home server. The VPS never stores mail — it just forwards TLS/TCP traffic through the Tailscale tunnel. This means Mailcow's own built-in Let's Encrypt client should be disabled, since Caddy on the VPS is what the outside world actually talks to on 443.

2
-

1. InstallPrerequisites

docker

Hardware (home server)

  • 2+ CPU cores (4+ for production/multiple domains)
  • 6 GB RAM minimum + 1 GB swap (8 GB recommended if running ClamAV/full-text search)
  • 20 GB disk minimum, more for mailbox storage

If your home server is resource-constrained, you can disable ClamAV and dockerfull-text composesearch in mailcow.conf (SKIP_CLAMD=y, SKIP_FTS=y) to run comfortably on ~2 GB RAM.

OS support

Mailcow supports KVM/ESXi/Hyper-V VMs and bare metal. It explicitly does not support Synology/QNAP NAS devices, OpenVZ, or LXC containers — only real Docker hosts.

Required packages

# Install required packages
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# Set up the stable repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker
sudo apt update
sudo apt install -y docker-cegit docker-ce-cliopenssl containerd.iocurl gawk coreutils grep jq

(jq is a fairly recent addition to Mailcow's requirements — make sure it's installed.)

Docker (latest engine, not distro package)

curl -sSL https://get.docker.com/ | CHANNEL=stable sh
sudo systemctl enable --now docker

Docker Compose plugin (v2.0+)

sudo apt install docker-compose-plugin
# Add your user to docker group
sudo usermod -aG docker $USER

Confirm:

3
docker compose version   # must be >= 2.0

Debian 13 (trixie) note

If you upgraded from Debian 12→13, a package called exim may get pulled in and bind port 25 on the host, blocking Mailcow's Postfix container from using it. Remove it first:

sudo apt remove --purge Createexim4 exim4-base exim4-config -y

2. DNS Records

records to configure

Set these at your domain registrar (Namecheap → Advanced DNS), pointing at your VPS's public IP (since that's what actually receives inbound connections):

# Name              Type       Value
mail                IN A       203.57.114.42
autodiscover        IN CNAME   mail.seabee.me.
autoconfig          IN CNAME   mail.seabee.me.
@                   IN MX 10   mail.seabee.me.

In Namecheap specifically

  • The A record: and CNAME records go under Advanced DNS → Host Records (Add New Record).

  • The MX record goes under Advanced DNS → Mail Settings → Custom MX, filled in as:

    FieldValue
    TypeMX Record
    Host@
    Valuemail.seabee.me.
    Priority10
    TTLAutomatic
  • Important: the MX record only resolves correctly if the mail A record above already exists — MX points to a hostname, not an IP directly.

  • Check Host Records for a stray CNAME on @ (bare domain) — Namecheap gives CNAME priority over MX on the same host, which silently breaks mail delivery if one exists.

SPF, DKIM, DMARC

@                   IN TXT     "v=spf1 mx a -all"
_dmarc              IN TXT     "v=DMARC1; p=reject; rua=mailto:postmaster@seabee.me"

Both go under Host Records as TXT records. DKIM is generated inside the Mailcow admin UI after install (Configuration → ARC/DKIM keys) — you'll copy that TXT record in afterward, also as a Host Record.

Reverse DNS (PTR)

Critical for deliverability: your VPS provider, not your DNS zone, controls this — PTR belongs to whoever owns the IP block. The PTR record needs to resolve 203.57.114.42 back to mail.yourdomain.comseabee.me.

On Binary Lane: mPanel → Network/IP settings → the "Reverse DNS" field next to your public IPv4 address. Edit it and set it to mail.seabee.me. Binary Lane uses a 12-hour TTL for PTR records, so allow up to half a day for it to propagate. Set the mail A record first — forward and reverse should match, and some providers expect the forward record to already resolve.

Verify once propagated:

dig +short mail.seabee.me        # → your serverVPS IP
  • MXdig record:+short @-x 203.57.114.42 #mail.seabee.me.
  • Changing the PTR only affects reverse lookups on that IP — any other hostnames already pointing at the same IP (e.g. a mail.yourdomain.comvps.seabee.me (priorityyou 10)use

  • TXTfor recordSSH) (SPF):keep v=spf1working mxexactly ~all
  • as before,

    since
    4 - InstallPTR and configureA mailserver
    records are independent.

    Optional but recommended: autoconfig SRV records

    Full zone-file form:

    #_autodiscover._tcp  CreateIN directorySRV  0 1 443  mail.seabee.me.
    _imaps._tcp         IN SRV  0 1 993  mail.seabee.me.
    _pop3s._tcp         IN SRV  0 1 995  mail.seabee.me.
    _submission._tcp    IN SRV  0 1 587  mail.seabee.me.
    _submissions._tcp   IN SRV  0 1 465  mail.seabee.me.
    _sieve._tcp         IN SRV  0 1 4190 mail.seabee.me.
    

    In Namecheap, SRV records use separate fields rather than one string. Add each one under Host Records → Add New Record → SRV Record:

    ServiceProtocolPriorityWeightPortTarget
    _autodiscover_tcp01443mail.seabee.me
    _imaps_tcp01993mail.seabee.me
    _pop3s_tcp01995mail.seabee.me
    _submission_tcp01587mail.seabee.me
    _submissions_tcp01465mail.seabee.me
    _sieve_tcp014190mail.seabee.me

    These aren't required for mail to function — the autodiscover/autoconfig CNAMEs above already cover most clients — but they add broader compatibility (notably Outlook via _autodiscover). Fine to add later once core mail delivery is confirmed working.


    3. Install Mailcow on the home server

    umask 0022
    mkdir -p ~/mailserverhome/conor/Docker
    cd ~/mailserverhome/conor/Docker
    #git Download docker-compose.yml and .env template
    wgetclone https://raw.githubusercontent.github.com/docker-mailserver/docker-mailserver/master/compose.yamlmailcow/mailcow-dockerized wgetmailcow
    https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/mailserver.envcd # Rename for easier use
    mv compose.yaml docker-compose.yml
    mv mailserver.envmailcow
    .env/generate_config.sh
    

    Note: Mailcow's own docs default to /opt/mailcow-dockerized, but any path works — Mailcow doesn't hardcode /opt anywhere; it just uses whatever directory you run generate_config.sh and docker compose from. The only requirement is that the user running these commands has read/write access to the directory and to the Docker socket (i.e. is in the docker group, or you run the commands with sudo).

    5

    You'll -be Editprompted .env variables

    for:

    • Mailcow hostname → enter HOSTNAME=mailmail.seabee.me (must match your DNS A/MX records)
    • DOMAINNAME=yourdomain.com
    • OVERRIDE_HOSTNAME=mail.yourdomain.com
    • ENABLE_SPAMASSASSIN=1
    • ENABLE_CLAMAV=1
    • ENABLE_FAIL2BAN=1
    • SSL_TYPE=letsencrypt (or manual if you have your own certs)
    • ACCOUNT_PROVISIONER=FILE Timezone

    This creates mailcow.conf.

    6
    -

    4. Edit mailcow.conf — key settings for your proxy setup

    nano mailcow.conf
    

    Change/confirm these values:

    MAILCOW_HOSTNAME=mail.seabee.me
    
    # Disable Mailcow's built-in Let's Encrypt — Caddy on the VPS handles TLS instead
    SKIP_LETS_ENCRYPT=y
    
    # Skip the public-IP-matches-DNS check, since this host is behind CGNAT
    SKIP_IP_CHECK=y
    
    # Disable IPv6 — nothing in the VPS→Tailscale→home path uses it, and half-enabling
    # it (detected but not configured in Docker's daemon.json) just invites confusion
    ENABLE_IPV6=false
    
    # nginx (webmail/admin UI) — scoped to this host's Tailscale IP only.
    # This is the ONLY service where mailcow.conf controls the bind address directly;
    # Postfix/Dovecot ports have no _BIND variable and are handled in the Docker
    # Compose override file instead (see Section 5).
    HTTP_BIND=100.64.0.3
    HTTP_PORT=8005
    HTTPS_BIND=100.64.0.3
    HTTPS_PORT=8443
    
    # Adjust if these clash with anything else on your Docker host
    IPV4_NETWORK=172.22.1
    

    Replace 100.64.0.3 with your home server's actual Tailscale IP (tailscale ip -4).

    Why SKIP_LETS_ENCRYPT=y: Mailcow's ACME client tries to prove domain ownership by responding on port 443 with the host's own certificate. Since the VPS (via Caddy) is what the public internet actually reaches, Mailcow's own ACME client would fail here anyway — Caddy already handles issuance/renewal for mail.seabee.me.

    Why HTTP_PORT=8005 rather than the Mailcow default of 8080: purely to avoid clashing with anything else already using 8080 on this host — pick whatever's free on your system, just make sure the same number is used consistently in the Caddy reverse_proxy line in Section 8.


    5. Bind Postfix/Dovecot ports to Tailscale only

    By default, Mailcow's docker-compose.yml binds mail ports to all interfaces (0.0.0.0). Since your home server sits behind CGNAT, nothing on the raw internet can reach these ports regardless — but leaving them on 0.0.0.0 still means every device on your home LAN and every peer on your tailnet can connect to them directly, bypassing HAProxy entirely. Scoping to the Tailscale IP limits that down to just the VPS.

    Only Postfix and Dovecot need this override. nginx (webmail/admin UI) is already scoped via HTTP_BIND/HTTPS_BIND in mailcow.conf (Section 4) — that's the only service where the base docker-compose.yml exposes a bind-address variable. Postfix and Dovecot's port lines have no such variable, so a Compose override is the only way to restrict them.

    Get your home server's Tailscale IP:

    tailscale ip -4
    

    Create docker-compose.override.yml in the same folder as docker-compose.yml (never edit docker-compose.yml directly — ./update.sh overwrites it on every update, but the override file is preserved):

    services:
      mailserver:
        image: ghcr.io/docker-mailserver/docker-mailserver:latest
        container_name: mailserver
        # Provide the FQDN of your mail server here (Your DNS MX record should point to this value)
        hostname: mx.home.conorbriggs.com.au
        env_file: .env
        # More information about the mail-server ports:
        # https://docker-mailserver.github.io/docker-mailserver/latest/config/security/understanding-the-ports/postfix-mailcow:
        ports:
          - "100.64.0.3:25:25"    # SMTP  (explicit TLS => STARTTLS, Authentication is DISABLED => use port 465/587 instead)
          - "143:143"  # IMAP4 (explicit TLS => STARTTLS)100.64.0.3:465:465"
          - "465:465"100.64.0.3:587:587"
      #dovecot-mailcow:
        ESMTP (implicit TLS)ports:
          - "587:587"  # ESMTP (explicit TLS => STARTTLS)100.64.0.3:993:993"
          - "993:993"  # IMAP4 (implicit TLS)
        volumes:100.64.0.3:995:995"
          - ./mail-data/:/var/mail/
          - ./mail-state/:/var/mail-state/
          - ./mail-logs/:/var/log/mail/
          - ./config/:/tmp/docker-mailserver/
          - /etc/localtime:/etc/localtime:ro
          - /etc/letsencrypt:/etc/letsencrypt:ro
        restart: always
        stop_grace_period: 1m
        # Uncomment if using `ENABLE_FAIL2BAN=1`:
        cap_add:
          - NET_ADMIN
        healthcheck:
          test: "ss --listening --ipv4 --tcp | grep --silent ':smtp' || exit 1"
          timeout: 3s
          retries: 0
        networks:
          - mailserver-network
    networks:
      mailserver-network:
        driver: bridge100.64.0.3:4190:4190"
    

    Replace 100.64.0.3 with your home server's actual Tailscale IP. If you also want LAN clients (phones/laptops on your home WiFi) to connect directly without going through the VPS, add a second binding per port using your LAN IP instead of, or alongside, the Tailscale one.

    Apply it:


    Connecting

    IMAP (Incoming):

    • Server: mx.home.conorbriggs.com.au
    • Port: 993 (IMAPS with SSL/TLS)
    • Security: SSL/TLS
    • Authentication: Normal password

    SMTP (Outgoing):

    • Server: mx.home.conorbriggs.com.au
    • Port: 587 (with STARTTLS) or 465 (with SSL/TLS)
    • Security: STARTTLS (port 587) or SSL/TLS (port 465)
    • Authentication: Normal password

    Container Management

    Basic Container Operations


    Start the mailserver 
    docker compose up -d
    docker compose ps
    

    Compose

    recreates
    Stoponly the mailserver
    containers
    dockerwhose composeconfig down
    changed.


    RestartVerify the mailserver
    bindings
    dockerlanded composeon restart
    the


    right
    View logs (live)
    docker compose logs -f


    View logs (last 100 lines)interface:

    docker compose logs --tail=100


    Check container status
    docker ps -a


    Check container health
    docker inspect mailserver | grep -A 10 Health



     

    Email Account Management

    Create Email Accounts

     

    Create a new email account (will prompt for password)
    docker exec -it mailserver setup email add user@home.conorbriggs.com.au

     

    Create account with password in command
    docker exec -it mailserver setup email add user@home.conorbriggs.com.au password123

     

    Create account with quota (e.g., 500MB)
    docker exec -it mailserver setup email add user@home.conorbriggs.com.au password123 500M

     

    List Email Accounts

     

    List all email accounts
    docker exec mailserver setup email list

     

    View the accounts file directly
    docker exec mailserver cat /tmp/docker-mailserver/postfix-accounts.cf

     

    Update/Change Passwords

     

    Update password for existing account
    docker exec -it mailserver setup email update user@home.conorbriggs.com.au new_password

     

    Change password (alternative method - will prompt)
    docker exec -it mailserver setup email update user@home.conorbriggs.com.au

     

    Delete Email Accounts

     

    Delete an email account
    docker exec -it mailserver setup email del user@home.conorbriggs.com.au

     

    Delete account and remove mailbox data
    docker exec mailserver setup email del user@home.conorbriggs.com.au
    rm -rf ./mail-data/home.conorbriggs.com.au/user

     


     

    Alias Management

    Create Aliases

     

    Create an alias (forward emails from alias to recipient)
    docker exec mailserver setup alias add alias@home.conorbriggs.com.au recipient@home.conorbriggs.com.au

     

    Create alias with multiple recipients
    docker exec mailserver setup alias add sales@home.conorbriggs.com.au "user1@home.conorbriggs.com.au,user2@home.conorbriggs.com.au"

     

    List Aliases

     

    List all aliases
    docker exec mailserver setup alias list

     

    View aliases file
    docker exec mailserver cat /tmp/docker-mailserver/postfix-virtual.cf

     

    Delete Aliases

     

    Delete an alias
    docker exec mailserver setup alias del alias@home.conorbriggs.com.au recipient@home.conorbriggs.com.au

     


     

    Quota Management

    Set Quotas

     

    Set quota for a user (e.g., 1GB)
    docker exec mailserver setup quota set user@home.conorbriggs.com.au 1G

     

    Set unlimited quota
    docker exec mailserver setup quota set user@home.conorbriggs.com.au 0

     

    Check Quotas

     

    Check quota for specific user
    docker exec mailserver setup quota get user@home.conorbriggs.com.au

     

    List all quotas
    docker exec mailserver setup quota list

     

    Check quota usage
    docker exec mailserver doveadm quota get -u user@home.conorbriggs.com.au

     

    Delete Quotas

     

    Remove quota (sets to default)
    docker exec mailserver setup quota del user@home.conorbriggs.com.au

     


     

    DKIM (Email Signing)

    Generate DKIM Keys

     

    Generate DKIM key for domain
    docker exec mailserver setup config dkim

     

    Generate for specific domain
    docker exec mailserver setup config dkim domain home.conorbriggs.com.au

     

    Generate with custom key size
    docker exec mailserver setup config dkim keysize 2048

     

    View DKIM Public Key

     

    Show DKIM DNS record
    docker exec mailserver setup config dkim help

     

    View the public key directly
    docker exec mailserver cat /tmp/docker-mailserver/opendkim/keys/home.conorbriggs.com.au/mail.txt

     


     

    Fail2Ban (Security)

    Fail2Ban Status

     

    Check fail2ban status
    docker exec mailserver setup fail2ban status

     

    Check banned IPs
    docker exec mailserver setup fail2ban

     

    Unban an IP address
    docker exec mailserver setup fail2ban unban <IP_ADDRESS>

     

    Ban an IP address
    docker exec mailserver setup fail2ban ban <IP_ADDRESS>

     


     

    Debugging & Diagnostics

    Service Status

     

    Check all listening ports
    docker exec mailserver ss -tlnp

     

    Check specific service status
    docker exec mailserver supervisorctl status

     

    Check Postfix status
    docker exec mailserver postfix status

     

    Check Dovecot status
    docker exec mailserver doveadm service status

     

    Mail Queue

     

    View mail queue
    docker exec mailserver postqueue -p

     

    Flush mail queue (retry sending)
    docker exec mailserver postqueue -f

     

    Delete all queued mail
    docker exec mailserver postsuper -d ALL

     

    Delete specific message from queue
    docker exec mailserver postsuper -d <QUEUE_ID>

     

    Logs

     

    View mail logs
    docker exec mailserver tail -f /var/log/mail/mail.log

     

    View mail errors
    docker exec mailserver tail -f /var/log/mail/mail.err

     

    View specific log files
    docker exec mailserver ls -la /var/log/mail/

     

    Search logs for specific email
    docker exec mailserver grep "user@domain.com" /var/log/mail/mail.log

     

    Test Email Delivery

     

    Test SMTP connection
    docker exec mailserver nc -zv localhost 25

     

    Send test email from command line
    echo "Test email body" | docker exec -i mailserver sendmail test@home.conorbriggs.com.au

     

    Test with swaks (if installed)
    docker exec mailserver swaks --to user@home.conorbriggs.com.au --from test@home.conorbriggs.com.au

     

    Connection Testing

     

    Test IMAP connection
    docker exec mailserver nc -zv localhost 143
    docker exec mailserver nc -zv localhost 993

     

    Test SMTP connection
    docker exec mailserver nc -zv localhost 25
    docker exec mailserver nc -zv localhost 587
    docker exec mailserver nc -zv localhost 465

     

    Check TLS/SSL certificates
    docker exec mailserver openssl s_client -connect localhost:993 -showcerts
    docker exec mailserver openssl s_client -connect localhost:465 -showcerts

     


     

    Configuration Management

    Reload Configuration

     

    Reload postfix configuration
    docker exec mailserver postfix reload

     

    Reload dovecot configuration
    docker exec mailserver doveadm reload

     

    Restart all services
    docker compose restart

     

    View Configuration

     

    View postfix configuration
    docker exec mailserver postconf

     

    View dovecot configuration
    docker exec mailserver doveconf

     

    View specific postfix setting
    docker exec mailserver postconf | grep smtp_tls

     

    Check all environment variables
    docker exec mailserver envtlpn | grep -E '(SMTP|IMAP|SSL|TLS)'25|465|587|993|995|4190|8005|8443'
    

    You should see 100.64.0.3 (not 0.0.0.0) next to each port.

    Backup
    Configuration

    6. Home server firewall

    Restrict inbound access on these ports to just your VPS's Tailscale IP, since that's the only legitimate source of forwarded traffic:

    Backup all mail data
    tarsudo -czfufw mailserver-backup-$(dateallow +%Y%m%d).tar.gzfrom ./mail-data<VPS_TAILSCALE_IP> ./mail-stateto ./configany port 25,465,587,993,995,4190,8005,8443 proto tcp
    

    (Adjust

    for
    Backupiptables/nftables justif configuration
    tar -czf mailserver-config-$(date +%Y%m%d).tar.gz ./config

     

    Backup specific user'that's mailbox
    what
    taryou're -czfrunning user-backup-$(date +%Y%m%d).tar.gz ./mail-data/home.conorbriggs.com.au/user

     instead.)


    7.

    Start

    Database/User Management

    User Database

     

    List all users in Dovecot
    Mailcow
    docker exec mailserver doveadm user '*'

     

    Check if user exists
    docker exec mailserver doveadm user user@home.conorbriggs.com.au

     

    View user's mailbox location
    docker exec mailserver doveadm mailbox status -u user@home.conorbriggs.com.au all '*'

     

    Mailbox Management

     

    List mailboxes for user
    docker exec mailserver doveadm mailbox list -u user@home.conorbriggs.com.au

     

    Create mailbox for user
    docker exec mailserver doveadm mailbox create -u user@home.conorbriggs.com.au Folder.Name

     

    Delete mailbox
    docker exec mailserver doveadm mailbox delete -u user@home.conorbriggs.com.au Folder.Name

     

    Rebuild mailbox index
    docker exec mailserver doveadm force-resync -u user@home.conorbriggs.com.au INBOX

     


     

    Performance & Monitoring

    Check Resource Usage

     

    Check container stats
    docker stats mailserver

     

    Check disk usage
    docker exec mailserver df -h

     

    Check memory usage
    docker exec mailserver free -h

     

    Check mail directory size
    du -sh ./mail-data/*

     

    Connection Monitoring

     

    Show active connections
    docker exec mailserver ss -tn | grep -E ':(25|587|465|143|993)'

     

    Count connections by port
    docker exec mailserver ss -tn | grep -E ':(25|587|465|143|993)' | wc -l

     

    Show who's connected to IMAP
    docker exec mailserver doveadm who

     


     

    SSL/TLS Certificate Management

    Check Certificates

     

    Check SSL certificate expiry
    docker exec mailserver openssl x509 -in /etc/letsencrypt/live/mx.home.conorbriggs.com.au/fullchain.pem -noout -dates

     

    View certificate details
    docker exec mailserver openssl x509 -in /etc/letsencrypt/live/mx.home.conorbriggs.com.au/fullchain.pem -noout -text

     

    Test SSL/TLS for SMTP
    openssl s_client -connect mx.home.conorbriggs.com.au:465 -showcerts

     

    Test STARTTLS for SMTP
    openssl s_client -connect mx.home.conorbriggs.com.au:587 -starttls smtp

     


     

    Troubleshooting

    Common Issues

     

    Check if services are running
    docker exec mailserver supervisorctl status

     

    Restart specific service
    docker exec mailserver supervisorctl restart postfix
    docker exec mailserver supervisorctl restart dovecot

     

    Check for permission issues
    docker exec mailserver ls -la /var/mail/
    docker exec mailserver ls -la /tmp/docker-mailserver/

     

    Verify DNS records
    dig mx home.conorbriggs.com.au
    dig txt _dmarc.home.conorbriggs.com.au
    dig txt mail._domainkey.home.conorbriggs.com.au

     

    Test email authentication
    docker exec mailserver opendkim-testkey -d home.conorbriggs.com.au -s mail

     

    Reset and Clean Up

     

    Remove all mail data (WARNING: deletes all emails)
    docker compose down
    rm -rf ./mail-data/*
    rm -rf ./mail-state/*
    docker compose up -d

     

    Clear logs
    docker exec mailserver truncate -s 0 /var/log/mail/mail.log

     

    Rebuild entire container
    docker compose down
    docker compose pull
    docker compose up -d
    --force-recreatedocker compose ps
    

    You should see 15+ containers reporting Up.


    8.

    VPS side — wire up Caddy and HAProxy

    QuickCaddy Reference(web UI / webmail / autodiscover — HTTPS termination)

    Setup

    Add Scripta Help

    new

    site block to your existing Caddyfile:

    Show all setup commands
    dockermail.seabee.me exec{
        mailserverreverse_proxy setup100.64.0.3:8005
    help}
    
    autodiscover.seabee.me, autoconfig.seabee.me {
        reverse_proxy 100.64.0.3:8005
    }
    

    Caddy

    handles
    Helpthe ACME cert issuance/renewal automatically here, same as your other sites — no extra config needed for specificthat command
    part.

    HAProxy (raw mail ports — TCP passthrough)

    This is the same pattern from your earlier HAProxy config — just confirm the backend IPs point at your home server's Tailscale IP and the ports match Mailcow's:

    dockerfrontend execsmtp_in
        mailservermode setuptcp
        emailoption helptcplog
        dockerbind exec*:25
        mailserverdefault_backend setupsmtp_home
    aliasbackend helpsmtp_home
        dockermode exectcp
        mailserverserver setuphome config100.64.0.3:25 helpcheck
    
    frontend smtp_submission_in
        mode tcp
        option tcplog
        bind *:587
        default_backend smtp_submission_home
    backend smtp_submission_home
        mode tcp
        server home 100.64.0.3:587 check
    
    frontend smtps_in
        mode tcp
        option tcplog
        bind *:465
        default_backend smtps_home
    backend smtps_home
        mode tcp
        server home 100.64.0.3:465 check
    
    frontend imaps_in
        mode tcp
        option tcplog
        bind *:993
        default_backend imaps_home
    backend imaps_home
        mode tcp
        server home 100.64.0.3:993 check
    
    frontend pop3s_in
        mode tcp
        option tcplog
        bind *:995
        default_backend pop3s_home
    backend pop3s_home
        mode tcp
        server home 100.64.0.3:995 check
    
    frontend sieve_in
        mode tcp
        option tcplog
        bind *:4190
        default_backend sieve_home
    backend sieve_home
        mode tcp
        server home 100.64.0.3:4190 check
    

    Reload HAProxy:

    File Locations Inside Container

    /tmp/docker-mailserver/sudo - Configuration files (mapped to ./config/)
    /var/mail/                        - Mail data (mapped to ./mail-data/)
    /var/mail-state/                  - State files (mapped to ./mail-state/)
    /var/log/mail/                    - Mail logs (mapped to ./mail-logs/)
    /etc/letsencrypt/                 - SSL certificates (read-only)
    /etc/postfix/                     - Postfix configuration
    /etc/dovecot/                     - Dovecot configuration

     

    Important Configuration Files

    ./config/postfix-accounts.cf      - Email accounts
    ./config/postfix-virtual.cf       - Aliases
    ./config/dovecot-quotas.cf        - User quotas
    ./config/opendkim/                - DKIM keys

     


     

    Advanced Operations

    Database Operations

     

    Export all accounts
    docker exec mailserver cat /tmp/docker-mailserver/postfix-accounts.cf > accounts-backup.txt

     

    Import accounts
    cat accounts-backup.txt | docker exec -i mailserver tee /tmp/docker-mailserver/postfix-accounts.cf
    docker compose restart

     

    Verify account database
    docker exec mailserver postmap -q user@home.conorbriggs.com.au /tmp/docker-mailserver/postfix-accounts.cf

     

    Custom Scripts

     

    Run custom maintenance script
    docker exec mailserver /bin/bashhaproxy -c "your-script-here"

     

    Execute interactive shell
    docker exec -it mailserver /bin/bash

     


     

    Monitoring & Alerts

    Set Up Monitoring

     

    Watch logs in real-time
    docker compose logs -f --tail=100

     

    Monitor for failed logins
    docker exec mailserver tail -f /var/log/mail/mail.logetc/haproxy/haproxy.cfg
    |sudo grepsystemctl "authenticationreload failed"haproxy
    

    On send-proxy: as covered before, only add this once Postfix/Dovecot on the home server are explicitly configured with postscreen_upstream_proxy_protocol = haproxy / haproxy_trusted_networks. Get everything working without it first.

    Monitor

    VPS mail queue size

    firewall
    watchsudo -nufw 60allow 'docker25,465,587,993,995,4190/tcp
    exec mailserver postqueue -p | tail -1'

    (80/443

    should
    Checkalready be open for errors
    Caddy.)


    9. First login

    dockerhttps://mail.seabee.me/admin
    exec mailserver grep -i error /var/log/mail/mail.log | tail -20

    Default credentials: admin / moohoo — change this immediately under Configuration → Access → Admin details.


    10.

    Post-install

    Commonchecklist

    Workflows

      Adding
    • DKIM: generate a Newkey User
    • in

      the

      admin
      1.UI Create(Configuration account
      → ARC/DKIM keys), then add the TXT record it gives you to your DNS
    • Change the default admin password (step 9)
    • Fail2Ban: built into Mailcow, verify it's enabled in the admin panel
    • Watchdog notifications: configure so you get alerted if a component goes down
    • Updates: run ./update.sh from /home/conor/Docker/mailcow monthly at minimum; more often for security patches

    11. Testing

    docker# execFrom an external machine, confirm each port reaches Mailcow
    openssl s_client -itstarttls mailserversmtp setup-connect emailmail.seabee.me:587
    addopenssl newuser@home.conorbriggs.com.aus_client -connect mail.seabee.me:993
    

    DNS/deliverability checks:

    2.
    dockerMX, execSPF, mailserverblacklist setupcheck
    quota
  • Mail-tester.com set newuser@home.conorbriggs.com.ausend 2G
  • a

    test

    email,
    3.get Verifya accountdeliverability created
    score
    dockercovering execSPF/DKIM/DMARC
    mailserver setup email list

     

    4. Test login: Use an email client

  • Send to connectcheck-auth@verifier.port25.com viafor IMAPa (993) or SMTP (587)

     

    Migrating Mail

     

    1. Backup old server
    tar -czf old-mailserver-backup.tar.gz ./mail-data

     

    2. Copy to new server
    scp old-mailserver-backup.tar.gz newserver:/path/to/mailserver/

     

    3. Extract on new server
    tar -xzf old-mailserver-backup.tar.gz

     

    4. Fix permissions
    chown -R 5000:5000 ./mail-data

     

    5. Restart mailserver
    docker compose restart

     

    Security Hardening

     

    1. Enable Fail2Ban (in .env file)
    ENABLE_FAIL2BAN=1

     

    2. Check banned IPs regularly
    docker exec mailserver fail2ban-client status postfix-sasl

     

    3. Monitorraw authentication attempts
    report
  • docker exec mailserver grep "authentication failed" /var/log/mail/mail.log

     

    4. Review SSL/TLS settings
    docker exec mailserver postconf | grep tls

     


    Quick

    reference:

    Tipsport &map

    BestPractices
    1. Always
    2. backupbeforechanges:-czfbackup.tar.gz./mail-data./config
    3. Test
    4. flowafterSendemailsin/out
    5. Monitor
    6. diskspace:df-hregularly
    7. Keep
    8. certificatesupdated:Encryptcertsexpireevery90dayslogsperiodically:Lookforauthenticationfailuresdeliveryissues
    9. Set
    10. appropriatequotas:Preventfromfillingupdisk
    11. Use
    12. strongMinimum12charactersfor
      Service Port VPS majorcomponent Forwards tarto
      Webmail/Admin emailUI 443 Caddy changes:(HTTPS) home:8005 test(HTTP)
      SMTP 25 HAProxy Check(TCP) home:25
      Submission 587 HAProxy Let's(TCP) home:587
      SMTPS 465 HAProxy
    13. Review(TCP)
    14. home:465
      IMAPS 993 HAProxy or(TCP) home:993
      POP3S 995 HAProxy users(TCP) home:995
      ManageSieve 4190 HAProxy passwords:(TCP) home:4190
      email accounts
    15. Enable DKIM/SPF/DMARC: Improves deliverability
    16. Regular updates: docker compose pull && docker compose up -d
    17. Document your changes: Keep notes on custom configurations