Skip to main content

Agent

The Wirety Agent automates configuration retrieval and health reporting.

Responsibilities​

  • Enrollment via token.
  • Maintain WireGuard config up-to-date (poll/WebSocket-triggered).
  • Heartbeat: hostname, uptime, endpoint observation, timestamps.

CLI Options​

wirety-agent [options]

Options:
-server string
Server base URL (no trailing /)
(env: SERVER_URL, default: http://localhost:8080)
-token string
Enrollment token (required)
(env: TOKEN)
-config string
Path to wireguard config file
(env: WG_CONFIG_PATH)
-apply string
Apply method: wg-quick|syncconf
(env: WG_APPLY_METHOD, default: syncconf)
-nat-interfaces string
Comma-separated list of NAT interfaces (env: NAT_INTERFACES)
Default: auto-detect all egress interfaces from the routing table
-portal-url string
Captive portal page URL
(env: CAPTIVE_PORTAL_URL, default: <SERVER_URL>/captive-portal)
-server-host string
Override the HTTP Host header for all requests to the server
(env: SERVER_HOST, default: derived from -server URL)
Useful when accessing the Wirety server by IP behind a reverse proxy
that routes by hostname (e.g. SERVER_URL=http://10.0.0.7 SERVER_HOST=wirety.internal)
-skip-tls-verify
Disable TLS certificate verification for connections to the server
(env: SKIP_TLS_VERIFY, default: false)
Use only when the server uses a self-signed or internally-signed certificate
that the agent host cannot verify. Never use in production with public certificates.
-log-level string
Log verbosity: trace|debug|info|warn|error|fatal
(env: LOG_LEVEL, default: info)
-log-format string
Log output format: text|json
(env: LOG_FORMAT, default: text)
-audit-log
Emit JSON audit events to stdout
(env: AUDIT_LOG, default: false)

Usage Example​

# Run agent — NAT interfaces are auto-detected from the routing table
export TOKEN=<ENROLLMENT_TOKEN>
export SERVER_URL=https://wirety.example.com
wirety-agent

# Explicit NAT interfaces (jump peer with internet + private VLAN egress)
wirety-agent -server https://wirety.example.com -token <TOKEN> -nat-interfaces ens2,ens6

# Environment variable equivalent
export NAT_INTERFACES=ens2,ens6
wirety-agent

# Access server by IP (no DNS) with Host header for reverse proxy routing
wirety-agent -server http://10.0.0.7 -server-host wirety.internal -token <TOKEN>

# Environment variable equivalent
export SERVER_URL=http://10.0.0.7
export SERVER_HOST=wirety.internal
wirety-agent

# Reverse proxy with self-signed certificate (disable TLS verification)
wirety-agent \
-server https://10.0.0.1 \
-server-host wirety.internal \
-portal-url https://wirety.internal/captive-portal \
-skip-tls-verify \
-token <TOKEN>

# Structured JSON logs at debug level (useful with log aggregators such as Loki / Datadog)
wirety-agent -log-format json -log-level debug

# Minimal output in production (warnings and above only)
wirety-agent -log-level warn

# Enable audit log alongside normal operation
wirety-agent -audit-log -log-format json

# Equivalent using environment variables
export LOG_FORMAT=json
export LOG_LEVEL=debug
export AUDIT_LOG=true
wirety-agent

Reverse Proxy / No-DNS Access (SERVER_HOST)​

When the Wirety server is deployed inside a private network behind a reverse proxy and no internal DNS is available, the agent can reach the server by IP while still sending the correct Host header for the proxy to route the request.

# Without DNS: connect to 10.0.0.7:80, but send "Host: wirety.internal"
# so Nginx / Caddy / Traefik routes the request to the Wirety backend.
wirety-agent \
-server http://10.0.0.7 \
-server-host wirety.internal \
-token <TOKEN>

This is equivalent to:

curl http://10.0.0.7/api/v1/agent/resolve \
-H "Host: wirety.internal" \
-H "Authorization: Bearer <TOKEN>"

The SERVER_HOST override is applied to all outbound connections from the agent:

  • Initial token resolution (/api/v1/agent/resolve)
  • WebSocket connection (/api/v1/ws)
  • Captive portal token creation (/api/v1/captive-portal/token)

Captive portal vhost isolation with SERVER_HOST​

The captive portal iptables rules derive the virtual hostname for SNI/Host filtering from SERVER_URL, not from SERVER_HOST. When SERVER_URL contains a bare IP (e.g. http://10.0.0.7), the agent cannot perform hostname-level filtering and falls back to port-only filtering — other virtual hosts on the same IP:port become reachable before authentication completes.

To get both no-DNS access and hostname isolation, use a resolvable hostname in SERVER_URL and omit SERVER_HOST:

# Preferred: DNS resolves wirety.internal → 10.0.0.7
# Agent connects to IP, SNI/Host filtering uses "wirety.internal"
wirety-agent -server http://wirety.internal -token <TOKEN>

If DNS is genuinely unavailable, SERVER_HOST + a bare-IP SERVER_URL still works — you simply lose vhost isolation for unauthenticated peers. See Reverse Proxy and Virtual Host Isolation for the full security implications.

NAT Interface Detection​

On jump peers, the agent adds a MASQUERADE rule for every egress interface so that forwarded traffic is correctly NATed regardless of which interface the routing table selects for a given destination.

By default the agent auto-detects all egress interfaces by scanning the routing table (ip route show) and keeping every interface that:

  • Has an IPv4 address
  • Is not loopback (lo)
  • Is not the WireGuard interface itself

This means a jump peer with both an internet uplink (ens2) and a private VLAN interface (ens6) will automatically get MASQUERADE on both, allowing peers to reach resources behind either interface.

Use NAT_INTERFACES to override when auto-detection picks up unwanted interfaces:

# Only NAT through the private VLAN interface
export NAT_INTERFACES=ens6

Host Prerequisites​

RequirementReason
WireGuard kernel/moduleInterface creation
curl / TLS libsEnrollment requests
Sufficient permissionsConfigure network interface, run iptables
Port 80 free on WireGuard interface IPCaptive portal HTTP server binds to <wg-ip>:80
Port 443 free on WireGuard interface IPCaptive portal HTTPS server binds to <wg-ip>:443 (self-signed cert)
nf_conntrack kernel moduleConntrack state matching in captive portal firewall rules
xt_string kernel moduleSNI / Host-header vhost isolation in captive portal firewall rules

The agent calls modprobe nf_conntrack and modprobe xt_string automatically at startup. These modules ship with the kernel on all mainstream distributions and require no manual installation. If either module is unavailable, the agent logs a warning and continues with degraded captive portal vhost isolation. See Kernel Module Requirements for persistence and troubleshooting.

Logging​

The agent uses zerolog for structured logging. Both the level and format are configurable via CLI flag or environment variable — the flag takes precedence.

LOG_LEVEL​

Controls which log entries are emitted.

ValueWhen to use
traceDeep protocol-level debugging (very verbose)
debugDevelopment and integration testing
infoNormal production operation (default)
warnOnly warnings and errors
errorOnly errors and fatal events
fatalSilent except on crashes

LOG_FORMAT​

ValueOutputWhen to use
textColoured, human-readable console output (default)Local development, direct terminal access
jsonOne JSON object per lineLog aggregators (Loki, Datadog, Elastic, etc.)

text sample:

2:47PM INF websocket connected url=wss://wirety.example.com/api/v1/ws
2:47PM INF DNS server starting addr=10.255.0.1:53

json sample:

{"level":"info","time":1744563600,"message":"websocket connected","url":"wss://wirety.example.com/api/v1/ws"}
{"level":"info","time":1744563600,"message":"DNS server starting","addr":"10.255.0.1:53"}
Production recommendation

Use LOG_FORMAT=json and LOG_LEVEL=info in production so that log lines are machine-parseable and can be ingested without extra parsing rules.

Security​

  • Token used only at enrollment; store ephemeral auth afterward.
  • Private keys generated server-side; agent receives only public + config data.
  • ACL blocking prevents agent from receiving updates (quarantine).

Heartbeat Data​

FieldDescription
hostnameReported system hostname
uptimeSeconds since boot
endpointDetected public endpoint
last_seenServer timestamp

Future​

  • Automatic key rotation.
  • Metrics emission (Prometheus).