Operations

This page covers running p2proxy as a long-lived service.

systemd

A minimal unit file:

# /etc/systemd/system/p2proxy.service
[Unit]
Description=Bitping p2proxy
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
Environment=BITPING_API_KEY=<your-key>
ExecStart=/usr/local/bin/p2proxy --no-ui --config /etc/p2proxy/Config.yaml
Restart=on-failure
RestartSec=5
DynamicUser=yes
StateDirectory=p2proxy

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable --now p2proxy
journalctl -u p2proxy -f

DynamicUser=yes runs the daemon as a transient unprivileged user. StateDirectory=p2proxy gives it /var/lib/p2proxy for the libp2p keypair.

If you need to bind a SOCKS5 listener below port 1024, either pick a high port (recommended) or grant the binary the capability:

sudo setcap 'cap_net_bind_service=+ep' "$(which p2proxy)"

Docker

The official image is ghcr.io/bitpingapp/p2proxy:latest. NO_UI=true is set by default so the daemon doesn’t try to draw a TUI without a TTY.

docker run -d --name p2proxy \
  -p 1080:1080 \
  -p 9091:9091 \
  -e BITPING_API_KEY=<your-key> \
  -v "$PWD/Config.yaml:/app/Config.yaml:ro" \
  ghcr.io/bitpingapp/p2proxy:latest

You need to expose:

  • Every per-server SOCKS5 port (-p 1080:1080, etc.) so clients on the host or network can reach it.
  • The metrics port (-p 9091:9091) if you want to scrape Prometheus metrics from outside the container.
  • If you pin a fixed libp2p port via listen_addrs, publish that port too — not strictly required, but it improves direct-vs-relay connectivity.

docker-compose

A reference docker-compose.yml ships in the repo. Typical shape:

services:
  p2proxy:
    image: ghcr.io/bitpingapp/p2proxy:latest
    restart: unless-stopped
    environment:
      BITPING_API_KEY: $BITPING_API_KEY
    ports:
      - "1080:1080"
      - "9091:9091" # metrics
    volumes:
      - ./Config.yaml:/app/Config.yaml:ro

p2proxy picks its own libp2p listen ports by default, so there’s nothing fixed to publish. If you set listen_addrs to a fixed port, publish that port too (it improves direct-vs-relay connectivity).

Prometheus metrics

p2proxy exposes Prometheus metrics on http://localhost:9091/metrics by default (set metrics_port to change it). Useful series:

Series Type Notes
p2proxy_peers_connected gauge Connected libp2p peers.
p2proxy_sessions_active gauge In-flight SOCKS5 sessions.
p2proxy_socks_connections_total, p2proxy_sessions_initialized_total counter Accepted / fully-established sessions.
p2proxy_upload_bytes_total, p2proxy_download_bytes_total counter Bytes relayed each direction.
p2proxy_session_errors_total{stage} counter Session failures by stage (handshake / request / peer-connection / data-transfer).
p2proxy_stream_opened_total, p2proxy_stream_acquire_failed_total counter Peer-stream opens / failures.
p2proxy_ping_rtt_seconds histogram Peer round-trip latency.
p2proxy_socks_rejected_no_peer_total counter Sessions rejected — no exit peer available.

A minimal scrape config:

scrape_configs:
  - job_name: p2proxy
    static_configs:
      - targets: ["localhost:9091"]

For dashboards, p2proxy_session_errors_total{stage} is the series you’ll watch most — a rising rate is the leading indicator of peer trouble.

Upgrading

  • Homebrew: brew upgrade --cask BitpingApp/tap/p2proxy
  • Debian/Ubuntu/RHEL/Alpine: download the new package from the releases page and reinstall.
  • Docker: pull the new tag and recreate the container — docker compose pull && docker compose up -d.
  • From source: git pull && cargo build --release -p p2proxy.

Restart the daemon to pick up the new binary. Config.yaml is read at startup, so config changes also require a restart.

Keypair / peer identity

p2proxy persists its libp2p keypair to node_keypair.bin in the working directory by default (override with keypair_path). Under systemd with StateDirectory=p2proxy, run the daemon from /var/lib/p2proxy or point keypair_path there. Deleting this file changes your peer ID; the daemon regenerates one on next start. You usually don’t need to touch this.

Next