MAIL SERVER — NIX

Ghost

Ghost

Source on GitHub

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

  1. 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. 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.
  3. 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.
  4. 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`).
  5. 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.
  6. 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.
How it works, step by step — each step as the project's own documentation states it.

CONCEPTS

ONE NIXOS MODULE — THE WHOLE MAIL STACKINTERNETinbound SMTPPOSTFIXreceive + submitRSPAMDfilter + signDOVECOTLMTP deliveryMAILDIRper-user storeAUTHENTICATION GATES — ANSWERED FROM DNS TXT RECORDSSPFDKIMDMARCgreylisting — and antivirus, if enabled — run in the same rspamd passSUBMISSIONauthenticated userPOSTFIXsender-login mapDKIM-SIGNselector + key from configINTERNETpublic key in DNSCLIENTS READ VIA IMAP — DOVECOT SERVES THE SAME MAILDIRthe same module also runs nginx (ACME + web) and kresd (local DNS resolver)
Ghost's mail stack as its NixOS module wires it: Postfix receives SMTP, Rspamd runs the SPF/DKIM/DMARC authentication gates (with greylisting and optional antivirus), Dovecot delivers by LMTP into the maildir, and outbound mail leaves DKIM-signed by Rspamd — component roles and options as default.nix and docs/quickstart.rst state them.

CONFIGURATION

OptionDefaultWhat it does
ghost.enable`false` (mkEnableOption)Enable the Ghost mail server
ghost.openFirewalltrueAutomatically open ports in the firewall
ghost.fqdnno default (required; example `mx.example.com`)The fully qualified domain name of the ghost server
ghost.domains[ ]The domains that ghost serves
ghost.certificateSchemeselfsignedTLS certificate scheme: `manual`, `selfsigned`, `acme-nginx`, or `acme`
ghost.messageSizeLimit20971520Message size limit enforced by Postfix (bytes; example `52428800`)
ghost.loginAccounts.<name>.hashedPasswordFilenullFile 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>.sendOnlyfalseSend-only account; mail to it is rejected from unauthorized senders
ghost.loginAccounts.<name>.sieveScriptnullPer-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/mailWhere to store mail (rootless/XDG default per the option text)
ghost.enableImaptrueIMAP with STARTTLS on port 1143 (per the option text)
ghost.enableImapSsltrueIMAP with TLS in wrapper mode on port 1993 (per the option text)
ghost.enableSubmissiontrueSMTP submission with STARTTLS on port 1587 (per the option text)
ghost.enableSubmissionSsltrueSMTP submission with TLS in wrapper mode on port 1465 (per the option text)
ghost.enablePop3` / `ghost.enablePop3Sslfalse` / `falsePOP3 (STARTTLS, port 1110) / POP3-TLS (wrapper mode, port 1995), per the option text
ghost.enableManageSievefalseManageSieve on port 5190
ghost.virusScanningfalseActivate virus scanning (ClamAV)
ghost.dkimSigningtrueActivate 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.dkimKeyBits2048For 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.localDnsResolvertrueRun a local DNS resolver (kresd), as recommended with Rspamd
ghost.recipientDelimiter+Recipient delimiter for `user+detail@` filing
ghost.maxConnectionsPerUser100Maximum IMAP/POP3 connections per user per IP
ghost.fullTextSearch.enable`false` (mkEnableOption)Full-text search indexing with Xapian via fts_flatcurve
ghost.fullTextSearch.autoIndextrueAutomatically 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.debugfalseVerbose logging for ghost-related services (development)

CONTROLS

ActionControl
Deploy / apply the server configuration`nixos-rebuild switch` (after importing the module and setting `ghost = { … }`)
Create a login-account password hashnix-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 recordCopy 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 clientTor 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

  1. RFC 5321 — Simple Mail Transfer ProtocolThe SMTP protocol Postfix speaks when Ghost receives and submits mail.
  2. 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.
  3. RFC 7208 — Sender Policy Framework (SPF)The sender-policy framework one of Rspamd's inbound authentication gates evaluates.
  4. 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.
  5. Rspamd documentationThe filter Ghost embeds: its SPF/DKIM/DMARC checks, greylisting, and DKIM signing are documented here.