This repository contains the Docker setup for chatmail relay.
Note
- Docker support is experimental, CI builds and tests the image automatically, but please report bugs.
- The image wraps the cmdeploy process in a Debian-systemd image with r/w access to
/sys/fs- Currently amd64-only (arm64 should work but is untested).
Pre-built images are available from GitHub Container Registry. The main branch and
tagged releases are pushed automatically by CI:
docker pull ghcr.io/chatmail/docker:main # latest main branch
docker pull ghcr.io/chatmail/docker:1.2.3 # tagged releaseInstall instructions follow for use with Docker Compose.
Check your version with:
docker compose versionInstall on:
- Debian 12 via official install instructions
- Debian 13+ with
apt install docker docker-compose
These must be set on the host, as they cannot be set from the container:
echo "fs.inotify.max_user_instances=65536" | sudo tee -a /etc/sysctl.d/99-inotify.conf
echo "fs.inotify.max_user_watches=65536" | sudo tee -a /etc/sysctl.d/99-inotify.conf
sudo sysctl --systemThe following is an example in BIND zone file format with a TTL of 1 hour (3600 seconds).
Substitute chat.example.org with your domain and update IP addresses:
chat.example.org. 3600 IN A 198.51.100.5
chat.example.org. 3600 IN AAAA 2001:db8::5
www.chat.example.org. 3600 IN CNAME chat.example.org.
mta-sts.chat.example.org. 3600 IN CNAME chat.example.org.
Choose one approach:
Option A: Download compose files directly
mkdir -p /srv/chatmail-relay && cd /srv/chatmail-relay
wget https://raw.githubusercontent.com/chatmail/docker/main/docker-compose.yaml
wget https://raw.githubusercontent.com/chatmail/docker/main/docker-compose.override.yaml.example -O docker-compose.override.yamlOption B: Clone the docker repo
git clone https://github.com/chatmail/docker
cd docker-
Set the fully qualified domain name (use
chat.example.orgor your own domain):echo 'MAIL_DOMAIN=chat.example.org' > .env
The container generates a
chatmail.iniwith defaults fromMAIL_DOMAINon first start. To customize chatmail settings, mount your ownchatmail.iniinstead (see Custom chatmail.ini below). -
Configure local customizations in
docker-compose.override.yaml:By default, all data is stored in docker volumes. You'll likely want to:
- Create and configure the mail storage location
- Configure external TLS certificates (if not using auto-generated certs)
- Customize the website
See the Customization section for examples.
-
Start the container:
docker compose up -d docker compose logs -f chatmail # view logs, Ctrl+C to exit -
After installation is complete, open
https://chat.example.orgin your browser.
pip install cmping
cmping chat.example.org
# alternatively, if you use https://docs.astral.sh/uv/
uvx cmping chat.example.orgShow required DNS records:
docker exec chatmail cmdeploy dns --ssh-host @localdocker exec chatmail cmdeploy status --ssh-host @localdocker exec chatmail cmdeploy benchdocker exec chatmail cmdeploy test --ssh-host localhostdocker exec chatmail journalctl -fu postfix@-Customize the chatmail landing page by mounting a directory with your own website source.
-
Create a directory with your custom website source:
mkdir -p ./data/www/src nano ./data/www/src/index.md
-
Add the volume mount in
docker-compose.override.yaml:services: chatmail: volumes: - ./data/www:/opt/chatmail-www
-
Restart the service:
docker compose down docker compose up -d
For full control over chatmail settings beyond just MAIL_DOMAIN:
-
Extract the generated config from a running container:
docker cp chatmail:/etc/chatmail/chatmail.ini ./chatmail.ini
-
Edit
chatmail.inias needed. -
Add the volume mount in
docker-compose.override.yaml:services: chatmail: volumes: - ./chatmail.ini:/etc/chatmail/chatmail.ini
-
Restart the container:
docker compose down && docker compose up -d
If TLS certificates are managed outside the container (e.g., by certbot, acmetool, or Traefik
on the host), mount them into the container and set TLS_EXTERNAL_CERT_AND_KEY
in docker-compose.override.yaml.
Changed certificates are picked up automatically via inotify. See the examples in
docker-compose.override.yaml.example for details.
If you have an existing bare-metal chatmail installation and want to switch to Docker:
-
Stop all existing services:
systemctl stop postfix dovecot doveauth nginx opendkim unbound \ acmetool-redirector filtermail filtermail-incoming chatmail-turn \ iroh-relay chatmail-metadata lastlogin mtail systemctl disable postfix dovecot doveauth nginx opendkim unbound \ acmetool-redirector filtermail filtermail-incoming chatmail-turn \ iroh-relay chatmail-metadata lastlogin mtail
-
Copy your existing
chatmail.iniand mount it into the container (see Custom chatmail.ini above):cp /usr/local/lib/chatmaild/chatmail.ini ./chatmail.ini
-
Copy persistent data into the
./data/subdirectories:mkdir -p data/dkim data/certs data/mail # DKIM keys cp -a /etc/dkimkeys/* data/dkim/ # TLS certificates rsync -a /var/lib/acme/ data/certs/
Note that ownership of dkim and acme is adjusted on container start.
For the mail directory:
rsync -a /home/vmail/ data/mail/
Alternatively, mount
/home/vmaildirectly by changing the volume indocker-compose.override.yaml:services: chatmail: volumes: - /home/vmail:/home/vmail
The three
./data/subdirectories cover all persistent state. Everything else is regenerated by theconfigureandactivatestages on container start.
To develop or contribute to the Docker setup:
Clone the relay repo and add this repository as a submodule:
git clone https://github.com/chatmail/relay
cd relay
git clone https://github.com/chatmail/docker
cd docker