mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
docker: add Traefik support
USE_FOREIGN_CERT_MANAGER existed in compose/example.env but was never read by any code. This wires it up end-to-end based on PR 662. - Preliminarily add config options for this, and skip AcmetoolDeployer if set. - Add Traefik integration in docker/docker-compose-traefik.yaml, with traefik-certs-dumper - post-hook.sh creates fullchain/privkey symlinks for chatmail - Chatmail container uses ports 25/143/465/587/993 directly, Traefik handles 80/443 - docker/traefik/ contains config.yaml and dynamic configs - docker/example-traefik.env for the Traefik setup - rename USE_FOREIGN_CERT_MANAGER to CHATMAIL_NOACME
This commit is contained in:
@@ -44,6 +44,7 @@ class Config:
|
||||
)
|
||||
self.mtail_address = params.get("mtail_address")
|
||||
self.disable_ipv6 = params.get("disable_ipv6", "false").lower() == "true"
|
||||
self.noacme = os.environ.get("CHATMAIL_NOACME", "").lower() == "true"
|
||||
self.addr_v4 = os.environ.get("CHATMAIL_ADDR_V4", "")
|
||||
self.addr_v6 = os.environ.get("CHATMAIL_ADDR_V6", "")
|
||||
self.acme_email = params.get("acme_email", "")
|
||||
|
||||
@@ -66,6 +66,7 @@ postfix_reinject_port_incoming = 10026
|
||||
# if set to "True" IPv6 is disabled
|
||||
disable_ipv6 = False
|
||||
|
||||
|
||||
# Your email adress, which will be used in acmetool to manage Let's Encrypt SSL certificates
|
||||
acme_email =
|
||||
|
||||
|
||||
@@ -610,7 +610,12 @@ def deploy_chatmail(config_path: Path, disable_mail: bool, website_only: bool) -
|
||||
UnboundDeployer(config),
|
||||
TurnDeployer(mail_domain),
|
||||
IrohDeployer(config.enable_iroh_relay),
|
||||
AcmetoolDeployer(config.acme_email, tls_domains),
|
||||
]
|
||||
|
||||
if not config.noacme:
|
||||
all_deployers.append(AcmetoolDeployer(config.acme_email, tls_domains))
|
||||
|
||||
all_deployers += [
|
||||
WebsiteDeployer(config),
|
||||
ChatmailVenvDeployer(config),
|
||||
MtastsDeployer(),
|
||||
|
||||
@@ -29,7 +29,7 @@ services:
|
||||
environment:
|
||||
MAIL_DOMAIN: $MAIL_DOMAIN
|
||||
CMDEPLOY_STAGES: ${CMDEPLOY_STAGES:-}
|
||||
USE_FOREIGN_CERT_MANAGER: ${USE_FOREIGN_CERT_MANAGER:-}
|
||||
CHATMAIL_NOACME: ${CHATMAIL_NOACME:-}
|
||||
network_mode: "host"
|
||||
volumes:
|
||||
## system
|
||||
|
||||
116
docker/docker-compose-traefik.yaml
Normal file
116
docker/docker-compose-traefik.yaml
Normal file
@@ -0,0 +1,116 @@
|
||||
# Traefik reverse proxy + cert manager for chatmail.
|
||||
# Use this instead of docker-compose.yaml when Traefik manages TLS certificates.
|
||||
#
|
||||
# Required .env vars:
|
||||
# MAIL_DOMAIN=chat.example.com
|
||||
# ACME_EMAIL=admin@example.com
|
||||
#
|
||||
# Usage:
|
||||
# cp docker/example-traefik.env .env
|
||||
# docker compose -f docker/docker-compose-traefik.yaml build
|
||||
# docker compose -f docker/docker-compose-traefik.yaml up -d
|
||||
|
||||
services:
|
||||
chatmail:
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: docker/chatmail_relay.dockerfile
|
||||
image: chatmail-relay:latest
|
||||
restart: unless-stopped
|
||||
container_name: chatmail
|
||||
depends_on:
|
||||
traefik-certs-dumper:
|
||||
condition: service_started
|
||||
cgroup: host
|
||||
tty: true
|
||||
tmpfs:
|
||||
- /tmp
|
||||
- /run
|
||||
- /run/lock
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
environment:
|
||||
MAIL_DOMAIN: $MAIL_DOMAIN
|
||||
CMDEPLOY_STAGES: ${CMDEPLOY_STAGES:-}
|
||||
CHATMAIL_NOACME: "true"
|
||||
PATH_TO_SSL: /var/lib/acme/live/${MAIL_DOMAIN}
|
||||
ports:
|
||||
- "25:25"
|
||||
- "143:143"
|
||||
- "465:465"
|
||||
- "587:587"
|
||||
- "993:993"
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:rw
|
||||
- chatmail-data:/home
|
||||
- chatmail-dkimkeys:/etc/dkimkeys
|
||||
- traefik-certs:/var/lib/acme/live:ro
|
||||
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.services.chatmail.loadbalancer.server.scheme=https
|
||||
- traefik.http.services.chatmail.loadbalancer.server.port=443
|
||||
- traefik.http.services.chatmail.loadbalancer.serverstransport=insecure@file
|
||||
- traefik.http.routers.chatmail.rule=Host(`${MAIL_DOMAIN}`) || Host(`mta-sts.${MAIL_DOMAIN}`) || Host(`www.${MAIL_DOMAIN}`)
|
||||
- traefik.http.routers.chatmail.tls=true
|
||||
- traefik.http.routers.chatmail.tls.certresolver=letsEncrypt
|
||||
|
||||
traefik:
|
||||
image: traefik:v3.3
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
command:
|
||||
- "--configFile=/config.yaml"
|
||||
- "--certificatesresolvers.letsEncrypt.acme.email=${ACME_EMAIL}"
|
||||
network_mode: host
|
||||
depends_on:
|
||||
traefik-init:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./traefik/config.yaml:/config.yaml:ro
|
||||
- traefik-data:/data
|
||||
- ./traefik/dynamic-configs:/dynamic/conf:ro
|
||||
|
||||
traefik-init:
|
||||
image: alpine:latest
|
||||
restart: "no"
|
||||
entrypoint: sh -c 'touch /data/acme.json && chmod 600 /data/acme.json'
|
||||
volumes:
|
||||
- traefik-data:/data
|
||||
|
||||
traefik-certs-dumper:
|
||||
image: ldez/traefik-certs-dumper:v2.10.0
|
||||
restart: unless-stopped
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
depends_on:
|
||||
- traefik
|
||||
entrypoint: sh -c '
|
||||
apk add openssl
|
||||
&& while ! [ -e /data/acme.json ] || ! [ "$$(jq ".[] | .Certificates | length" /data/acme.json | jq -s "add")" != "0" ]; do
|
||||
sleep 1
|
||||
; done
|
||||
&& traefik-certs-dumper file --version v3 --watch --domain-subdir=true
|
||||
--source /data/acme.json --dest /certs --post-hook "sh /post-hook.sh"'
|
||||
volumes:
|
||||
- traefik-data:/data:ro
|
||||
- traefik-certs:/certs
|
||||
- ./traefik/post-hook.sh:/post-hook.sh:ro
|
||||
|
||||
volumes:
|
||||
chatmail-data:
|
||||
chatmail-dkimkeys:
|
||||
traefik-data:
|
||||
traefik-certs:
|
||||
5
docker/example-traefik.env
Normal file
5
docker/example-traefik.env
Normal file
@@ -0,0 +1,5 @@
|
||||
MAIL_DOMAIN="chat.example.com"
|
||||
ACME_EMAIL="admin@example.com"
|
||||
|
||||
# CMDEPLOY_STAGES - default: "configure,activate". Set to "install,configure,activate" to force full reinstall.
|
||||
# CMDEPLOY_STAGES="configure,activate"
|
||||
@@ -4,4 +4,4 @@ MAIL_DOMAIN="chat.example.com"
|
||||
# CMDEPLOY_STAGES="configure,activate"
|
||||
|
||||
# Skip acmetool when using an external certificate manager (e.g. Traefik, Caddy).
|
||||
# USE_FOREIGN_CERT_MANAGER="True"
|
||||
# CHATMAIL_NOACME="True"
|
||||
|
||||
@@ -6,7 +6,7 @@ SETUP_CHATMAIL_SERVICE_PATH="${SETUP_CHATMAIL_SERVICE_PATH:-/lib/systemd/system/
|
||||
# Whitelist only the env vars needed by setup_chatmail_docker.sh.
|
||||
# Forwarding all env vars (via printenv) would leak Docker internals,
|
||||
# orchestrator secrets, and other unrelated variables into systemd.
|
||||
env_vars="MAIL_DOMAIN CMDEPLOY_STAGES CHATMAIL_INI CHATMAIL_NOSYSCTL CHATMAIL_NOPORTCHECK PATH_TO_SSL PATH USE_FOREIGN_CERT_MANAGER"
|
||||
env_vars="MAIL_DOMAIN CMDEPLOY_STAGES CHATMAIL_INI CHATMAIL_NOSYSCTL CHATMAIL_NOPORTCHECK CHATMAIL_NOACME PATH_TO_SSL PATH"
|
||||
sed -i "s|<envs_list>|$env_vars|g" "$SETUP_CHATMAIL_SERVICE_PATH"
|
||||
|
||||
exec /lib/systemd/systemd "$@"
|
||||
|
||||
30
docker/traefik/config.yaml
Normal file
30
docker/traefik/config.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
log:
|
||||
level: INFO
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
permanent: true
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false
|
||||
file:
|
||||
directory: /dynamic/conf
|
||||
watch: true
|
||||
|
||||
certificatesResolvers:
|
||||
letsEncrypt:
|
||||
acme:
|
||||
storage: /data/acme.json
|
||||
caServer: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
tlschallenge: true
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
4
docker/traefik/dynamic-configs/insecure.yaml
Normal file
4
docker/traefik/dynamic-configs/insecure.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
http:
|
||||
serversTransports:
|
||||
insecure:
|
||||
insecureSkipVerify: true
|
||||
12
docker/traefik/post-hook.sh
Normal file
12
docker/traefik/post-hook.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
# Post-hook for traefik-certs-dumper: create symlinks from Traefik's
|
||||
# cert dump format to the paths chatmail expects (fullchain, privkey).
|
||||
CERTS_DIR="${CERTS_DIR:-/certs}"
|
||||
|
||||
for dir in "$CERTS_DIR"/*/; do
|
||||
[ -d "$dir" ] || continue
|
||||
cd "$dir"
|
||||
[ -f "certificate.crt" ] && ln -sf certificate.crt fullchain
|
||||
[ -f "privatekey.key" ] && ln -sf privatekey.key privkey
|
||||
cd - > /dev/null
|
||||
done
|
||||
Reference in New Issue
Block a user