You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Security: byjpr/mailserver
Security
docs/security.md
Security design
This document lists what the server protects against and how. Most defaults
come from simple-nixos-mailserver (SNM); the rest is added in modules/.
Threats considered
Someone spoofs your domain: they send mail that claims to come from you.
Someone spoofs another domain to your users, e.g. phishing "from" a bank.
The server is abused to send spam, through an open relay, a guessed or
leaked password, or a compromised mail client.
Passive or active interception of mail in transit.
Compromise of the host through exposed services or weak administration.
Leaked secrets from the git repository or the Nix store.
1. Spoofing your domains
Measure
Where
SPF v=spf1 mx -all: only the MX host (and the relay, if configured) may send
lib/default.nix
DKIM signature on all outgoing mail, 2048-bit RSA, one key per domain, rotatable selectors
mail.nix, scripts/add-domain.sh
DMARC p=reject; sp=reject; adkim=s; aspf=s: receivers reject unauthenticated mail claiming to be from you, including from subdomains
lib/default.nix
SPF record for the HELO name, so bounces can be authenticated too
lib/default.nix
Port 25 refuses any envelope sender in your own domains. Your users send through port 465 with a password, so such mail is always forged
mail.nix (local_sender_domains)
Authenticated users can only send as their own address or aliases, both in the envelope (reject_sender_login_mismatch) and in the From: header recipients see (an Rspamd prefilter rejects anything else), so one user can't impersonate another
SNM, modules/rspamd/from-owner.lua
Aggregate DMARC reports are received at dmarc-reports@, so you see who tries to send as you
settings.nix
2. Spoofed and unwanted inbound mail
Measure
Where
Rspamd checks SPF, DKIM, DMARC and ARC on every message
SNM
DMARC policies are enforced: a message that fails DMARC for a domain publishing p=reject is rejected, and one under p=quarantine is marked as spam. By default Rspamd only adds a score
mail.nix (dmarc.conf)
Greylisting, DNS blocklists, Bayes, phishing and URL checks
Rspamd defaults
A local validating DNS resolver (Knot Resolver), so DNSBL queries aren't blocked as they are from public resolvers, and DNSSEC is validated for DANE
SNM
Strict SMTP: HELO required and must be a valid FQDN, sender and recipient domains must exist, pipelining before the greeting is rejected
mail.nix
Unknown recipients are rejected during the SMTP dialogue (no backscatter)
SNM (virtual_mailbox_maps)
3. Abuse of the server for sending spam
Measure
Where
No open relay: only authenticated users (and localhost) can send to external domains
SNM smtpd_relay_restrictions, mynetworks limited to localhost
Port 25 does not offer authentication at all, which removes it as a password-guessing target
mail.nix
Authentication only over TLS, only on port 465 and IMAP on 993
Per-IP authentication rate limit in Postfix, plus fail2ban bans after 3 failed logins (exponentially longer bans for repeat offenders)
mail.nix, hardening.nix
Passwords stored only as yescrypt hashes, at least 12 characters enforced by just passwd
scripts/passwd.sh
Privacy-sensitive headers (client IP, user agent) stripped from submitted mail
SNM
fail2ban deliberately doesn't watch port 25 protocol errors. Doing so
eventually bans the outbound servers of Gmail or Outlook over a single
misdirected message.
Implicit TLS for clients (993 and 465, RFC 8314); plaintext IMAP, POP3 and STARTTLS submission are disabled
mail.nix
MTA-STS policy in enforce mode, so other servers must use verified TLS when delivering to you
web.nix, lib/default.nix
TLS-RPT, so you get reports when someone fails to connect securely
lib/default.nix
Outgoing mail validates DANE and MTA-STS of the receiver (postfix-tlspol)
SNM
With a relay: certificate verification is mandatory (secure), so the relay password can never be sent in plaintext or to an impostor
relay.nix
CAA record: only Let's Encrypt may issue certificates for the mail host
lib/default.nix
5. Host hardening
Measure
Where
Only ports 22, 25, 80, 443, 465 and 993 are open (nftables on the host; on DigitalOcean also its cloud firewall). SSH is only accepted from sshAllowedCidrs
hardening.nix
SSH: keys only, no passwords, root only by key, modern algorithms only, no forwarding
hardening.nix
The server's SSH host key is generated by just init and pinned in known_hosts; no trust on first use
scripts/init.sh, scripts/install.sh
No passwords for any system user; immutable user database; sudo removed
hardening.nix
Kernel: restricted pointers, dmesg, BPF, ptrace and kexec; no ICMP redirects or source routing; rp_filter; SYN cookies; rarely used network protocols blacklisted
hardening.nix
nginx answers only for the mail host and the MTA-STS names; anything else gets a closed connection. No version banner
web.nix
The Rspamd web UI is only on a local Unix socket
SNM
Services run under systemd sandboxing where SNM/nixpkgs provide it
The server can't be destroyed by Terraform accidentally (prevent_destroy)
infra/servers/*/main.tf
The provider's SMTP-blocking network firewall is turned off on netcup (its default "Mail block" policy), with the host firewall doing the filtering
infra/servers/netcup/main.tf
6. Secrets
Secrets are encrypted with sops to two
age keys: yours, and one derived from the server's SSH host key. The server
decrypts them at boot into /run/secrets (tmpfs), readable only by the
service that needs each one. Nothing secret enters the Nix store, which is
world-readable.
The server's private SSH host key is stored in the repo encrypted to your
key only, and is copied to the server once during just install.
Mailbox passwords never exist anywhere in plaintext except while you type
them.
The public halves (DKIM public keys, host public key) are committed in
plaintext on purpose: they are needed to generate DNS records and
known_hosts.
If your age key leaks, generate a new one, update .sops.yaml, run
sops updatekeys secrets/*, and rotate the mailbox passwords and DKIM keys.
Not covered
Encryption at rest. The server's disk isn't encrypted (an unattended
server would need the key on the same machine).
Virus scanning (ClamAV) is off because of the 1 GB RAM budget; see the
README.
DNSSEC for your own zones is up to your DNS host; turn it on in
Cloudflare if you use it.
Two-factor authentication for IMAP/SMTP isn't something mail clients
support. Use long random passwords (just passwd <address> --random).