Newt is a fully user space WireGuard tunnel client and TCP/UDP proxy, designed to securely expose private resources controlled by Pangolin. By using Newt, you don’t need to manage complex WireGuard tunnels and NATing.

Preview

Newt Preview

Newt interface preview

How Newt Works

Registers with Pangolin

Using the Newt ID and a secret, the client will make HTTP requests to Pangolin to receive a session token. Using that token, it will connect to a websocket and maintain that connection. Control messages will be sent over the websocket.

Receives WireGuard Control Messages

When Newt receives WireGuard control messages, it will use the information encoded (endpoint, public key) to bring up a WireGuard tunnel using netstack fully in user space. It will ping over the tunnel to ensure the peer on the Gerbil side is brought up.

Receives Proxy Control Messages

When Newt receives proxy control messages, it will use the information encoded to create a local low level TCP and UDP proxies attached to the virtual tunnel in order to relay traffic to programmed targets.

Configuration Arguments

id
string
required
Newt ID generated by Pangolin to identify the client.Example: 31frd0uzbjvp721
secret
string
required
A unique secret used to authenticate the client ID with the websocket.Example: h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6
Keep this secret private and secure. It’s used for authentication.
endpoint
string
required
The endpoint where both Gerbil and Pangolin reside for websocket connections.Example: https://pangolin.example.com
mtu
integer
MTU for the internal WireGuard interface.Default: 1280
dns
string
DNS server to use for resolving the endpoint.Default: 8.8.8.8
log-level
string
The log level to use for Newt output.Options: DEBUG, INFO, WARN, ERROR, FATALDefault: INFO
ping-interval
string
Interval for pinging the server.Default: 3s
ping-timeout
string
Timeout for each ping.Default: 5s
docker-socket
string
Set the Docker socket path for container discovery integration.Example: /var/run/docker.sock
docker-enforce-network-validation
boolean
Validate the container target is on the same network as the Newt process.Default: false
health-file
string
Check if connection to WireGuard server (Pangolin) is ok. Creates a file if ok, removes it if not ok. Can be used with Docker healthcheck to restart Newt.Example: /tmp/healthy
updown
string
Script to be called when targets are added or removed.Example: /path/to/updown.sh
tls-client-cert
string
Client certificate (p12 or pfx) for mutual TLS (mTLS) authentication.Example: /path/to/client.p12
accept-clients
boolean
Enable WireGuard server mode to accept incoming Olm client connections.Default: false
generateAndSaveKeyTo
string
Path to save generated private key (used with accept-clients).Example: /var/key
native
boolean
Use native WireGuard interface when accepting clients (requires WireGuard kernel module and Linux, must run as root).Default: false (uses userspace netstack)
interface
string
Name of the WireGuard interface (used with native mode).Default: newt
keep-interface
boolean
Keep the WireGuard interface after shutdown (used with native mode).Default: false

Environment Variables

All CLI arguments can be set using environment variables as an alternative to command line flags. Environment variables are particularly useful when running Newt in containerized environments.
PANGOLIN_ENDPOINT
string
Endpoint of your Pangolin server (equivalent to --endpoint)
NEWT_ID
string
Newt ID generated by Pangolin (equivalent to --id)
NEWT_SECRET
string
Newt secret for authentication (equivalent to --secret)
MTU
integer
MTU for the internal WireGuard interface (equivalent to --mtu)Default: 1280
DNS
string
DNS server to use for resolving the endpoint (equivalent to --dns)Default: 8.8.8.8
LOG_LEVEL
string
Log level (equivalent to --log-level)Default: INFO
DOCKER_SOCKET
string
Path to Docker socket for container discovery (equivalent to --docker-socket)
PING_INTERVAL
string
Interval for pinging the server (equivalent to --ping-interval)Default: 3s
PING_TIMEOUT
string
Timeout for each ping (equivalent to --ping-timeout)Default: 5s
UPDOWN_SCRIPT
string
Path to updown script for target add/remove events (equivalent to --updown)
TLS_CLIENT_CERT
string
Path to client certificate for mTLS (equivalent to --tls-client-cert)
DOCKER_ENFORCE_NETWORK_VALIDATION
boolean
Validate container targets are on same network (equivalent to --docker-enforce-network-validation)Default: false
HEALTH_FILE
string
Path to health file for connection monitoring (equivalent to --health-file)
ACCEPT_CLIENTS
boolean
Enable WireGuard server mode (equivalent to --accept-clients)Default: false
GENERATE_AND_SAVE_KEY_TO
string
Path to save generated private key (equivalent to --generateAndSaveKeyTo)
USE_NATIVE_INTERFACE
boolean
Use native WireGuard interface (Linux only, equivalent to --native)Default: false
INTERFACE
string
Name of the WireGuard interface (equivalent to --interface)Default: newt
KEEP_INTERFACE
boolean
Keep the WireGuard interface after shutdown (equivalent to --keep-interface)Default: false
CONFIG_FILE
string
Load the config JSON from this file instead of in the home folder.
When both environment variables and CLI arguments are provided, CLI arguments take precedence.

Basic Configuration Examples

Binary Example

newt \
--id 31frd0uzbjvp721 \
--secret h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6 \
--endpoint https://example.com
docker-compose.yml
services:
  newt:
    image: fosrl/newt
    container_name: newt
    restart: unless-stopped
    environment:
      - PANGOLIN_ENDPOINT=https://example.com
      - NEWT_ID=2ix2t8xk22ubpfy
      - NEWT_SECRET=nnisrfsdfc7prqsp9ewo1dvtvci50j5uiqotez00dgap0ii2
      - HEALTH_FILE=/tmp/healthy

Docker Compose with CLI Arguments

