roundcube mail01 / mail-fetch01 db-mail mail01 / mail-fetch01 mail-fetch / interner Mailstack mail01 / mail-fetch01
Find a file
2026-09-08 09:58:36 +02:00
backup Mailserver aufgebaut 2026-09-08 09:58:36 +02:00
compose/mail Mailserver aufgebaut 2026-09-08 09:58:36 +02:00
config Mailserver aufgebaut 2026-09-08 09:58:36 +02:00
data Mailserver aufgebaut 2026-09-08 09:58:36 +02:00
scripts Mailserver aufgebaut 2026-09-08 09:58:36 +02:00
README.md Mailserver aufgebaut 2026-09-08 09:58:36 +02:00

Perfekt. Dann bekommst du jetzt das komplette Zielbild fuer den Mailserver auf 10.100.20.16 mit:

  • Zielstruktur auf der VM
  • Repo-Struktur analog zu deinen Infra-Repos
  • Compose-Dateien
  • Config-Grundstruktur
  • Scripts fuer Verzeichnisse und Deployment
  • Certbot-Pfade passend zu
    • /srv/mail-fetch01/data/mailserver/certs/fullchain.pem
    • /srv/mail-fetch01/data/mailserver/certs/privkey.pem

Ich halte es bewusst so, dass du es sauber ins Repo legen, pushen und auf der Mail-VM deployen kannst.


1. Zielbild

Dienste

  • mailserver mit docker-mailserver
  • db-mail fuer Roundcube
  • roundcube

Domains

  • Mailserver: mail.theboxhub.ch
  • Webmail: webmail.theboxhub.ch
  • Maildomain: theboxhub.ch

DNS

  • mail.theboxhub.ch -> 10.100.20.16
  • webmail.theboxhub.ch -> 10.100.20.10
  • MX theboxhub.ch -> mail.theboxhub.ch

Zertifikate lokal auf der Mail-VM

  • /srv/mail-fetch01/data/mailserver/certs/fullchain.pem
  • /srv/mail-fetch01/data/mailserver/certs/privkey.pem

2. Repo-Struktur

Ich schlage fuer dein Repo vor:

/srv/workspace/infra/mail-fetch01/
├── backup
│   ├── compose
│   ├── databases
│   ├── mailserver
│   └── roundcube
├── compose
│   ├── mailserver
│   │   └── compose.yaml
│   ├── mariadb
│   │   └── compose.yaml
│   └── roundcube
│       └── compose.yaml
├── config
│   ├── mailserver
│   │   ├── postfix-main.cf
│   │   ├── postfix-master.cf
│   │   ├── dovecot.cf
│   │   ├── fetchmailrc
│   │   └── .gitkeep
│   ├── mariadb
│   │   └── .gitkeep
│   └── roundcube
│       └── .gitkeep
├── data
│   ├── mailserver
│   │   ├── certs
│   │   ├── config
│   │   ├── dkim
│   │   ├── logs
│   │   ├── maildata
│   │   └── state
│   ├── mariadb
│   │   └── .gitkeep
│   └── roundcube
│       └── .gitkeep
├── README.md
└── scripts
    ├── deploy.sh
    └── init-dirs.sh

Wichtig:

  • im Repo sind data/... und backup/... nur Strukturplatzhalter
  • echte produktive Daten liegen spaeter auf der VM unter /srv/mail-fetch01/...

3. Repo-Struktur in code-server anlegen

Wenn du das Repo unter /srv/workspace/infra/mail-fetch01 vorbereitest:

cd /srv/workspace/infra
mkdir -p mail-fetch01
cd /srv/workspace/infra/mail-fetch01

mkdir -p backup/{compose,databases,mailserver,roundcube}
mkdir -p compose/{mailserver,mariadb,roundcube}
mkdir -p config/mailserver
mkdir -p config/{mariadb,roundcube}
mkdir -p data/mailserver/{certs,config,dkim,logs,maildata,state}
mkdir -p data/mariadb
mkdir -p data/roundcube
mkdir -p scripts

touch compose/mailserver/compose.yaml
touch compose/mariadb/compose.yaml
touch compose/roundcube/compose.yaml

