add docker setup
This commit is contained in:
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user