Files
mailgoserver/docker-deploy
2026-08-15 06:22:02 +01:00
..
2026-08-15 06:22:02 +01:00
2026-08-15 06:22:02 +01:00
2026-08-15 06:22:02 +01:00
2026-08-15 06:22:02 +01:00
2026-08-15 06:22:02 +01:00
2026-08-15 06:22:02 +01:00

Docker deployment

Two independent images, both built from the same source tree:

  • Dockerfile — mailgoserver only.
  • Dockerfile.rspamd — mailgoserver + the latest rspamd in the same container, already wired together (see below). Use this one if you want stronger spam filtering than the built-in heuristic score alone.

docker-compose.yml defines both as Compose profiles so a plain docker compose up can't accidentally start both at once:

cd docker-deploy

# mailserver only
docker compose --profile standalone up -d --build

# mailserver + rspamd, bundled
docker compose --profile with-rspamd up -d --build

Either way, the app itself now binds the real standard mail ports by default — 25 (SMTP), 465 (direct-TLS SMTP), 143 (IMAP), 993 (direct-TLS IMAP) — and the admin/webmail UI on its usual non-privileged 5000/5001 (HTTP/HTTPS); put your own reverse proxy or a 80:5000/443:5001 port mapping in front if you want those on 80/443 too. Binding the low mail ports needs no extra capability here since the container runs as root. Copy .env.example to .env in this folder to change any host-side port — useful if something else on the host already owns 25/143/etc., or if you want to run both profiles side by side.

What happens on first boot

There's no baked-in config. On first start, the binary generates a fresh settings.ini with defaults (mirroring internal/config/config.go), a self-signed TLS certificate, DKIM/mailstore master keys, and an empty SQLite database — all inside the /app/data volume, so it survives container restarts/rebuilds. The web UI seeds one admin account: username admin, password Password123!, and forces an immediate username + password change on first login — see the main README for the full first-login walkthrough.

Before using this for real mail, exec into the container (or edit the volume from the host) and update settings.ini:

docker exec -it mailgoserver sh -c 'vi /app/data/settings.ini'
docker restart mailgoserver

At minimum, set [Server] HOSTNAME / helo_hostname to your real mail domain, and if you'll use passkeys, [Auth] rp_id / rp_origin to match the exact domain the admin dashboard is reached at (rp_id can't be localhost once you're on a real domain — see the main README's WebAuthn note). There's no environment-variable override mechanism — settings.ini in the volume is the one source of config truth.

Enabling rspamd (the with-rspamd profile)

The bundled rspamd's default config already listens on 127.0.0.1:11333 for scanning requests — exactly what [Rspamd] url defaults to in settings.ini, and since both processes share the container's network namespace, no networking setup is needed. All that's left is turning it on:

[Rspamd]
enabled      = true
url          = http://127.0.0.1:11333
reject_score = 15

...then restart the container. The built-in heuristic spam score (internal/mailstore/spam.go) always runs regardless of this setting — rspamd is additive, not a replacement, and if it's ever unreachable, mail still flows on the heuristic score alone (rspamd errors are logged, never fatal to delivery).

This bundle intentionally skips Redis — rspamd runs fine without it for SPF/DKIM/RBL/ regexp-based scoring, but Bayes learning and greylisting need it. Add a redis service to docker-compose.yml and point rspamd's redis.conf at it if you need those.

Persistence

Volume What's in it
mailserver-data / mailserver-rspamd-data settings.ini, the SQLite DB, encrypted mailbox storage, DKIM/mailstore master keys, TLS certs, the CSRF app secret — everything mailgoserver itself owns.
rspamd-data (rspamd profile only) rspamd's own Bayes/fuzzy-hash storage, so spam-learning state survives image rebuilds.

Back up the *-data volume like you would the equivalent bare-metal server_data/ directory — losing the mailstore master key makes all stored mail unrecoverable, same as a non-Docker install.

Logs / health

docker compose --profile standalone logs -f      # or --profile with-rspamd
docker inspect --format '{{.State.Health.Status}}' mailgoserver

Both images expose GET /health (used by the container HEALTHCHECK), matching the JSON the admin dashboard's own health check reads.