touch config/mailserver/postfix-main.cf
touch config/mailserver/postfix-master.cf
touch config/mailserver/dovecot.cf
touch config/mailserver/fetchmailrc

touch config/mariadb/.gitkeep
touch config/roundcube/.gitkeep

touch data/mailserver/certs/.gitkeep
touch data/mailserver/config/.gitkeep
touch data/mailserver/dkim/.gitkeep
touch data/mailserver/logs/.gitkeep
touch data/mailserver/maildata/.gitkeep
touch data/mailserver/state/.gitkeep
touch data/mariadb/.gitkeep
touch data/roundcube/.gitkeep

touch scripts/init-dirs.sh
touch scripts/deploy.sh
touch README.md

4. Zielstruktur auf der Mail-VM

Das wird spaeter durch init-dirs.sh erzeugt:

/srv/mail-fetch01/
├── backup
│   ├── compose
│   ├── databases
│   ├── mailserver
│   └── roundcube
├── compose
│   ├── mailserver
│   ├── mariadb
│   └── roundcube
├── config
│   ├── mailserver
│   ├── mariadb
│   └── roundcube
└── data
    ├── mailserver
    │   ├── certs
    │   ├── config
    │   ├── dkim
    │   ├── logs
    │   ├── maildata
    │   └── state
    ├── mariadb
    └── roundcube

5. scripts/init-dirs.sh

Datei: /srv/workspace/infra/mail-fetch01/scripts/init-dirs.sh

#!/usr/bin/env bash
set -euo pipefail

echo "Erstelle Verzeichnisstruktur unter /srv/mail-fetch01 ..."

sudo mkdir -p /srv/mail-fetch01/backup/{compose,databases,mailserver,roundcube}
sudo mkdir -p /srv/mail-fetch01/compose/{mailserver,mariadb,roundcube}
sudo mkdir -p /srv/mail-fetch01/config/{mailserver,mariadb,roundcube}

sudo mkdir -p /srv/mail-fetch01/data/mailserver/{certs,config,dkim,logs,maildata,state}
sudo mkdir -p /srv/mail-fetch01/data/mariadb
sudo mkdir -p /srv/mail-fetch01/data/roundcube

echo "Setze Besitz auf aktuellen Benutzer: $USER"
sudo chown -R "$USER:$USER" /srv/mail-fetch01

echo "Fertig."
tree /srv/mail-fetch01 || true

Ausfuehrbar machen:

chmod +x /srv/workspace/infra/mail-fetch01/scripts/init-dirs.sh

6. scripts/deploy.sh

Datei: /srv/workspace/infra/mail-fetch01/scripts/deploy.sh

#!/usr/bin/env bash
set -euo pipefail

REPO_ROOT="/srv/workspace/infra/mail-fetch01"
TARGET_ROOT="/srv/mail-fetch01"

echo "Deploye Compose-Dateien ..."
sudo mkdir -p "$TARGET_ROOT/compose"
sudo cp -r "$REPO_ROOT/compose/." "$TARGET_ROOT/compose/"

echo "Deploye Konfigurationen ..."
sudo mkdir -p "$TARGET_ROOT/config"
sudo cp -r "$REPO_ROOT/config/." "$TARGET_ROOT/config/"

echo "Setze Besitz auf aktuellen Benutzer: $USER"
sudo chown -R "$USER:$USER" "$TARGET_ROOT"

echo "Fertig."

Ausfuehrbar machen:

chmod +x /srv/workspace/infra/mail-fetch01/scripts/deploy.sh

7. Compose mailserver

Datei: /srv/workspace/infra/mail-fetch01/compose/mailserver/compose.yaml

x-logging: &default-logging
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

