Stalwart
| Description / name | Input element |
|---|---|
| Container Registry | |
| Container Configuration Root Path | |
| Timezone | |
| Stalwart Host Port | |
| Stalwart /config Path |
Stalwart Mail Server is an open-source mail server solution with JMAP, IMAP4, POP3, and SMTP support and a wide range of modern features. It is written in Rust and designed to be secure, fast, robust and scalable.
| Port | 25 |
| Registry | ghcr.io/daemonless/stalwart |
| Daemonless | daemonless/stalwart |
| Source | stalw.art/ |
| Website | stalw.art |
Version Tags
Multi-arch manifests — resolve automatically to the right image for your platform.
| Tag | Description | Best For |
|---|---|---|
latest |
Upstream Binary. Built from official release. | Most users — recommended. |
pkg |
FreeBSD Quarterly. Uses stable, tested packages. | Production stability. |
pkg-latest |
FreeBSD Latest. Rolling package updates. | Staying current. |
| Tag | Description | Best For |
|---|---|---|
latest-amd64 |
Upstream Binary. Built from official release. | Most users — recommended. |
pkg-amd64 |
FreeBSD Quarterly. Uses stable, tested packages. | Production stability. |
pkg-latest-amd64 |
FreeBSD Latest. Rolling package updates. | Staying current. |
| Tag | Description | Best For |
|---|---|---|
latest-aarch64 |
Upstream Binary. Built from official release. | Most users — recommended. |
pkg-aarch64 |
FreeBSD Quarterly. Uses stable, tested packages. | Production stability. |
pkg-latest-aarch64 |
FreeBSD Latest. Rolling package updates. | Staying current. |
Before deploying, ensure your host environment is ready. See the Quick Start Guide for host setup instructions, including the security model for host vs. container privileges.
Deployment
Save as compose.yaml, then run podman-compose up -d.
Save as run.sh, then run sh run.sh.
Save as stalwart-deploy.yaml, then run ansible-playbook stalwart-deploy.yaml.
Warning
Exposing ports in AppJail means that your service can be reached from remote hosts. If that is not your intention, do not expose the ports and communicate with the service using the jail's IPv4 address or hostname assigned by the virtual network.
Save the files above, then run appjail-director up.
Save the files above, then run sh run.sh.
Experimental
Bastille's OCI support is experimental. It requires buildah and shares the host network stack (inherit). Mount volumes with --volume HOST JAIL; without it, image-declared volumes are stored under ${bastille_volumesdir}/${jail}.
Save as bastille-compose.yml, then run bastille up.
Access at: http://localhost:25
Interactive Configuration
Parameters
Environment Variables
| Variable | Default | Description |
|---|---|---|
TZ |
UTC |
Timezone for the container |
ADMIN_SECRET |
changeme |
Password for the fallback 'admin' web-admin account |
ENABLE_V4PROXY |
true |
Enable internal socat IPv4->IPv6 proxy on port 8080 for initial setup UI and healthchecks on FreeBSD (default true). Set false to disable. |
SKIP_CHOWN |
true |
Skip the startup recursive chown of /config once ownership is recorded in /config/.chown_done (default true). Set false to force a chown on every start. The marker lives in /config, so /config must be a persistent volume for the skip to take effect across restarts. |
Volumes
| Path | Description |
|---|---|
/config |
Config (config.toml) + rocksdb data store |
Ports
| Port | Protocol | Description |
|---|---|---|
25 |
TCP | SMTP |
465 |
TCP | SMTP submission (implicit TLS) |
587 |
TCP | SMTP submission (STARTTLS) |
143 |
TCP | IMAP4 |
993 |
TCP | IMAP4 (implicit TLS) |
110 |
TCP | POP3 |
995 |
TCP | POP3 (implicit TLS) |
4190 |
TCP | ManageSieve |
443 |
TCP | HTTPS / JMAP / web admin |
8080 |
TCP | HTTP / JMAP / web admin |
IPv4 / Dual-Stack & Internal Proxy Notes
- Internal IPv4 Proxy (
ENABLE_V4PROXY): Stalwartv0.16.xbootstrap mode binds to[::]:8080(IPv6). On FreeBSD (wherenet.inet6.ip6.v6only=1by default), accessinghttp://127.0.0.1:8080via IPv4 is refused. The container includes an internalsocathelper (stalwart-v4proxy) enabled by default (ENABLE_V4PROXY=true) that bridges IPv4 port 8080 to IPv6[::1]:8080. You can disable the internal proxy by settingENABLE_V4PROXY=false, or enable IPv4-mapping host-wide on FreeBSD by settingsysctl net.inet6.ip6.v6only=0. - External IPv4 Reverse Proxy / PROXY Protocol: If placing Stalwart behind an external IPv4 reverse proxy (Nginx, Traefik, HAProxy) or using PROXY protocol headers, add your proxy's IPv4 address/subnet (e.g.
127.0.0.1/32) toproxyTrustedNetworksunder Settings → Network → Services in Stalwart to prevent header parsing failures and proxy auto-bans.
Using PostgreSQL or SQLite instead of RocksDB
By default config.toml stores everything (data, full-text search, blobs,
and lookups) in RocksDB under /config/data. To swap in an external
PostgreSQL database instead, replace the [store."rocksdb"] section and
point [storage] at the new store:
For SQLite (a single-file database, good for small single-node setups):
Edit /config/config.toml after the first run seeds it, then restart the
container. Blob storage can also be split onto a separate store (e.g. keep
blob = "rocksdb" while data/fts/lookup move to PostgreSQL) — see
stalw.art/docs/storage for the full
per-store breakdown.
Implementation Details
- Architectures: amd64, aarch64
- User:
stalwart(UID/GID set via PUID/PGID). Defaults to1000:1000. - Base: Built on
ghcr.io/daemonless/base(FreeBSD 15.1).
Need help? Join our Discord community.