docker-compose.yml
services:
  newt:
    image: fosrl/newt
    container_name: newt
    restart: unless-stopped
    command:
      - --id 31frd0uzbjvp721
      - --secret h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6
      - --endpoint https://example.com
      - --health-file /tmp/healthy

Advanced Features

Accept Client Connections

When the --accept-clients flag is enabled (or ACCEPT_CLIENTS=true environment variable is set), Newt operates as a WireGuard server that can accept incoming client connections from other devices. This enables peer-to-peer connectivity through the Newt instance.

Client Tunneling Modes

Newt supports two WireGuard tunneling modes:
Userspace Mode (Default)
By default, Newt uses a fully userspace WireGuard implementation using netstack. This mode:
  • Does not require root privileges
  • Works on all supported platforms (Linux, Windows, macOS)
  • Does not require WireGuard kernel module to be installed
  • Runs entirely in userspace - no system network interface is created
  • Is containerization-friendly - works seamlessly in Docker containers
This is the recommended mode for most deployments, especially containerized environments.
Native Mode (Linux only)
When using the --native flag or setting USE_NATIVE_INTERFACE=true, Newt uses the native WireGuard kernel module. This mode:
  • Requires root privileges to create and manage network interfaces
  • Only works on Linux with the WireGuard kernel module installed
  • Creates a real network interface (e.g., newt0) on the system
  • May offer better performance for high-throughput scenarios
  • Requires proper network permissions and may conflict with existing network configurations
Native mode requires Linux with WireGuard kernel module and must run as root.

Native Mode Requirements

To use native mode:
  1. Run on a Linux system
  2. Install the WireGuard kernel module
  3. Run Newt as root (sudo)
  4. Ensure the system allows creation of network interfaces
Docker Compose example:
docker-compose.yml
services:
  newt:
    image: fosrl/newt
    container_name: newt
    restart: unless-stopped
    environment:
      - PANGOLIN_ENDPOINT=https://example.com
      - NEWT_ID=2ix2t8xk22ubpfy
      - NEWT_SECRET=nnisrfsdfc7prqsp9ewo1dvtvci50j5uiqotez00dgap0ii2
      - ACCEPT_CLIENTS=true

Docker Socket Integration

Newt can integrate with the Docker socket to provide remote inspection of Docker containers. This allows Pangolin to query and retrieve detailed information about containers running on the Newt client, including metadata, network configuration, port mappings, and more. Configuration: You can specify the Docker socket path using the --docker-socket CLI argument or by setting the DOCKER_SOCKET environment variable. On most Linux systems the socket is /var/run/docker.sock. When deploying Newt as a container, you need to mount the host socket as a volume for the Newt container to access it.
docker-compose.yml
services:
  newt:
    image: fosrl/newt
    container_name: newt
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - PANGOLIN_ENDPOINT=https://example.com
      - NEWT_ID=2ix2t8xk22ubpfy
      - NEWT_SECRET=nnisrfsdfc7prqsp9ewo1dvtvci50j5uiqotez00dgap0ii2
      - DOCKER_SOCKET=/var/run/docker.sock
If the Docker socket is not available or accessible, Newt will gracefully disable Docker integration and continue normal operation.

Hostnames vs IPs

When the Docker Socket Integration is used, depending on the network which Newt is run with, either the hostname (generally considered the container name) or the IP address of the container will be sent to Pangolin:
  • Running in Network Mode ‘host’: IP addresses will be used
  • Running in Network Mode ‘bridge’: IP addresses will be used
  • Running in docker-compose without a network specification: Docker compose creates a network for the compose by default, hostnames will be used
  • Running on docker-compose with defined network: Hostnames will be used

Docker Enforce Network Validation

When run as a Docker container, Newt can validate that the target being provided is on the same network as the Newt container and only return containers directly accessible by Newt. Validation will be carried out against either the hostname/IP Address and the Port number to ensure the running container is exposing the ports to Newt.
If the Newt container is run with a network mode of host, this feature will not work. Running in host mode causes the container to share its resources with the host machine, making it impossible to retrieve specific host container information for network validation.
Configuration: Validation is false by default. It can be enabled via setting the --docker-enforce-network-validation CLI argument or by setting the DOCKER_ENFORCE_NETWORK_VALIDATION environment variable.

Updown Scripts

You can pass in an updown script for Newt to call when it is adding or removing a target:
--updown "python3 test.py"
The script will be called with arguments when a target is added or removed:
python3 test.py add tcp localhost:8556
python3 test.py remove tcp localhost:8556
Returning a string from the script in the format of a target (ip:dst so 10.0.0.1:8080) will override the target and use this value instead to proxy.
You can look at updown.py as a reference script to get started!

mTLS Authentication

Newt supports mutual TLS (mTLS) authentication if the server has been configured to request a client certificate. Requirements:
  • Only PKCS12 (.p12 or .pfx) file format is accepted
  • The PKCS12 file must contain:
    • Private key
    • Public certificate
    • CA certificate
  • Encrypted PKCS12 files are currently not supported
Binary Example:
newt \
--id 31frd0uzbjvp721 \
--secret h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6 \
--endpoint https://example.com \
--tls-client-cert ./client.p12
Docker Compose Example:
docker-compose.yml
services:
  newt:
    image: fosrl/newt
    container_name: newt
    restart: unless-stopped
    environment:
      - PANGOLIN_ENDPOINT=https://example.com
      - NEWT_ID=2ix2t8xk22ubpfy
      - NEWT_SECRET=nnisrfsdfc7prqsp9ewo1dvtvci50j5uiqotez00dgap0ii2
      - TLS_CLIENT_CERT=./client.p12
Get your id and secret from the Pangolin dashboard when creating a Newt client.