MAIL SERVER — NIX

Ghost
OVERVIEW
Ghost is the Qompass AI Ghost Mail Server (GitHub repo description): a NixOS module (`ghost = { … }`) that runs a complete mail server — Postfix, Dovecot, Rspamd, nginx, and a local DNS resolver — from one declarative configuration, plus a Tor-native Android mail client in the same repo. The README titles it "Qompass AI Gateway Hosting Onion Secure Transmission (Ghost) Protocol."
HOW IT WORKS
- 1You set the minimum DNS first (A/AAAA for `mail.<domain>`), import the module into a NixOS configuration, set `ghost.enable`, `ghost.fqdn`, and `ghost.domains`, and declare `ghost.loginAccounts` with hashed-password files.
- 2`nixos-rebuild switch` brings up all mail components: Postfix receives/submits SMTP, Dovecot serves IMAP/POP3 and LMTP delivery, Rspamd filters spam and signs DKIM, nginx serves the ACME challenge and web surfaces, and kresd runs as the local DNS resolver.
- 3Inbound mail is checked by Rspamd (SPF/DKIM/DMARC, greylisting, antivirus if enabled), delivered by Dovecot LMTP into `ghost.mailDirectory` — honoring per-user Sieve scripts, `+detail` filing, aliases, catch-all lists, and forwards defined in the config.
- 4Account aliases both receive mail for the mailbox and grant send-as rights via the Postfix sender-login map; a separate send-only login can be granted exactly one sender identity via `extraSenderLogins` (the production pattern in `examples/qompass-ai.nix`).
- 5Outbound mail is DKIM-signed by Rspamd (selector/key type from config; the rspamd service generates the public-key file you publish in DNS), and you complete deliverability by publishing MX, SPF, DKIM, DMARC, and reverse-DNS records as the quickstart prescribes.
- 6Clients connect over the enabled services — IMAP/IMAP-TLS, submission/submission-TLS, optionally POP3 and ManageSieve — or, on Android, through the repo's Tor-only client: Tor bootstrap, then IMAP (993) + SMTP (465) through Tor's SOCKS5 proxy with OpenPGP encryption and no clearnet connection.
CONCEPTS
CONFIGURATION
| Option | Default | What it does |
|---|---|---|
ghost.enable | `false` (mkEnableOption) | Enable the Ghost mail server |
ghost.openFirewall | true | Automatically open ports in the firewall |
ghost.fqdn | no default (required; example `mx.example.com`) | The fully qualified domain name of the ghost server |
ghost.domains | [ ] | The domains that ghost serves |
ghost.certificateScheme | selfsigned | TLS certificate scheme: `manual`, `selfsigned`, `acme-nginx`, or `acme` |
ghost.messageSizeLimit | 20971520 | Message size limit enforced by Postfix (bytes; example `52428800`) |
ghost.loginAccounts.<name>.hashedPasswordFile | null | File containing the user's hashed password (preferred over inline `hashedPassword`) |
ghost.loginAccounts.<name>.aliases | [ ] | Aliases of this login account (also grant send-as rights) |
ghost.loginAccounts.<name>.catchAll | [ ] | Domains for which this account acts as catch-all (production example leaves it `[ ]` — catch-all OFF) |
ghost.loginAccounts.<name>.quota | `null` (standard quota `100G` per the option text) | Per-user quota, e.g. `2G` |
ghost.loginAccounts.<name>.sendOnly | false | Send-only account; mail to it is rejected from unauthorized senders |
ghost.loginAccounts.<name>.sieveScript | null | Per-user Sieve script |
ghost.extraVirtualAliases | { } | Virtual aliases forwarding mail to a login account (production pattern: role addresses as aliases of the human mailbox) |
ghost.forwards | { } | Forward mail to an external address |
ghost.mailDirectory | $XDG_DATA_HOME/mail | Where to store mail (rootless/XDG default per the option text) |
ghost.enableImap | true | IMAP with STARTTLS on port 1143 (per the option text) |
ghost.enableImapSsl | true | IMAP with TLS in wrapper mode on port 1993 (per the option text) |
ghost.enableSubmission | true | SMTP submission with STARTTLS on port 1587 (per the option text) |
ghost.enableSubmissionSsl | true | SMTP submission with TLS in wrapper mode on port 1465 (per the option text) |
ghost.enablePop3` / `ghost.enablePop3Ssl | false` / `false | POP3 (STARTTLS, port 1110) / POP3-TLS (wrapper mode, port 1995), per the option text |
ghost.enableManageSieve | false | ManageSieve on port 5190 |
ghost.virusScanning | false | Activate virus scanning (ClamAV) |
ghost.dkimSigning | true | Activate DKIM signing |
ghost.dkimSelector | `mail` (module default; production example uses `ghost`) | The DKIM selector |
ghost.dkimKeyType | `ed25519` (module default; production example uses `rsa`) | DKIM key type: `rsa` or `ed25519` |
ghost.dkimKeyBits | 2048 | For RSA, number of bits in the DKIM key |
ghost.dkimKeyDirectory | `$HOME/.local/share/dkim` (production example overrides to `/var/lib/ghost/dkim`) | Directory for DKIM private keys |
ghost.localDnsResolver | true | Run a local DNS resolver (kresd), as recommended with Rspamd |
ghost.recipientDelimiter | + | Recipient delimiter for `user+detail@` filing |
ghost.maxConnectionsPerUser | 100 | Maximum IMAP/POP3 connections per user per IP |
ghost.fullTextSearch.enable | `false` (mkEnableOption) | Full-text search indexing with Xapian via fts_flatcurve |
ghost.fullTextSearch.autoIndex | true | Automatically index messages as they are received or modified |
ghost.monitoring.enable | `false` (mkEnableOption) | Monitoring via monit |
ghost.borgbackup.enable | `false` (mkEnableOption) | Backup via borgbackup; `borgbackup.startAt` default `hourly` |
ghost.backup.enable | `false` (mkEnableOption) | Backup via rsnapshot; retain defaults hourly 24 / daily 7 / weekly 54 |
ghost.debug | false | Verbose logging for ghost-related services (development) |
CONTROLS
| Action | Control |
|---|---|
| Deploy / apply the server configuration | `nixos-rebuild switch` (after importing the module and setting `ghost = { … }`) |
| Create a login-account password hash | nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' |
| Check DNS propagation during setup | `nix-shell -p bind --command "host -t A mail.example.com"` (and the AAAA/MX/TXT/rDNS variants in the guide) |
| Accept Let's Encrypt terms (with `certificateScheme = "acme-nginx"`) | `security.acme.acceptTerms = true;` and `security.acme.defaults.email = "…";` in the NixOS config |
| Publish the DKIM record | Copy the public key the rspamd service generated (quickstart: `/var/dkim/example.com.mail.txt`) into a `mail._domainkey` TXT record |
| Build the Android client | `cd android && ./gradlew assembleRelease` (Android SDK 35, JDK 17) |
| Use the Android client | Tor bootstrap with progress UI, then inbox/compose over IMAP+SMTP through Tor; foreground service keeps the onion connection alive during sync |
NOT COVERED
- The README is mostly boilerplate; the mail-server behavior above is sourced from `default.nix`, `docs/quickstart.rst`, and `examples/qompass-ai.nix`, not from a narrative README section. - `default.nix` was read from the sandbox clone (`~/workspace/repos/ghost`, Oct 5); the GitHub tree listing matches the same file layout, but every option default was not re-verified byte-for-byte against GitHub HEAD. - The repo also ships legacy mail-hosting material (`etc/`, `www/`, `setup.php`, the SquirrelMail patches); whether it is live or legacy is not stated in the files read, so it is not described above. - The Android client's "What it is not (v1)" notes in `android/README.md` say there is no message-reader detail view yet, while the source tree contains a `MessageReaderScreen.kt`; the README statement is the one recorded here and the discrepancy is flagged, not resolved.
REFERENCES
- RFC 5321 — Simple Mail Transfer ProtocolThe SMTP protocol Postfix speaks when Ghost receives and submits mail.
- RFC 6376 — DomainKeys Identified Mail (DKIM) SignaturesThe signing scheme Rspamd applies to Ghost's outbound mail; the public key is the DNS TXT record the quickstart has you publish.
- RFC 7208 — Sender Policy Framework (SPF)The sender-policy framework one of Rspamd's inbound authentication gates evaluates.
- RFC 7489 — Domain-based Message Authentication, Reporting, and Conformance (DMARC)The policy layer that ties SPF and DKIM results to the sender domain on inbound checks.
- Rspamd documentationThe filter Ghost embeds: its SPF/DKIM/DMARC checks, greylisting, and DKIM signing are documented here.