Skip to content

Operations

This page covers running the proxy on a deployed box: the systemd unit, the command-line flags, and what the logs tell you.

Service control

The shipped RPM installs the systemd unit pdns-pf-proxy-tcp.service, which runs the binary as /usr/bin/pdns-pf-proxy-tcp --config /etc/pdns-pf/proxy-tcp.yaml run under the unprivileged pdns-proxy-tcp user. It is granted CAP_NET_BIND_SERVICE so it can bind privileged ports (80, 443) without running as root.

systemctl status pdns-pf-proxy-tcp
journalctl -u pdns-pf-proxy-tcp -f
systemctl restart pdns-pf-proxy-tcp

There is no config reload: the proxy reads its configuration once at startup, so a config change requires a restart. On SIGINT or SIGTERM the proxy stops accepting new connections immediately, gives existing connections a short grace period to finish, then force-closes whatever remains.

Config location

The unit passes /etc/pdns-pf/proxy-tcp.yaml. The example template ships as /etc/pdns-pf/proxy-tcp.example.yaml. See the Configuration page for the full reference.

Subcommands

The binary has three subcommands:

Subcommand Purpose
run Start the proxy listeners and serve until shutdown.
check Validate the effective configuration and exit without starting listeners.
version Print the build version.

Use check to validate a config before restarting the service:

pdns-pf-proxy-tcp --config /etc/pdns-pf/proxy-tcp.yaml check

Command-line flags

The proxy can run entirely from flags, with YAML optional. The persistent flags work with any subcommand and override the matching YAML values after the file loads.

Flag Default Purpose
--config, -c "" YAML config file to load before applying flag overrides.
--decision-backend nats Remote decision backend: none, nats, or http.
--simulator-http-url "" Base URL for the http backend, e.g. http://127.0.0.1:8080.
--debug false Force debug log level.
--log-level connection Log level: debug, connection, info, warn, or error.
--log-format human Log format: human, logfmt, or json.

The run subcommand adds flags that create listeners. Repeating an address flag adds more listeners.

Flag Default Purpose
--http-address Append a plain HTTP listener. Repeatable.
--https-address Append an HTTPS listener. Repeatable.
--http-proxy-protocol-address Append an HTTP listener that requires HAProxy PROXY protocol v1. Repeatable.
--https-proxy-protocol-address Append an HTTPS listener that requires HAProxy PROXY protocol v1. Repeatable.
--socks5-address Append a SOCKS5 listener. Repeatable.
--status-address "" Serve the status page and Prometheus metrics on this address. Empty disables it. Overrides status.address.
--dev-listeners false Shorthand for --http-address=:9980, --https-address=:9943, and --socks5-address=:9990, and serves the status page on 127.0.0.1:9919 with the per-connection table enabled.
--vhost "" Static vhost for listeners created by the flags above.
--proxy-profile 0 Static profile number for listeners created by the flags above.
--fail-open false Allow proxying when the decision backend fails, for listeners created by the flags above.

The --vhost, --proxy-profile, and --fail-open flags apply only to listeners created on the command line, not to listeners defined in YAML.

Observability

The proxy's observability surface is its structured logs plus an optional HTTP server that exposes a status page and Prometheus metrics.

Logging uses log/slog. In a terminal the human format is colorized and easy to read; logfmt and json are machine-parseable for log shipping. The default connection level keeps the per-session lifecycle logs on without the volume of full debug output.

Per-connection logs

Each connection produces a summary line when it closes, carrying the request ID, client address, target host, upstream IP and port, the time spent in each stage, the bytes transferred each way, and the decision rule that allowed or blocked it. The request ID is highlighted in terminal output so a single session is easy to follow.

Periodic activity stats

Every tcp.active_stats_interval (default 10s) the proxy logs one summary line of current activity:

  • active connection count, split into pre-proxy and proxying connections
  • connections added and closed during the interval
  • bytes in and out during the interval, and the average rate each way

Accepted-but-not-yet-proxying connections are counted too, so a flood of stalled or idle connections is visible. When an interval has no activity the proxy logs one line noting that periodic stats are muted, then stays quiet until traffic resumes. Set active_stats_interval to 0 to disable these summaries entirely while keeping the per-connection logs.

Status and metrics server

When status.address is set, the proxy starts a plain HTTP server with three endpoints:

Path Purpose
/metrics Prometheus metrics. See the Metrics page.
/healthz Liveness probe. Returns 200 OK.
/ Summary status page: version, uptime, active connection counts, and Go runtime stats.

The server is disabled by default. Configure it under status, or pass --status-address on the run command. --dev-listeners enables it on 127.0.0.1:9919.

Warning

Setting status.connections: true adds a per-connection table to the status page that exposes client addresses and destination hosts, and snapshots every active connection on each page load. Keep it off in production. --dev-listeners turns it on, so bind the dev status server to localhost only.

SOCKS5 listener

A SOCKS5 listener accepts only CONNECT requests to ports 80 and 443, then routes on the HTTP Host or TLS SNI that follows rather than the SOCKS destination address. It applies the same filtering as the HTTP and HTTPS listeners, so it is a convenient way to send a client through the filter without configuring routing for every host.

Warning

The SOCKS5 listener performs no authentication. Anyone who can reach its bind address can proxy through it. Bind it to a trusted interface or protect it with a firewall — never expose it to the public Internet.

Pausing a subscriber

The proxy accepts a runtime command over NATS to close a subscriber's live sessions and optionally reject new ones for a short window. See Pause control.