Skip to content

Commit 8ccf4a7

Browse files
committed
docker: add traefik support
1 parent 2c344d7 commit 8ccf4a7

File tree

13 files changed

+246
-6
lines changed

13 files changed

+246
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ chatmail.zone
170170
/custom/
171171
docker-compose.yaml
172172
.env
173+
/traefik/data/

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
- Add configuration parameters
2727
([#614](https://github.com/chatmail/relay/pull/614)):
28+
- `use_foreign_cert_manager` - Use a third-party certificate manager instead of acmetool (default: `False`)
2829
- `change_kernel_settings` - Whether to change kernel parameters during installation (default: `True`)
2930
- `fs_inotify_max_user_instances_and_watchers` - Value for kernel parameters `fs.inotify.max_user_instances` and `fs.inotify.max_user_watches` (default: `65535`)
3031

chatmaild/src/chatmaild/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ def __init__(self, inipath, params):
4444
)
4545
self.mtail_address = params.get("mtail_address")
4646
self.disable_ipv6 = params.get("disable_ipv6", "false").lower() == "true"
47+
self.use_foreign_cert_manager = (
48+
params.get("use_foreign_cert_manager", "false").lower() == "true"
49+
)
4750
self.change_kernel_settings = (
4851
params.get("change_kernel_settings", "true").lower() == "true"
4952
)

chatmaild/src/chatmaild/ini/chatmail.ini.f

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
# if set to "True" IPv6 is disabled
6161
disable_ipv6 = False
6262

63+
# if you set "True", acmetool will not be installed and you will have to manage certificates yourself.
64+
use_foreign_cert_manager = False
65+
6366
#
6467
# Kernel settings
6568
#

cmdeploy/src/cmdeploy/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -726,10 +726,11 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
726726
deploy_iroh_relay(config)
727727

728728
# Deploy acmetool to have TLS certificates.
729-
tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"]
730-
deploy_acmetool(
731-
domains=tls_domains,
732-
)
729+
if not config.use_foreign_cert_manager:
730+
tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"]
731+
deploy_acmetool(
732+
domains=tls_domains,
733+
)
733734

734735
apt.packages(
735736
# required for setfacl for echobot

docker/docker-compose-traefik.yaml

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
services:
2+
chatmail:
3+
build:
4+
context: ./docker
5+
dockerfile: chatmail_relay.dockerfile
6+
tags:
7+
- chatmail-relay:latest
8+
image: chatmail-relay:latest
9+
restart: unless-stopped
10+
container_name: chatmail
11+
depends_on:
12+
- traefik-certs-dumper
13+
cgroup: host # required for systemd
14+
tty: true # required for logs
15+
tmpfs: # required for systemd
16+
- /tmp
17+
- /run
18+
- /run/lock
19+
logging:
20+
driver: json-file
21+
options:
22+
max-size: "10m"
23+
max-file: "3"
24+
environment: #all possible variables you can check inside README and /chatmaild/src/chatmaild/ini/chatmail.ini.f
25+
MAIL_DOMAIN: $MAIL_DOMAIN
26+
# MAX_MESSAGE_SIZE: "50M"
27+
# DEBUG_COMMANDS_ENABLED: "true"
28+
# FORCE_REINIT_INI_FILE: "true"
29+
# RECREATE_VENV: "false"
30+
USE_FOREIGN_CERT_MANAGER: "true"
31+
CHANGE_KERNEL_SETTINGS: "false"
32+
PATH_TO_SSL: "${CERTS_ROOT_DIR_CONTAINER}/${MAIL_DOMAIN}"
33+
ENABLE_CERTS_MONITORING: "true"
34+
# CERTS_MONITORING_TIMEOUT: 60
35+
# IS_DEVELOPMENT_INSTANCE: "true"
36+
ports:
37+
- "25:25"
38+
- "587:587"
39+
- "143:143"
40+
- "465:465"
41+
- "993:993"
42+
volumes:
43+
## system
44+
- /sys/fs/cgroup:/sys/fs/cgroup:rw # required for systemd
45+
- ./:/opt/chatmail
46+
- ${CERTS_ROOT_DIR_HOST}:${CERTS_ROOT_DIR_CONTAINER}:ro
47+
48+
## data
49+
- ./data/chatmail:/home
50+
# - ./data/chatmail-dkimkeys:/etc/dkimkeys
51+
# - ./data/chatmail-echobot:/run/echobot
52+
# - ./data/chatmail-acme:/var/lib/acme
53+
54+
## custom resources
55+
# - ./custom/www/src/index.md:/opt/chatmail/www/src/index.md
56+
57+
## debug
58+
# - ./docker/files/setup_chatmail_docker.sh:/setup_chatmail_docker.sh
59+
# - ./docker/files/entrypoint.sh:/entrypoint.sh
60+
# - ./docker/files/update_ini.sh:/update_ini.sh
61+
62+
labels:
63+
- traefik.enable=true
64+
- traefik.http.services.chatmail-relay.loadbalancer.server.scheme=https
65+
- traefik.http.services.chatmail-relay.loadbalancer.server.port=443
66+
- traefik.http.services.chatmail-relay.loadbalancer.serverstransport=insecure@file
67+
- traefik.http.routers.chatmail-relay.rule=Host(`${MAIL_DOMAIN}`) || Host(`mta-sts.${MAIL_DOMAIN}`) || Host(`www.${MAIL_DOMAIN}`)
68+
- traefik.http.routers.chatmail-relay.service=chatmail-relay
69+
- traefik.http.routers.chatmail-relay.tls=true
70+
- traefik.http.routers.chatmail-relay.tls.certresolver=letsEncrypt
71+
72+
traefik_init:
73+
image: alpine:latest
74+
restart: on-failure
75+
logging:
76+
driver: json-file
77+
options:
78+
max-size: "10m"
79+
max-file: "3"
80+
working_dir: /app
81+
entrypoint: sh -c '
82+
touch acme.json &&
83+
chown 0:0 ./acme.json &&
84+
chmod 600 ./acme.json'
85+
volumes:
86+
- ./traefik/data:/app
87+
88+
traefik:
89+
image: traefik:v3.3
90+
container_name: traefik
91+
restart: unless-stopped
92+
logging:
93+
driver: json-file
94+
options:
95+
max-size: "10m"
96+
max-file: "3"
97+
command:
98+
- "--configFile=/config.yaml"
99+
- "--certificatesresolvers.letsEncrypt.acme.email=${ACME_EMAIL}"
100+
# ports:
101+
# - "80:80"
102+
# - "443:443"
103+
network_mode: host
104+
depends_on:
105+
traefik_init:
106+
condition: service_completed_successfully
107+
volumes:
108+
- /var/run/docker.sock:/var/run/docker.sock
109+
- ./traefik/config.yaml:/config.yaml
110+
- ./traefik/data/acme.json:/acme.json
111+
- ./traefik/dynamic-configs:/dynamic/conf
112+
113+
traefik-certs-dumper:
114+
image: ldez/traefik-certs-dumper:v2.10.0
115+
restart: unless-stopped
116+
logging:
117+
driver: json-file
118+
options:
119+
max-size: "10m"
120+
max-file: "3"
121+
depends_on:
122+
- traefik
123+
entrypoint: sh -c '
124+
apk add openssl &&
125+
while ! [ -e /data/acme.json ]
126+
|| ! [ `jq ".[] | .Certificates | length" /data/acme.json | jq -s "add" ` != 0 ]; do
127+
sleep 1
128+
; done
129+
&& traefik-certs-dumper file --version v3 --watch --domain-subdir=true
130+
--source /data/acme.json --dest /data/letsencrypt/certs --post-hook "sh /post-hook.sh"'
131+
environment:
132+
CERTS_DIR: /data/letsencrypt/certs
133+
volumes:
134+
- ./traefik/data/letsencrypt:/data/letsencrypt
135+
- ./traefik/data/acme.json:/data/acme.json
136+
- ./traefik/post-hook.sh:/post-hook.sh

docker/example.env

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
MAIL_DOMAIN="chat.example.com"
2+
ACME_EMAIL="my.email@gmail.com"
3+
4+
CERTS_ROOT_DIR_HOST="./traefik/data/letsencrypt/certs"
5+
CERTS_ROOT_DIR_CONTAINER="/var/lib/acme/live"

docker/files/entrypoint.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@ set -eo pipefail
33

44
unlink /etc/nginx/sites-enabled/default || true
55

6+
if [ "${USE_FOREIGN_CERT_MANAGER,,}" == "true" ]; then
7+
if [ ! -f "$PATH_TO_SSL/fullchain" ]; then
8+
echo "Error: file '$PATH_TO_SSL/fullchain' does not exist. Exiting..." > /dev/stderr
9+
sleep 2
10+
exit 1
11+
fi
12+
if [ ! -f "$PATH_TO_SSL/privkey" ]; then
13+
echo "Error: file '$PATH_TO_SSL/privkey' does not exist. Exiting..." > /dev/stderr
14+
sleep 2
15+
exit 1
16+
fi
17+
fi
18+
619
SETUP_CHATMAIL_SERVICE_PATH="${SETUP_CHATMAIL_SERVICE_PATH:-/lib/systemd/system/setup_chatmail.service}"
720

821
env_vars=$(printenv | cut -d= -f1 | xargs)

docs/DOCKER_INSTALLATION_EN.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,25 @@ Please substitute it with your own domain.
3232
```
3333

3434
## Installation
35+
When installing via Docker, there are several options:
3536

36-
1. Copy the file `./docker/docker-compose-default.yaml` to `docker-compose.yaml`. This is necessary because `docker-compose.yaml` is in `.gitignore` and won’t cause conflicts when updating the git repository.
37+
- Use the built-in nginx and acmetool in Chatmail container to host the chat and manage certificates.
38+
- Use third-party tools for certificate management.
39+
40+
For the third-party certificate manager example, traefik will be used, but you can use whatever is more convenient for you.
41+
42+
1. Copy the file `./docker/docker-compose-default.yaml` or `./docker/docker-compose-traefik.yaml` and rename it to `docker-compose.yaml`. This is necessary because `docker-compose.yaml` is in `.gitignore` and won’t cause conflicts when updating the git repository.
3743

3844
```shell
3945
cp ./docker/docker-compose-default.yaml docker-compose.yaml
46+
## or
47+
# cp ./docker/docker-compose-traefik.yaml docker-compose.yaml
48+
```
49+
50+
2. Copy `./docker/example.env` and rename it to `.env`. This file stores variables used in `docker-compose.yaml`.
51+
52+
```shell
53+
cp ./docker/example.env .env
4054
```
4155

4256
3. Configure environment variables in the `.env` file. These variables are used in the `docker-compose.yaml` file to pass repeated values.

docs/DOCKER_INSTALLATION_RU.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,22 @@ Please substitute it with your own domain.
2929
```
3030

3131
## Installation
32+
При установке через docker есть несколько вариантов:
33+
- использовать встроенный в chatmail контейнер nginx и acmetool для хостинга чата и управления сертификатами.
34+
- использовать сторонние инструменты для менеджмента сертификатов
3235

33-
1. Скопировать файл `./docker/docker-compose-default.yaml` в `docker-compose.yaml`. Это нужно потому что `docker-compose.yaml` находится в `.gitignore` и не будет создавать конфликты при обновлении гит репозитория.
36+
В качестве примера для стороннего менеджера сертификатов будет использоваться traefik, но вы можете использовать то что удобнее вам.
37+
38+
1. Скопировать файл `./docker/docker-compose-default.yaml` или `./docker/docker-compose-traefik.yaml` и переименовать в `docker-compose.yaml`. Это нужно потому что `docker-compose.yaml` находится в `.gitignore` и не будет создавать конфликты при обновлении гит репозитория.
3439
```shell
3540
cp ./docker/docker-compose-default.yaml docker-compose.yaml
41+
## or
42+
# cp ./docker/docker-compose-traefik.yaml docker-compose.yaml
43+
```
44+
45+
2. Скопировать `./docker/example.env` и переименовать в `.env`. Здесь хранятся переменные, которые используятся в `docker-compose.yaml`.
46+
```shell
47+
cp ./docker/example.env .env
3648
```
3749

3850
3. Настроить переменные окружения в `.env` файле. Эти переменные используются в `docker-compose.yaml` файле, чтобы передавать повторяющиеся значения.

0 commit comments

Comments
 (0)