Tests SSH into the host and run systemctl/journalctl/env directly,
which fails on Docker deployments where services run inside the
container. When CHATMAIL_DOCKER is set (to container name), Remote
and SSHExec now wrap commands in `docker exec`. Without CHATMAIL_DOCKER,
behavior is unchanged.
Remove the custom certmon timer (polling via sha1sum every 60s),
replaced by the deployer's tls-cert-reload.path unit (inotify).
chatmail-init.sh: inject TLS_EXTERNAL_CERT_AND_KEY env var into
chatmail.ini at startup if not already present.
docker-compose.yaml: remove CMDEPLOY_STAGES, CHATMAIL_NOSYSCTL,
TLS_EXTERNAL_CERT_AND_KEY from base environment (set in init script
or via override file).
Add Docker-based deployment: Dockerfile based on systemd image,
docker-compose.yaml, build script, entrypoint, external certificate
monitoring, CI workflow, and documentation.
This builds on the chatmaild/cmdeploy preparation in the previous
commit (j4n/docker-prep-chatmail) which added the env-var-driven
feature flags (CHATMAIL_NOSYSCTL, CHATMAIL_NOPORTCHECK, CHATMAIL_NOACME)
and @local deployment support needed by the container.
This is commit 2 of 3 to merge squashed changes on j4n/docker and docker
branches, original commits were beef0ec..606f36e
Architecture overview (mostly by original author Keonik1):
- Debian-systemd image wrapping the existing cmdeploy install
- Host networking to not manually expose the many ports needed
- Config via MAIL_DOMAIN env var or (new) mounted chatmail.ini
- New: cmdeploy stages: install at build, configure+activate at startup
- New: Monitoring service for external certs via systemd timer (chatmail-certmon)
- New: Image version tracking for automatic upgrade detection (cm + config hash)
- New: docker-compose.override.yaml pattern for user customizations
- New: GitHub Actions CI for ghcr.io image builds
Traefik reverse-proxy support is prepared but the specific files are
excluded from this PR and will be submitted separately.
TODO:
- [ ] Pull out CHATMAIL_NOACME as PR #855 introduced a proper mechanism
- [ ] Check if underlying image could be based on regular debian-slim
images with a step to enable systemd, similar to
https://github.com/alexdzyoba/docker-debian-systemd
Files added:
.dockerignore
.github/workflows/docker-build.yaml
docker-compose.yaml
docker-compose.override.yaml.example
docker/build.sh
docker/chatmail_relay.dockerfile
docker/files/chatmail-certmon.{service,sh,timer}
docker/files/entrypoint.sh
docker/files/setup_chatmail.service
docker/files/setup_chatmail_docker.sh
env.example
doc/source/docker.rst
Files modified:
.gitignore
doc/source/getting_started.rst
doc/source/index.rst
Co-authored-by: Keonik1 <keonik.dev@gmail.com>
Co-authored-by: missytake <missytake@systemli.org>
- chatmaild:
- basedeploy.py: Add has_systemd() guard. During Docker image builds
there's no running systemd, so deployers that query SystemdEnabled
facts would crash; this change might also be helpful for non-systemd
platforms.
- cmdeploy:
- cmdeploy.py:
- when deploying to @docker, auto-set CHATMAIL_NOPORTCHECK and
CHATMAIL_NOSYSCTL since neither makes sense inside a container
- --config default now reads CHATMAIL_INI env var, so Docker
entrypoints can point to a mounted ini without CLI flags.
- deployers.py:
- skip port check / CHATMAIL_NOPORTCHECK
- skip echobot systemd cleanup w/ has_systemd
- dovecot/deployer.py:
- Guard sysctl writes behind CHATMAIL_NOSYSCTL
- invert dovecot install check so it works without systemd
- sshexec.py: Add __call__ to LocalExec so cmdeploy status works with
@local target. Without it, cmdeploy status tried to call the
executor directly and got TypeError.
Consolidated from j4n/docker branch commits (selection):
- 8953fde feat(cmdeploy): read CHATMAIL_INI env var for default --config path
- 81d7782 fix(cmdeploy): add __call__ to LocalExec so status works with @local
- 8bba78e docker: disable port check if docker is running. fix#694
- 865b514 docker: replace config flags with env vars, drop docker param (instead of f26cb08)
Files: cmdeploy/src/cmdeploy/{basedeploy,cmdeploy,deployers,sshexec,dovecot/deployer}.py
Co-authored-by: Keonik1 <keonik.dev@gmail.com>
Co-authored-by: missytake <missytake@systemli.org>
- chatmaild:
- basedeploy.py: Add has_systemd() guard. During Docker image builds
there's no running systemd, so deployers that query SystemdEnabled
facts would crash; this change might also be helpful for non-systemd
platforms.
- cmdeploy:
- cmdeploy.py:
- when deploying to @docker, auto-set CHATMAIL_NOPORTCHECK and
CHATMAIL_NOSYSCTL since neither makes sense inside a container
- --config default now reads CHATMAIL_INI env var, so Docker
entrypoints can point to a mounted ini without CLI flags.
- deployers.py:
- skip port check / CHATMAIL_NOPORTCHECK
- skip echobot systemd cleanup w/ has_systemd
- dovecot/deployer.py:
- Guard sysctl writes behind CHATMAIL_NOSYSCTL
- invert dovecot install check so it works without systemd
- sshexec.py: Add __call__ to LocalExec so cmdeploy status works with
@local target. Without it, cmdeploy status tried to call the
executor directly and got TypeError.
Consolidated from j4n/docker branch commits (selection):
- 8953fde feat(cmdeploy): read CHATMAIL_INI env var for default --config path
- 81d7782 fix(cmdeploy): add __call__ to LocalExec so status works with @local
- 8bba78e docker: disable port check if docker is running. fix#694
- 865b514 docker: replace config flags with env vars, drop docker param (instead of f26cb08)
Files: cmdeploy/src/cmdeploy/{basedeploy,cmdeploy,deployers,sshexec,dovecot/deployer}.py
Co-authored-by: Keonik1 <keonik.dev@gmail.com>
Co-authored-by: missytake <missytake@systemli.org>
Adds a new tls_external_cert_and_key config option for chatmail servers
that manage their own TLS certificates (e.g. via an external ACME client
or a load balancer).
A systemd path unit (tls-cert-reload.path) watches the certificate file
via inotify and automatically reloads dovecot and nginx when it changes.
Postfix reads certs per TLS handshake so needs no reload.
Also extracts openssl_selfsigned_args() so cert generation parameters
are shared between SelfSignedTlsDeployer and the e2e test.