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).