mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
docker: make compose work with cgroups (v2), conversion scripts/docs
This commit is contained in:
@@ -3,12 +3,12 @@ services:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: docker/chatmail_relay.dockerfile
|
||||
tags:
|
||||
- chatmail-relay:latest
|
||||
image: chatmail-relay:latest
|
||||
restart: unless-stopped
|
||||
container_name: chatmail
|
||||
cgroup: host # required for systemd
|
||||
# Required for systemd — use only one of the following:
|
||||
cgroup: host # compose v2 only
|
||||
# privileged: true # compose v1 (not tested)
|
||||
tty: true # required for logs
|
||||
tmpfs: # required for systemd
|
||||
- /tmp
|
||||
|
||||
84
docker/cm_ini_to_env.py
Executable file
84
docker/cm_ini_to_env.py
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert a chatmail.ini to a Docker .env file.
|
||||
|
||||
Usage: python docker/cm_ini_to_env.py [chatmail.ini] [.env]
|
||||
|
||||
Reads the ini file, extracts all non-default key=value pairs,
|
||||
and writes them as UPPER_CASE env vars suitable for docker-compose.
|
||||
"""
|
||||
|
||||
import configparser
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Keys that only make sense for bare-metal deploys or are handled
|
||||
# separately by the Docker setup and should not appear in .env.
|
||||
SKIP_KEYS = set()
|
||||
|
||||
# Keys that exist in .env but have a different name than the ini key.
|
||||
# ini_key -> env_key
|
||||
RENAMES = {}
|
||||
|
||||
|
||||
def read_ini(path):
|
||||
"""Return dict of key=value from [params] section."""
|
||||
cp = configparser.ConfigParser()
|
||||
cp.read(path)
|
||||
if not cp.has_section("params"):
|
||||
sys.exit(f"Error: {path} has no [params] section")
|
||||
return dict(cp.items("params"))
|
||||
|
||||
|
||||
def read_defaults():
|
||||
"""Return dict of default values from the ini template."""
|
||||
template = Path(__file__).resolve().parent.parent / "chatmaild/src/chatmaild/ini/chatmail.ini.f"
|
||||
if not template.exists():
|
||||
return {}
|
||||
cp = configparser.ConfigParser()
|
||||
cp.read(template)
|
||||
if not cp.has_section("params"):
|
||||
return {}
|
||||
defaults = {}
|
||||
for key, value in cp.items("params"):
|
||||
# Template placeholders like {mail_domain} aren't real defaults.
|
||||
if "{" not in value:
|
||||
defaults[key] = value
|
||||
return defaults
|
||||
|
||||
|
||||
def ini_to_env(ini_path, only_non_default=True):
|
||||
"""Yield (ENV_KEY, value) pairs from an ini file."""
|
||||
params = read_ini(ini_path)
|
||||
defaults = read_defaults() if only_non_default else {}
|
||||
|
||||
for key, value in sorted(params.items()):
|
||||
if key in SKIP_KEYS:
|
||||
continue
|
||||
if only_non_default and key in defaults and value.strip() == defaults[key].strip():
|
||||
continue
|
||||
env_key = RENAMES.get(key, key.upper())
|
||||
yield env_key, value.strip()
|
||||
|
||||
|
||||
def main():
|
||||
ini_path = sys.argv[1] if len(sys.argv) > 1 else "chatmail.ini"
|
||||
env_path = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
|
||||
if not Path(ini_path).exists():
|
||||
sys.exit(f"Error: {ini_path} not found")
|
||||
|
||||
lines = []
|
||||
for env_key, value in ini_to_env(ini_path):
|
||||
lines.append(f'{env_key}="{value}"')
|
||||
|
||||
output = "\n".join(lines) + "\n"
|
||||
|
||||
if env_path:
|
||||
Path(env_path).write_text(output)
|
||||
print(f"Wrote {len(lines)} variables to {env_path}")
|
||||
else:
|
||||
print(output, end="")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -67,7 +67,10 @@ git config --global --add safe.directory /opt/chatmail
|
||||
if [ "$RECREATE_VENV" = true ]; then
|
||||
rm -rf venv
|
||||
fi
|
||||
# Skip venv creation if it already exists
|
||||
if [ ! -x venv/bin/python ] || [ ! -x venv/bin/cmdeploy ]; then
|
||||
./scripts/initenv.sh
|
||||
fi
|
||||
|
||||
./scripts/cmdeploy init --config "${INI_FILE}" $INI_CMD_ARGS $MAIL_DOMAIN || true
|
||||
bash /update_ini.sh
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
- The Docker image is only suitable for amd64. If you need to run it on a different architecture, try modifying the Dockerfile (specifically the part responsible for installing dovecot).
|
||||
|
||||
# Docker installation
|
||||
This section provides instructions for installing Chatmail using docker-compose.
|
||||
This section provides instructions for installing Chatmail using Docker Compose.
|
||||
|
||||
**Note:** Docker Compose v2 is required (`docker compose`, not `docker-compose`) for its support of the `cgroup: host` option in `docker-compose.yaml` is only supported by Compose v2.
|
||||
[see documentation](https://docs.docker.com/engine/install/debian/#install-using-the-repository)
|
||||
```shell
|
||||
apt install docker-ce docker-compose-plugin docker.io- docker-compose-
|
||||
```
|
||||
|
||||
## Preliminary setup
|
||||
We use `chat.example.org` as the Chatmail domain in the following steps.
|
||||
@@ -75,6 +81,9 @@ docker compose up -d # start service
|
||||
docker compose logs -f chatmail # view container logs, press CTRL+C to exit
|
||||
```
|
||||
|
||||
### venv creation
|
||||
The first container start takes longer because it creates the cmdeploy Python virtualenv at `/opt/chatmail/venv` (persisted on the host via volume mount). Subsequent starts reuse the existing venv. Set `RECREATE_VENV=true` in `.env` to force a rebuild if needed.
|
||||
|
||||
6. After installation is complete, you can open `https://<your_domain_name>` in your browser.
|
||||
|
||||
## Using custom files
|
||||
@@ -114,6 +123,50 @@ docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Migrating from a bare-metal install
|
||||
|
||||
If you have an existing bare-metal Chatmail installation and want to switch to Docker:
|
||||
|
||||
1. Stop all existing services:
|
||||
|
||||
```shell
|
||||
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
|
||||
```
|
||||
|
||||
2. Convert your existing `chatmail.ini` to the Docker `.env` format:
|
||||
|
||||
```shell
|
||||
python3 docker/cm_ini_to_env.py /usr/local/lib/chatmaild/chatmail.ini .env
|
||||
```
|
||||
|
||||
3. Copy persistent data into the `./data/` subdirectories:
|
||||
|
||||
```shell
|
||||
mkdir -p data/chatmail-dkimkeys data/chatmail-acme data/chatmail
|
||||
|
||||
# DKIM keys
|
||||
cp -a /etc/dkimkeys/* data/chatmail-dkimkeys/
|
||||
|
||||
# ACME certificates and account
|
||||
rsync -a /var/lib/acme/ data/chatmail-acme/
|
||||
|
||||
# Mail data
|
||||
rsync -a /home/ data/chatmail/
|
||||
```
|
||||
|
||||
Alternatively, you can mount `/home/vmail` directly by changing the volume in `docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
- /home/vmail:/home/vmail
|
||||
```
|
||||
|
||||
The three `./data/` subdirectories cover all persistent state. Everything else is regenerated by the `configure` and `activate` stages on container start.
|
||||
|
||||
## Forcing a full reinstall
|
||||
|
||||
The Docker image bakes the install stage (binary downloads, package setup, chatmaild venv) into the image at build time. On container start, only the `configure` and `activate` stages run by default.
|
||||
|
||||
Reference in New Issue
Block a user