Skip to content

Config file

atreoAGENT keeps its configuration in a YAML file at /var/lib/atreoagent/config.yaml. Most fields populate themselves: at install time the file doesn’t exist, and pairing fills in the device-specific values. You only edit it for networking, proxy, or feature toggles.

# Set automatically during pairing
device_token: ""
device_id: ""
# Hostname used for app subdomains. Set automatically at pair time
# (e.g. "alice.atreo.link", or your custom domain once attached).
# The TLS cert is *.<apps_hostname>.
apps_hostname: alice.atreo.link
# Log verbosity: debug | info | warn | error (default: info)
log_level: info
# Persistent data directory
data_dir: /var/lib/atreoagent
# Optional public-IP override; leave empty to auto-detect
endpoint_ip: ""
endpoint_port: 0
# WireGuard tunnel settings
wireguard:
listen_port: 51820
firewall_enabled: true
upnp_enabled: true # master switch for auto port-opening; a manual port forward works too
pcp_enabled: true # try PCP (RFC 6887) first, for both IPv4 and IPv6
ipv6_pinhole_enabled: true # open an IPv6 firewall pinhole for the WireGuard port
# CGNAT relay fallback (on by default; used only when there's no public
# inbound path). Set enabled false to opt out; force keeps a relay session up
# even when a direct path exists.
relay:
enabled: true
force: false
# Reverse proxy settings
proxy:
enabled: true
http_port: 80
https_port: 443
auth_port: 9091
trusted_networks: [] # empty by default; opt in to specific CIDRs
trusted_proxies: [] # external reverse proxies allowed to set X-Forwarded-*
# TLS certificate settings
certs:
email: you@example.com
cert_dir: /var/lib/atreoagent/certs
# Notification API
notify:
port: 9876
# Built-in SMTP server (off by default; LAN-only)
smtp:
enabled: false
listen: "0.0.0.0:2525"
max_message_bytes: 1048576
rate_per_minute: 50
tls_enabled: false # advertise STARTTLS via a self-signed cert (TLS 1.3)
catch_all: "" # unmatched RCPT TO -> this member's email; empty = reject (default)
# Source-IP allowlist. Unset = loopback + RFC1918 + link-local + ULA + the
# WireGuard tunnel subnet. Connections from outside the list are rejected
# before AUTH. Example to widen to one extra LAN:
# trusted_networks:
# - "192.168.50.0/24"

The full hostname under which apps are served for this device. Populated by atreoLINK at pair time. Examples:

  • alice.atreo.link for the SaaS default subdomain.
  • home.example.com for a custom domain.

The agent requests a wildcard TLS certificate for *.<apps_hostname> and uses this value as the suffix it strips when extracting the app slug from incoming hostnames.

Log verbosity. Accepts debug, info, warn (or warning), and error, case-insensitive. Defaults to info. An unrecognised value causes the agent to refuse to start. Overridden by the LOG_LEVEL environment variable.

Field Default Description
listen_port 51820 UDP port WireGuard listens on.
firewall_enabled true Confine tunnel peers to the proxy ports, plus the raw host ports each member is granted via exposed-port apps — a member only reaches the ports they’ve been given. Fails closed: if iptables/ip6tables is unavailable or the rules can’t be applied, the agent refuses to start rather than leaving peers unconfined. Set false only if you genuinely can’t run iptables — this lets every host port bound to 0.0.0.0 (or ::) be reached by every paired peer (and bypasses the per-app ACL); it’s discouraged.
upnp_enabled true Master switch for automatic inbound-port opening. Opens the WireGuard UDP port via PCP, NAT-PMP, or UPnP — and, for IPv6, a firewall pinhole. Set false to disable all of it (none of PCP/NAT-PMP/UPnP/IPv6 pinhole runs); then forward listen_port/UDP manually instead. Overridden by WG_UPNP_ENABLED and the --no-upnp flag.
pcp_enabled true Try PCP (Port Control Protocol, RFC 6887) first when opening the port, for both IPv4 and IPv6, before falling back to NAT-PMP/UPnP. Set false to skip PCP. Overridden by WG_PCP_ENABLED.
ipv6_pinhole_enabled true Open an IPv6 firewall pinhole for the WireGuard port on the gateway (via PCP or UPnP IGDv2), so the published AAAA endpoint is reachable. Set false to manage the gateway firewall yourself. Overridden by WG_IPV6_PINHOLE_ENABLED.

The WireGuard interface is always called wg-atreo (hardcoded). The tunnel overlay is dual-stack with fixed addressing — IPv4 100.64.0.1/100.64.0.0/24 and IPv6 fd00:64::1/fd00:64::/64.

