2026-08-12 12:56:22 +01:00
|
|
|
# Deploying mailgoserver
|
|
|
|
|
|
|
|
|
|
## Build
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cd mailgoserver
|
|
|
|
|
go build -o mailgoserver .
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
One static binary — no venv, no `pip install`, no gunicorn.
|
|
|
|
|
|
|
|
|
|
## Bind ports 25/587 without root
|
|
|
|
|
|
|
|
|
|
```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.
|
|
|
|
|
|
|
|
|
|
## systemd (unified process)
|
|
|
|
|
|
|
|
|
|
The Go binary runs the SMTP listeners and the web UI in one process (no GIL, so no
|
|
|
|
|
need to split them into separate services the way `script_install_service.sh` split
|
|
|
|
|
`pymta-smtp.service` / `pymta-web.service` for the Python version). One unit is enough:
|
|
|
|
|
|
|
|
|
|
```ini
|
|
|
|
|
[Unit]
|
|
|
|
|
Description=mailgoserver (SMTP + web admin)
|
|
|
|
|
After=network.target
|
|
|
|
|
|
|
|
|
|
[Service]
|
|
|
|
|
Type=simple
|
|
|
|
|
WorkingDirectory=/opt/mailgoserver
|
|
|
|
|
ExecStart=/opt/mailgoserver/mailgoserver --host 127.0.0.1 --port 5000
|
|
|
|
|
Restart=always
|
|
|
|
|
RestartSec=5
|
|
|
|
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
|
|
|
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
|
|
|
|
PrivateTmp=true
|
|
|
|
|
ProtectSystem=strict
|
|
|
|
|
ReadWritePaths=/opt/mailgoserver
|
|
|
|
|
ProtectHome=true
|
|
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
|
WantedBy=multi-user.target
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If you do want the SMTP and web parts as separate services (matching the Python
|
|
|
|
|
split exactly), run two units with `--smtp-only` and `--web-only` respectively —
|
|
|
|
|
both flags exist for this.
|
|
|
|
|
|
|
|
|
|
## nginx
|
|
|
|
|
|
|
|
|
|
No changes needed. `script_nginx_setup.sh` reverse-proxies to `http://127.0.0.1:5000`
|
|
|
|
|
and terminates its own TLS for the web UI — mailgoserver listens on the same host:port
|
|
|
|
|
by default, so the existing nginx config works unmodified. The SMTP TLS listener still
|
|
|
|
|
consumes `ssl_certs/server.crt`/`server.key`, same as before.
|
|
|
|
|
|
|
|
|
|
## Admin dashboard login
|
|
|
|
|
|
|
|
|
|
First run seeds one 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.
|
|
|
|
|
|
|
|
|
|
Optional second factors, enabled per-account from **Account** in the sidebar:
|
|
|
|
|
- **Authenticator app (TOTP)** — works anywhere, no extra config.
|
|
|
|
|
- **Passkeys / security keys (WebAuthn)** — bound to the exact origin the dashboard
|
|
|
|
|
is served at. Set `[Auth] rp_id` / `rp_origin` in `settings.ini` to your real public
|
|
|
|
|
domain before registering passkeys in production (e.g. `rp_id = mail.example.com`,
|
|
|
|
|
`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.
|
2026-08-12 12:59:59 +01:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
See [LICENSE](LICENSE).
|