# # ============================================================================= # GENERAL CONFIGURATION # ============================================================================= # APP_NAME = name of application for use in scripts # COMPOSE_FILE = default for no app_name in docker-compose file name, app if there is # BACKUP = if true, include this application in backup operations # UPDATE_TYPE = auto: new image builds are applied automatically (a recovery snapshot is taken first), manual: only when you press Update # VERSION = the Stalwart release line this install tracks; drives the image tag. # The two settings do different jobs and are safe together: # UPDATE_TYPE=auto picks up REBUILDS of the version below (security/bug # patches) — snapshot, pull, recreate. Your data volume is untouched; # nothing is reinstalled. # Changing VERSION is how you move BETWEEN releases (v0.16 -> v0.17). # So patches land on their own, while a version jump stays a decision you # make — which matters while Stalwart is pre-1.0 and still settling its # storage schema. # HEALTHCHECK = if true, default docker health checks for that container will be enabled # AUTHELIA = if true, use Authelia authentication, if false turned off. # HEADSCALE = options : false, local, remote (see general config). e.g false or local,remote # CFG_STALWART_APP_NAME=stalwart # MULTI_INSTANCE = if true, this app can run as multiple isolated instances # (own data/DB/subdomain/backups) via `libreportal instance create`. Only set on # apps whose compose identity (container_name, Traefik routers, backup labels) # is instance-safe — see scripts/instance/instance_create.sh. # Not instance-safe. A mail server must own the SMTP/IMAP ports (25, 465, 587, 993); a second copy could not bind them. CFG_STALWART_MULTI_INSTANCE=false CFG_STALWART_BACKUP=true # STORAGE = which storage location holds this app's data. Change it with # `libreportal app move stalwart ` — editing here records intent only. CFG_STALWART_STORAGE=default # Storage Location - Which disk holds this app's data [default:Primary] # Mail is the one app where a "live" snapshot is a real risk: the message store # is being written continuously, so a copy taken mid-write can land mid-transaction. # stop-snapshot-start costs seconds of queued delivery (senders retry — that is # what SMTP does) and buys a consistent store. CFG_STALWART_BACKUP_STRATEGY=stop-snapshot-start CFG_STALWART_UPDATE_TYPE=auto CFG_STALWART_VERSION=v0.16 CFG_STALWART_COMPOSE_FILE=default CFG_STALWART_HEALTHCHECK=true CFG_STALWART_AUTHELIA=false CFG_STALWART_HEADSCALE=false # # ============================================================================= # METADATA # ============================================================================= # CATEGORY = application category for grouping # TITLE = display name for the application # DESCRIPTION = short description of the application # LONG_DESCRIPTION = detailed description of the application # URL = source repository or documentation URL # ACTIONS = available actions for this application # CFG_STALWART_CATEGORY="communication" CFG_STALWART_TITLE="Stalwart" CFG_STALWART_DESCRIPTION="Mail Server" CFG_STALWART_LONG_DESCRIPTION="An all-in-one mail and collaboration server — SMTP, IMAP, POP3 and JMAP plus calendars and contacts" CFG_STALWART_URL="https://github.com/stalwartlabs/stalwart" CFG_STALWART_ACTIONS="configure|install|restart|shutdown|uninstall" # # ============================================================================= # NETWORK CONFIGURATION # ============================================================================= # DOMAIN = number of domain from the general config, useful when using multiple domains # WHITELIST = if true only allow whitelisted ips (see general config), if false allow all # CFG_STALWART_DOMAIN=1 CFG_STALWART_WHITELIST=false CFG_STALWART_NETWORK=default # # MODE = who this mail server is for. This is the single most consequential # setting on the app, so it is worth reading before changing. # # private — mail stays on your own network. Stalwart still gives you # mailboxes, IMAP, calendars and contacts, and mail between local # accounts works normally. It just does not exchange mail with the # internet, so there is no MX, no reverse DNS, no port 25 and no # deliverability to worry about. Port 25 is not published at all; # the client ports stay bound to the host but are never opened # through the firewall. # # public — a real internet mail server. Needs outbound AND inbound port 25, # a matching reverse DNS record set by your VPS provider, and the # DNS records the installer prints. Be aware that deliverability is # a reputation game as much as a configuration one: a brand-new IP # is distrusted by large providers for weeks regardless of how # correct your setup is. That part no installer can fix for you. # # auto — decide at install time: public if Traefik is installed (which in # practice means you have a domain pointed here), private if not. # The resolved value is written back here, so this reads as a real # answer afterwards rather than staying 'auto'. # # Changing this later is supported — see the "Mail exposure" tool in the WebUI, # which flips the setting and reconfigures the server both ways. CFG_STALWART_MODE=auto # # ============================================================================= # PORT CONFIGURATION # ============================================================================= # PORT_ = port configuration: app|name|external:internal|access|protocol|login|traefik|webui|description|paths|subdomain # - app: application name # - name: service identifier (webui, dns, ssh, etc.) # - external:internal: port mapping (external can be 'random' for auto-allocation) # - access: 'public' (internet accessible), 'private' (local network only), 'disabled' (not running) # - protocol: 'tcp' or 'udp' # - login: if true, this port requires basic-auth via Traefik (only meaningful when traefik=true) # - traefik: if true, Traefik handles this port (reverse proxy) # - webui: if true, this port serves the main web interface # - description: human-readable description of the service # # MAIL PORTS ARE FIXED, NOT RANDOM. Every other app can take a random external # port because only a browser (via Traefik) reaches it. Mail is different: other # mail servers on the internet connect to port 25 by number, and mail clients # expect 465/587/993 — a randomised external port silently makes the server # unreachable. Only the admin UI gets a random port, because that one IS just a # browser behind Traefik. CFG_STALWART_PORT_1="stalwart-service|webui|random:8080|public|tcp|false|true|true|Admin Interface||mail" CFG_STALWART_PORT_2="stalwart-service|smtp|25:25|public|tcp|false|false|false|SMTP (server-to-server mail delivery)|" CFG_STALWART_PORT_3="stalwart-service|submissions|465:465|public|tcp|false|false|false|Mail submission (implicit TLS)|" CFG_STALWART_PORT_4="stalwart-service|submission|587:587|public|tcp|false|false|false|Mail submission (STARTTLS)|" CFG_STALWART_PORT_5="stalwart-service|imaps|993:993|public|tcp|false|false|false|IMAP (implicit TLS)|" CFG_STALWART_PORT_6="stalwart-service|imap|143:143|disabled|tcp|false|false|false|IMAP (STARTTLS) — enable only if a client needs it|" CFG_STALWART_PORT_7="stalwart-service|pop3s|995:995|disabled|tcp|false|false|false|POP3 (implicit TLS) — off by default, IMAP is preferred|" CFG_STALWART_PORT_8="stalwart-service|sieve|4190:4190|disabled|tcp|false|false|false|ManageSieve (client-managed mail filters)|" CFG_STALWART_PORT_9="stalwart-service|jmap|443:443|disabled|tcp|false|false|false|HTTPS/JMAP direct — leave disabled when Traefik fronts the UI|" # The password reaches the container through a compose environment variable, so # if you replace the generated one by hand keep it alphanumeric: docker compose # interpolates `$` and YAML treats ` #` as a comment, either of which would # silently mangle the value. The generator only emits letters and digits. CFG_STALWART_ADMIN_USER=admin CFG_STALWART_ADMIN_PASSWORD_1=RANDOMIZEDPASSWORD1 # # ============================================================================= # AUTOMATIC SETUP # ============================================================================= # Out of the box Stalwart opens a five-screen setup wizard on first sign-in and # waits for a human. LibrePortal already knows the answers that matter — the # hostname and the domain — so the installer fills the wizard in instead, and # the user's first sight of Stalwart is a configured mail server. # # CLI_VERSION = the version of the Stalwart CLI used to apply that setup. # Pinned, not ':latest', for the same reason the server image is: this writes # configuration, so an unattended jump to a new CLI is not something to # discover during an install. The CLI is a separate upstream project from the # server and is NOT included in the server image, which is why it is a # container of its own rather than something bundled. CFG_STALWART_CLI_VERSION=1.0.12 # # FIRST_MAILBOX = local part of one real mailbox created during setup. # Setup leaves you with admin@, which is an administrator account # rather than somewhere to read mail. 'postmaster' is the default for a # concrete reason: the generated zone file points DMARC and TLS-RPT reports at # postmaster@, and if nothing creates it those reports bounce. # Set empty to skip creating it. CFG_STALWART_FIRST_MAILBOX=postmaster CFG_STALWART_FIRST_MAILBOX_PASSWORD_1=RANDOMIZEDPASSWORD2 # # DNS_PROVIDER = 'manual', or a provider name to let Stalwart publish DNS itself. # On 'manual' the installer prints the full record set — including the real # DKIM public keys — for you to paste at your registrar. # Given a provider, Stalwart writes MX, SPF, DKIM, DMARC, MTA-STS, TLS-RPT, # SRV and CAA into the zone through the provider's API and keeps them in sync. # That also makes DKIM key rotation safe to leave switched on, since the server # republishes the records itself — hand-managed DKIM keys are, in practice, # keys nobody ever rotates. # # Wired up here: Cloudflare, DigitalOcean, DeSEC (token-only providers). # Route 53 and Google Cloud DNS need more than a token — set those up in the # admin console instead. # # The trade: the token is stored in the mail server's database and can write to # your zone, so compromising this box means compromising your DNS. Scope the # token to this one zone if your provider allows it. CFG_STALWART_DNS_PROVIDER=manual CFG_STALWART_DNS_API_TOKEN=