Mailserver aufgebaut

This commit is contained in:
mrwacka 2026-09-08 09:58:36 +02:00
parent 578686701d
commit 56addbe241
22 changed files with 660 additions and 0 deletions

530
README.md
View file

@ -0,0 +1,530 @@
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:
```text
/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:
```bash
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:
```text
/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`
```bash
#!/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:
```bash
chmod +x /srv/workspace/infra/mail-fetch01/scripts/init-dirs.sh
```
---
# 6. scripts/deploy.sh
Datei:
`/srv/workspace/infra/mail-fetch01/scripts/deploy.sh`
```bash
#!/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:
```bash
chmod +x /srv/workspace/infra/mail-fetch01/scripts/deploy.sh
```
---
# 7. Compose mailserver
Datei:
`/srv/workspace/infra/mail-fetch01/compose/mailserver/compose.yaml`
```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`
```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`
```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:
```text
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:
```text
/srv/mail-fetch01/data/mailserver/config/
```
Im Repo koennen wir Vorlagen unter:
```text
/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`
```conf
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:
```bash
chmod 600 /srv/mail-fetch01/config/mailserver/fetchmailrc
```
---
# 14. Zertifikate
Du hast bestaetigt:
```text
/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
```bash
cd /srv/workspace/infra
git clone <dein-repo> mail-fetch01
cd mail-fetch01
```
## Zielstruktur erzeugen
```bash
./scripts/init-dirs.sh
```
## Compose und Config deployen
```bash
./scripts/deploy.sh
```
## Zertifikate ablegen
```bash
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:
```bash
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.

0
backup/compose/.gitkeep Normal file
View file

View file

View file

View file

106
compose/mail/compose.yaml Normal file
View file

@ -0,0 +1,106 @@
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: none
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
- /srv/mail-fetch01/config/mailserver/fetchmailrc:/etc/fetchmailrc: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
db-mail:
image: mariadb:10.11
container_name: db-mail
restart: unless-stopped
environment:
TZ: Europe/Zurich
MYSQL_ROOT_PASSWORD: "MAILROOT_9kL4mQ2xT7vP1cD8"
MYSQL_DATABASE: "roundcube"
MYSQL_USER: "roundcube"
MYSQL_PASSWORD: "RCPASS_8xT2mQ7vL4pD1cK9"
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
roundcube:
image: roundcube/roundcubemail:latest
container_name: roundcube
restart: unless-stopped
depends_on:
db-mail:
condition: service_healthy
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_8xT2mQ7vL4pD1cK9"
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":true,"verify_peer_name":true,"allow_self_signed":false}}'
ROUNDCUBEMAIL_SMTP_CONN_OPTIONS: '{"ssl":{"verify_peer":true,"verify_peer_name":true,"allow_self_signed":false}}'
ports:
- "8080:80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 5
start_period: 20s
logging: *default-logging

View file

View file

@ -0,0 +1,6 @@
# Interval ist 60 Sekunden. Interval 3 wäre 3x 60 Sekunden, etc.
poll imap.mail-ch.ch proto IMAP port 993 interval 3
user 'joni@pop.agri.ch' pass '9Ty8TyToo?'
is "jonas@theboxhub.ch" here
ssl

View file

View file

0
config/mariadb/.gitkeep Normal file
View file

View file

View file

View file

View file

View file

View file

View file

0
data/mariadb/.gitkeep Normal file
View file

0
data/roundcube/.gitkeep Normal file
View file

0
scripts/deploy.sh Normal file
View file

18
scripts/init-dirs.sh Normal file
View file

@ -0,0 +1,18 @@
#!/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-fetch/data/roundcube
echo "Setze Besitz auf aktuellen Benutzer: $USER"
sudo chown -R "$USER:$USER" /srv/mail-fetch01
echo "Fertig."
tree /srv/mail-fetch01 || true