add docker setup

This commit is contained in:
2026-08-15 06:22:02 +01:00
parent 892f366a16
commit 310700407e
11 changed files with 410 additions and 19 deletions
+112 -6
View File
@@ -1,4 +1,89 @@
# Deploying mailgoserver
# mailgoserver
A self-hosted email server in one static Go binary: SMTP (send + receive, direct-to-MX
delivery, DKIM signing), IMAP mailbox storage, an admin web dashboard, and a self-service
webmail portal. It's a Go port of PyMTA-server — same feature set, one process instead of
a Python venv + separate services.
## What it does
- **SMTP MTA** — accepts mail for domains you configure, relays outbound mail directly
to the recipient's MX (no smarthost needed), signs outgoing mail with DKIM, and
enforces per-domain sender authentication or IP whitelisting so it can't be used as an
open relay.
- **IMAP mailbox storage** — real, retrievable mailboxes (Thunderbird, Outlook, any IMAP
client) with AES-encrypted-at-rest message storage, per-mailbox quotas, send-as
aliases, and filter rules (move to folder, forward, discard, based on from/subject/
body conditions with AND/OR logic).
- **Spam filtering** — a built-in heuristic score always runs; optionally point it at an
[rspamd](https://rspamd.com) instance for a lot more signal (see `docker-deploy/` for
a container that bundles rspamd for you).
- **Webmail portal** (`/webmail`) — inbox/folders, HTML compose with attachments,
drafts, search, keyboard shortcuts, conversation grouping, recipient autocomplete,
filter-rule management, and PGP (OpenPGP encrypt/decrypt/sign/verify) and S/MIME
(sign/verify) support per mailbox.
- **Admin dashboard** (`/pymta-manager`) — manage domains, senders, mailboxes, DKIM
keys, IP whitelisting, TLS (self-signed or Let's Encrypt via DNS-01: Cloudflare,
Route53, DigitalOcean, Google Cloud DNS), and review email + auth logs.
- **Security hardening built in** — CSRF protection, security headers (CSP, X-Frame-
Options, etc.), Cloudflare-aware trusted-proxy IP resolution, login rate limiting and
account lockout, TOTP + WebAuthn/passkey MFA (admin and mailbox owners), and automatic
temporary IP blacklisting for SMTP/IMAP brute-force or relay-abuse attempts with an
admin-visible Blacklist page and dashboard attack-count tiles.
## Quick start
### Docker (fastest)
```bash
cd docker-deploy
docker compose --profile standalone up -d --build
```
See [`docker-deploy/README.md`](docker-deploy/README.md) for the rspamd-bundled variant
and full details (ports, volumes, first-boot config).
### From source
```bash
go build -o mailgoserver .
./mailgoserver
```
One static binary — no venv, no `pip install`, no gunicorn. Requires Go 1.26+ to build;
the binary itself has no runtime dependencies (pure-Go SQLite driver, no cgo).
## What to expect on first run
There's no config to write up front. The first time it starts in a given working
directory, it generates:
- `settings.ini` — every setting with an inline comment explaining it (SMTP/IMAP ports,
hostname, TLS, DKIM key size, mailbox quotas, MFA enforcement, rate limits, and so
on). Regenerated only if missing — it's never overwritten or merged into on later
runs, so edits stick.
- A self-signed TLS certificate (used until you either supply your own or enable Let's
Encrypt from the admin dashboard).
- An empty SQLite database, with one seeded admin account: username `admin`, password
`Password123!`. Logging in with it **immediately forces** a username + password
change before anything else in the dashboard is reachable — the default credentials
can never be left in place.
- A mailstore master key and a CSRF-signing app secret, both generated once and reused
on every subsequent start — back these up like any other secret (losing the mailstore
master key makes all stored mail unrecoverable, even for admins).
From there: log into `/pymta-manager`, add a domain (and complete its DNS ownership
verification), add a mailbox or sender, and you're sending/receiving. The bare `/` root
redirects to the webmail login (`/webmail/login`) by default, since most visitors are
mailbox owners, not admins — there's a "Login as Admin" link from there to
`/pymta-manager`.
Default ports (all configurable in `settings.ini`): SMTP `25`, direct-TLS SMTP `465`,
IMAP `143`, direct-TLS IMAP `993` — the real standard mail ports, so binding them
directly needs root or `setcap` (see below), which the Docker deployment already
handles for you. Admin/webmail HTTP `5000` / HTTPS `5001` stay deliberately
non-privileged; put a reverse proxy or your own `80`/`443` mapping in front of those if
you want the dashboard on standard web ports too.
## Build
@@ -7,15 +92,20 @@ cd mailgoserver
go build -o mailgoserver .
```
One static binary — no venv, no `pip install`, no gunicorn.
## Bind ports 25/143/465/993 without root
## Bind ports 25/587 without root
The default SMTP/IMAP ports are the real standard ones now, so running the binary
directly (not via Docker) needs one of:
```bash
sudo setcap 'cap_net_bind_service=+ep' ./mailgoserver
```
Same purpose as `script_setup_py_environment.sh`'s `setcap` step on the Python venv, applied to the compiled binary instead.
or run it as root, or via the systemd unit below (which grants the capability instead
of running as root). Same purpose as `script_setup_py_environment.sh`'s `setcap` step
on the Python venv, applied to the compiled binary instead. **Not needed for the Docker
deployment** — those containers run as root, so binding 25/143/465/993 directly just
works with no extra setup.
## systemd (unified process)
@@ -56,6 +146,12 @@ and terminates its own TLS for the web UI — mailgoserver listens on the same h
by default, so the existing nginx config works unmodified. The SMTP TLS listener still
consumes `ssl_certs/server.crt`/`server.key`, same as before.
## Docker
See [`docker-deploy/`](docker-deploy/) — a standalone image and one that bundles the
latest rspamd in the same container, both via a single `docker-compose.yml` using
Compose profiles.
## Admin dashboard login
First run seeds one account: username `admin`, password `Password123!`. Logging in
@@ -70,10 +166,20 @@ Optional second factors, enabled per-account from **Account** in the sidebar:
`rp_origin = https://mail.example.com`). The defaults (`localhost` /
`http://localhost:5000`) only work for local testing — WebAuthn requires either
HTTPS or the literal host `localhost`, so passkeys need the nginx+TLS setup above
to work behind a real domain.
(or the Docker deployment) to work behind a real domain.
## Abuse protection
Failed SMTP/IMAP auth attempts (bad passwords, denied relay attempts) are counted per
source IP; once a configurable threshold is hit within a window, that IP is temporarily
blocked at the listener level — before the SMTP/IMAP banner is even sent — with the
block duration doubling on repeat offenses up to a cap. Manage active blocks and exempt
trusted IPs from this check entirely from **Blacklist** in the admin sidebar (a global-
admin-only page) — this is separate from the IP whitelist used to authorize
unauthenticated relay for a domain. Tunable in `settings.ini`'s `[Security]` section.
---
## License
See [LICENSE](LICENSE).
See [LICENSE](LICENSE).