Field Default Description
enabled true Use the CGNAT relay as a fallback when the agent has no reachable public inbound path. It’s automatic and only kicks in when no direct path exists — direct paths always win. Set false to opt this agent out of relaying entirely (off-LAN clients will then be unreachable when there’s no direct path). Overridden by RELAY_ENABLED.
force false Keep a relay session up even when a direct path exists, so a relay endpoint is always available to offer to clients (clients still prefer LAN/direct). Useful for offering a relay config alongside a direct one; not needed for normal use. Overridden by RELAY_FORCE.

Setting endpoint_ip also keeps the agent off the relay: it tells the agent it already has a reachable public address, so it advertises that direct endpoint instead.

Field Default Description
enabled true Run the built-in HTTPS reverse proxy. Set to false if using your own (Caddy / Traefik / nginx).
http_port 80 HTTP port (used for the 80 to 443 redirect).
https_port 443 HTTPS port for the reverse proxy.
auth_port 9091 Forward-auth endpoint port.
trusted_networks (empty) CIDRs that bypass per-app ACL checks. Empty by default — no networks are trusted until you opt in. See Trusted networks.
trusted_proxies (empty) CIDRs of external reverse proxies allowed to set X-Forwarded-For / X-Forwarded-Host on forward-auth requests. Required when using Caddy / Traefik / nginx.
Field Default Description
email (required) Email used for Let’s Encrypt registration.
cert_dir /var/lib/atreoagent/certs Where TLS certificates and the ACME account key are stored.
Field Default Description
port 9876 Port for the local notification API. Binds on every interface so self-hosted apps in their own containers can reach it. Gated by a bearer-token API key.

See Notification API → Authentication for the bearer-auth key.

Field Default Description
enabled false Enable the built-in SMTP-to-push gateway.
listen 0.0.0.0:2525 Bind address for the SMTP server. The default binds all interfaces; the trusted_networks allowlist — not the bind address — is what keeps the gateway LAN-only.
max_message_bytes 1048576 Max accepted message size (1 MiB).
rate_per_minute 50 Per-source-IP rate limit.
trusted_networks 127.0.0.0/8, ::1/128, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, fe80::/10, fc00::/7, plus the WireGuard tunnel subnet (100.64.0.0/24; the IPv6 overlay fd00:64::/64 falls under fc00::/7) Source-IP allowlist. Connections from an IP outside the list are rejected before AUTH. Widening it to public IP space logs a warning at startup. Overridden by SMTP_TRUSTED_NETWORKS. See Source-IP allowlist.
tls_enabled false Advertise STARTTLS using a self-signed cert generated under the data dir. STARTTLS requires TLS 1.3. Required for apps that refuse plaintext AUTH (e.g. Grafana). See STARTTLS.
catch_all (empty) Fallback recipient for mail whose RCPT TO matches no member. Must be an existing member’s atreoLINK email — a push can only be sealed to a member — otherwise unknown mail is still rejected and a warning is logged. Empty (default) rejects unknown recipients with 550. Overridden by SMTP_CATCH_ALL. See Catch-all recipient.

See Built-in SMTP server for the routing model and a critical warning about exposing port 2525.

The agent stores all persistent state under data_dir:

/var/lib/atreoagent/
├── config.yaml # Agent configuration
├── admin_pin.json # Pinned owner identity (set at pair time)
├── acl.json # Cached ACL from atreoLINK
├── mobile_devices.json # Paired mobile devices and browsers
├── ip_allocations.json # WireGuard tunnel IP assignments
├── notify_api_key # Bearer key for the notification API
├── custom_domain.json # Custom domain state (if attached)
├── cert_renewal_state.json # Per-suffix renewal-failure tracking
├── keys/
│ ├── ed25519.key # Device identity (private)
│ ├── ed25519.pub # Device identity (public)
│ ├── wg_private.key # WireGuard private key
│ ├── wg_public.key # WireGuard public key
│ └── acme_account.key # ACME account private key
└── certs/
└── <suffix>/
├── registration.json # ACME registration metadata
├── fullchain.pem # TLS certificate (full chain)
└── privkey.pem # TLS private key

Each served TLS suffix has its own subdirectory under certs/. The legacy <yourname>.atreo.link suffix and any active custom domain are stored side by side.

Resolution order, later wins:

  1. Built-in defaults.
  2. Values in config.yaml (if the file exists).
  3. Environment variables.

config.yaml remains the source of pairing-derived data (device_token, device_id, apps_hostname). Environment variables are for tunables, not pairing state.

WireGuard is a registered trademark of Jason A. Donenfeld.