Files
proxy/resources/config.sample.toml
T
2026-06-08 16:57:10 +02:00

168 lines
4.9 KiB
TOML

# Migration proxy sample configuration.
#
# This is a starting template. Edit the destinations, mappings, TLS
# certificates and admin token to match your deployment, then start the
# service. The proxy refuses to boot until every referenced destination,
# certificate and credential path is valid (see SPEC section 8.4).
#
# Run with: proxy /etc/proxy/config.toml
# Or set: PROXY_CONFIG=/etc/proxy/config.toml
[server]
# Worker threads (0 = one per CPU).
threads = 0
# Hostname advertised in protocol greetings; defaults to the local IP.
hostname = "proxy.example.com"
shutdown_grace = "30s"
log_level = "info"
# TLS certificates used to TERMINATE inbound implicit-TLS and STARTTLS.
# Multiple certificates are selected by SNI. Mark one as the default.
[tls.certificate.default]
cert = "/etc/proxy/tls/fullchain.pem"
key = "/etc/proxy/tls/privkey.pem"
default = true
[tls.protocols]
min_version = "1.2"
# ---------------------------------------------------------------------------
# Routing: which destination handles an identifier when it is missing or
# unmapped, and (optionally) where raw SMTP/25 and LMTP/24 traffic is sent.
# ---------------------------------------------------------------------------
[routing]
default_destination = "legacy"
# smtp_passthrough_destination = "stalwart"
# ---------------------------------------------------------------------------
# Mappings: identifier -> destination id. Source is "file", "redis" or "sql".
# ---------------------------------------------------------------------------
[mapping]
source = "file"
normalize = "lowercase"
negative_ttl = "30s"
positive_ttl = "10m"
[mapping.file]
path = "/etc/proxy/mappings.tsv"
# [mapping.redis]
# url = "redis://10.0.0.5:6379"
# key_prefix = "route:"
# [mapping.sql]
# url = "postgres://user:pass@10.0.0.6/proxy"
# query = "SELECT destination FROM routes WHERE identifier = $1"
# ---------------------------------------------------------------------------
# Destinations. The default destination must support every listener protocol
# declared below. Each destination lists the per-protocol backend port and the
# TLS mode the proxy must use on the OUTBOUND leg.
# ---------------------------------------------------------------------------
[destination.legacy]
host = "10.0.1.10"
tls_server_name = "mail.legacy.example.com"
proxy_protocol = true
[destination.legacy.protocol.imap]
port = 993
tls = "implicit"
[destination.legacy.protocol.pop3]
port = 995
tls = "implicit"
[destination.legacy.protocol.submission]
port = 587
tls = "starttls"
[destination.legacy.protocol.managesieve]
port = 4190
tls = "starttls"
[destination.legacy.protocol.http]
port = 443
tls = "implicit"
[destination.stalwart]
host = "10.0.1.20"
tls_server_name = "mail.new.example.com"
proxy_protocol = true
[destination.stalwart.protocol.imap]
port = 993
tls = "implicit"
[destination.stalwart.protocol.pop3]
port = 995
tls = "implicit"
[destination.stalwart.protocol.submission]
port = 587
tls = "starttls"
[destination.stalwart.protocol.managesieve]
port = 4190
tls = "starttls"
[destination.stalwart.protocol.http]
port = 443
tls = "implicit"
# ---------------------------------------------------------------------------
# Listeners: one entry per protocol + TLS mode + bind set.
# tls = "implicit" | "starttls" | "plain".
# ---------------------------------------------------------------------------
[listener.imap]
protocol = "imap"
bind = ["0.0.0.0:993", "[::]:993"]
tls = "implicit"
[listener.imap-starttls]
protocol = "imap"
bind = ["0.0.0.0:143", "[::]:143"]
tls = "starttls"
[listener.pop3]
protocol = "pop3"
bind = ["0.0.0.0:995", "[::]:995"]
tls = "implicit"
[listener.submission]
protocol = "submission"
bind = ["0.0.0.0:587", "[::]:587"]
tls = "starttls"
[listener.submissions]
protocol = "submission"
bind = ["0.0.0.0:465", "[::]:465"]
tls = "implicit"
[listener.managesieve]
protocol = "managesieve"
bind = ["0.0.0.0:4190", "[::]:4190"]
tls = "starttls"
[listener.https]
protocol = "http"
bind = ["0.0.0.0:443", "[::]:443"]
tls = "implicit"
forwarded = "off"
# ---------------------------------------------------------------------------
# HTTP routing rules. First match wins. A rule pins a destination by path, or
# extracts an account identifier and routes it through the mapping store.
# ---------------------------------------------------------------------------
[[http.route]]
match = "/.well-known/**"
destination = "legacy"
[[http.route]]
match = "/**"
extract = { from = "authorization" }
fallback = "default"
# ---------------------------------------------------------------------------
# Admin listener: the cache-integrity boundary. Bind to loopback or a dedicated
# management network only. TLS is mandatory; plaintext admin is rejected.
# ---------------------------------------------------------------------------
[admin]
bind = "127.0.0.1:9443"
tls = "implicit"
bearer_token_file = "/etc/proxy/admin.token"
min_token_len = 32
lockout_threshold = 5
lockout_duration = "5m"