Skip to content

How to run a tunnel relay

Prerequisites, installation, payment channel setup, and operations for an ADNL tunnel node relay.

  • Go 1.24 or newer, available from the official Go downloads page
  • Static public IP address
  • UDP port 17330 open for tunnel traffic
  • TCP port 18889 open temporarily for automatic IP detection

Build from source:

Terminal window
git clone https://github.com/ton-blockchain/adnl-tunnel
cd adnl-tunnel
make binary

The binary is produced at build/tunnel-node. Precompiled binaries are available from the releases page.

Terminal window
./tunnel-node

On first launch the relay:

  1. Generates config.json with four Ed25519 key pairs
  2. Attempts to detect the external IP via a port checker (TCP 18889 to tonutils.com:9099)
  3. Publishes the node in the DHT overlay
  4. Prints the ADNL identity:
Tunnel started, listening on 0.0.0.0:17330 ADNL id is: <BASE64_ADNL_ID>

Open config.json and check:

  • ExternalIP: must contain the public IP. If empty, the port checker failed. Set it manually.
  • TunnelListenAddr: defaults to 0.0.0.0:17330. Change if a different bind address is needed.
  • TunnelServerKey: the node identity key. Do not modify.

See the tunnel relay reference for the full list of configuration fields.

  1. Edit config.json:

    {
    "PaymentsEnabled": true,
    "Payments": {
    "MinPricePerPacketRoute": 100,
    "MinPricePerPacketInOut": 200
    }
    }
  2. Restart the relay. In interactive mode (TTY), the relay prompts for the payment node key:

    No active onchain payment channel found, please input payment node id (pub key) in base64 format, to deploy channel with:

    Enter the base64 public key of the payment node. In non-interactive mode (systemd, Docker), pass the key as a flag:

    Terminal window
    ./tunnel-node --payment-node <HEX_PAYMENT_NODE_KEY>
  3. The relay deploys the payment channel contract on-chain (timeout 150 s), then waits for state exchange.

  4. Verify the deployment with the balance interactive command.

To pin clients to this relay:

Terminal window
./tunnel-node -gen-shared-config <OUTPUT_PATH>

This produces a JSON file containing the node public key and payment parameters. Distribute the file to clients, who reference it via NodesPoolConfigPath in their configuration.

Enable the metrics endpoint:

Terminal window
./tunnel-node -metrics-listen-addr 0.0.0.0:9100

Metrics are exported under the tunnel_ namespace. The full metric list is in the tunnel relay reference.

In TTY mode, the commands speed, stats, balance, capacity, wallet-ton-balance, and wallet-ton-transfer are available; each is documented in the interactive commands reference.

Example unit file:

[Unit]
Description=ADNL Tunnel Relay
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=tunnel
WorkingDirectory=/opt/tunnel-node
ExecStart=/opt/tunnel-node/tunnel-node -v 2 -metrics-listen-addr 127.0.0.1:9100
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
SymptomCauseFix
ExternalIP is empty after startupPort checker cannot reach TCP 18889Open TCP 18889 temporarily or set ExternalIP manually
skipping dht because no external address knownExternalIP not configuredSet ExternalIP in config.json
tunnel looks disconnectedNo control response for 45 secondsCheck network connectivity and peer availability
more than 33% incoming packets lostExcessive packet loss on the pathInvestigate network quality or relay selection
free packets exceeds rate limitUnpaid traffic exceeds 10 packets per secondEnable payments or reduce traffic
Relay registers but clients cannot connectRelay is behind NAT without port forwardingSet ExternalIP manually in config.json AND forward UDP 17330 on the router

Send SIGTERM to stop the relay. The node commits virtual payment channels before exiting (timeout 15 s).

To update: stop the relay, replace the binary, and restart. Keys in config.json and state in payments-db/ persist across restarts.