services:
  mailserver:
    image: mailserver/docker-mailserver:latest
    container_name: mailserver
    hostname: mail
    domainname: theboxhub.ch
    restart: unless-stopped
    stop_grace_period: 1m
    dns:
      - 10.100.20.49
      - 1.1.1.1
    environment:
      TZ: Europe/Zurich
      ENABLE_FETCHMAIL: 1
      FETCHMAIL_POLL: 60
      OVERTAKE_IP: 1
      ENABLE_SPAMASSASSIN: 1
      ENABLE_CLAMAV: 0
      SSL_TYPE: manual
      SSL_CERT_PATH: /etc/letsencrypt/live/mailserver/fullchain.pem
      SSL_KEY_PATH: /etc/letsencrypt/live/mailserver/privkey.pem
      PERMIT_DOCKER: connected-networks
      ONE_DIR: 1
      DMS_DEBUG: 0
    ports:
      - "25:25"
      - "143:143"
      - "465:465"
      - "587:587"
      - "993:993"
    volumes:
      - /srv/mail-fetch01/data/mailserver/maildata:/var/mail
      - /srv/mail-fetch01/data/mailserver/config:/tmp/docker-mailserver
      - /srv/mail-fetch01/data/mailserver/state:/var/mail-state
      - /srv/mail-fetch01/data/mailserver/logs:/var/log/mail
      - /srv/mail-fetch01/data/mailserver/dkim:/etc/opendkim/keys
      - /srv/mail-fetch01/data/mailserver/certs/fullchain.pem:/etc/letsencrypt/live/mailserver/fullchain.pem:ro
      - /srv/mail-fetch01/data/mailserver/certs/privkey.pem:/etc/letsencrypt/live/mailserver/privkey.pem:ro
    cap_add:
      - NET_ADMIN
      - SYS_PTRACE
    healthcheck:
      test: ["CMD-SHELL", "ss -ltn | grep -q ':25' || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s
    logging: *default-logging

8. Compose MariaDB fuer Roundcube

Datei: /srv/workspace/infra/mail-fetch01/compose/mariadb/compose.yaml

x-logging: &default-logging
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

services:
  db-mail:
    image: mariadb:10.11
    container_name: db-mail
    restart: unless-stopped
    environment:
      TZ: Europe/Zurich
      MYSQL_ROOT_PASSWORD: "MAILROOT_4mK9pL2xT7vQ1cD8"
      MYSQL_DATABASE: "roundcube"
      MYSQL_USER: "roundcube"
      MYSQL_PASSWORD: "RCPASS_7xL2mQ9tK4pD1cV8"
    volumes:
      - /srv/mail-fetch01/data/mariadb:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s
    logging: *default-logging

9. Compose Roundcube

Datei: /srv/workspace/infra/mail-fetch01/compose/roundcube/compose.yaml

x-logging: &default-logging
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

services:
  roundcube:
    image: roundcube/roundcubemail:latest
    container_name: roundcube
    restart: unless-stopped
    environment:
      TZ: Europe/Zurich
      ROUNDCUBEMAIL_DB_TYPE: mysql
      ROUNDCUBEMAIL_DB_HOST: db-mail
      ROUNDCUBEMAIL_DB_NAME: roundcube
      ROUNDCUBEMAIL_DB_USER: roundcube
      ROUNDCUBEMAIL_DB_PASSWORD: "RCPASS_7xL2mQ9tK4pD1cV8"
      ROUNDCUBEMAIL_SKIN: elastic
      ROUNDCUBEMAIL_DEFAULT_HOST: "tls://mail.theboxhub.ch"
      ROUNDCUBEMAIL_DEFAULT_PORT: 143
      ROUNDCUBEMAIL_SMTP_SERVER: "tls://mail.theboxhub.ch"
      ROUNDCUBEMAIL_SMTP_PORT: 587
      ROUNDCUBEMAIL_IMAP_CONN_OPTIONS: '{"ssl":{"verify_peer":false,"verify_peer_name":false,"allow_self_signed":true}}'
      ROUNDCUBEMAIL_SMTP_CONN_OPTIONS: '{"ssl":{"verify_peer":false,"verify_peer_name":false,"allow_self_signed":true}}'
    ports:
      - "8080:80"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 20s
    logging: *default-logging

Wichtig:

  • NPM soll spaeter webmail.theboxhub.ch auf 10.100.20.16:8080 weiterleiten.

10. Wichtiger Hinweis zu den getrennten Compose-Dateien

Da du drei getrennte Compose-Dateien willst, brauchen die Dienste fuer roundcube und db-mail einen gemeinsamen Compose-Kontext oder ein gemeinsames Netz.

Am saubersten gibt es dafuer zwei Wege:

Variante A - alles in eine gemeinsame Mail-Compose

Einfacher im Betrieb.

Variante B - externes Docker-Netz

Sauber getrennt, aber etwas mehr Aufwand.

Da du explizit nach Compose, Struktur und Config fragst, empfehle ich fuer Mail hier klar:

Empfehlung

Mailserver, Roundcube und DB in eine gemeinsame Compose-Datei packen.

Das ist fuer dieses Stack viel robuster.

Wenn du willst, kannst du die Repo-Struktur trotzdem getrennt behalten, aber technisch ist eine einzige compose/mail/compose.yaml besser.


11. Deshalb meine echte Empfehlung: eine gemeinsame Mail-Compose

Wenn du es operativ sauber willst, nimm statt 3 Dateien besser diese Struktur:

compose/
└── mail
    └── compose.yaml

Mit allen 3 Services zusammen.

Wenn du willst, schreibe ich dir diese Gesamtdatei sofort.
Das ist fuer dein Setup deutlich praktischer als drei isolierte Stacks.


12. Mailserver-Configstruktur

Fuer docker-mailserver liegen die aktiven Dateien unter:

/srv/mail-fetch01/data/mailserver/config/

Im Repo koennen wir Vorlagen unter:

/srv/workspace/infra/mail-fetch01/config/mailserver/

ablegen.

Minimal noetig

  • postfix-main.cf
  • postfix-master.cf
  • dovecot.cf
  • fetchmailrc

Hinweis: docker-mailserver braucht nicht zwingend alle davon. Vieles kann ueber setup und Standardconfig laufen.


13. fetchmailrc Vorlage

Datei: /srv/workspace/infra/mail-fetch01/config/mailserver/fetchmailrc

set daemon 60
set syslog

poll imap.example.com with proto IMAP
  user "dein.externes.postfach@example.com" there with password "DEIN_EXTERNES_PASSWORT" is "jonas@theboxhub.ch" here
  ssl
  fetchall

Wichtig:

  • das ist nur eine Vorlage
  • Rechte spaeter auf der Ziel-VM unbedingt restriktiv setzen:
    chmod 600 /srv/mail-fetch01/config/mailserver/fetchmailrc
    

14. Zertifikate

Du hast bestaetigt:

/srv/mail-fetch01/data/mailserver/certs/fullchain.pem
/srv/mail-fetch01/data/mailserver/certs/privkey.pem

Das passt genau zu obiger Compose.


15. Setup nach Clone auf Ziel-VM

Repo klonen

cd /srv/workspace/infra
git clone <dein-repo> mail-fetch01
cd mail-fetch01

Zielstruktur erzeugen

./scripts/init-dirs.sh

Compose und Config deployen

./scripts/deploy.sh

Zertifikate ablegen

sudo cp /etc/letsencrypt/live/mail.theboxhub.ch/fullchain.pem /srv/mail-infetch01t01/data/mailserver/certs/fullchain.pem
sudo cp /etc/letsencrypt/live/mail.theboxhub.ch/privkey.pem /srv/mail-fetch01/data/mailserver/certs/privkey.pem
sudo chmod 600 /srv/mail-fetch01/data/mailserver/certs/privkey.pem

16. Erster Start

Wenn du bei den 3 Compose-Dateien bleibst:

cd /srv/mail-fetch01/compose/mariadb && docker compose up -d
cd /srv/mail-fetch01/compose/mailserver && docker compose up -d
cd /srv/mail-fetch01/compose/roundcube && docker compose up -d

17. Aber nochmals: meine klare Empfehlung

Fuer diesen Mail-Stack solltest du wirklich lieber eine gemeinsame Compose-Datei verwenden.
Sonst bekommst du unnoetig Aufwand mit Netzwerken, DNS innerhalb von Docker und Service-Namen.

Wenn du magst

schreibe ich dir jetzt direkt als naechsten Schritt:

  1. die finale empfohlene Gesamtstruktur
  2. eine einzige saubere compose/mail/compose.yaml
  3. die finalen Repo-Befehle zum Anlegen

Das waere fuer deinen Mailserver die bessere produktive Variante.