Servers and NAS

Warren without the desktop app

Under the desktop app sit a daemon and a command line that need no screen at all, a container image that carries the tunnel for its neighbours, and a gateway that speaks the WireGuard protocol to the devices that can install nothing else. Enough to put a seedbox, a NAS, a router or a whole server behind Warren.

One container carries the tunnel

The warren-vpn image runs the Warren client with no graphical interface, in the shape popularized by gluetun: one container owns the tunnel, the kill switch and the network namespace, and everything that must egress through the VPN joins that namespace. In Docker Compose it is one line in the neighbouring service; in Kubernetes it is a sidecar in the same pod.

Warren speaks neither WireGuard nor OpenVPN, so no generic VPN container can carry it. This image is the supported way to run Warren wherever containers run: a Linux server, a Synology, a QNAP, an Unraid, a TrueNAS, a Kubernetes cluster.

  • The kill switch is on by default. When the daemon dies the namespace dies with it: there is no window where traffic can bypass the tunnel.
  • NAT-PMP port forwarding is built in. When the exit grants a public port, the container writes it to a file and runs the command you gave it, with the port substituted, so you can push it into your application: a torrent client then listens and announces on that same port. The complete qBittorrent recipe, credentials included, sits in docker/examples/ in the repository.
  • The recovery phrase is mounted as a file, never given as an environment variable: a variable is readable in a docker inspect. Inside a container the daemon cannot seal it with the machine's chip and falls back to a file only root can read, so treat the state volume as secret material.
  • It needs NET_ADMIN and /dev/net/tun. The container installs its rules inside its own namespace and never touches the host firewall.

The image is rebuilt and published on every daemon release and on every fix to the image itself, but the package is still private for now: a docker pull answers "unauthorized". Until it opens, the repository script builds the same image locally, around the latest released daemon, under the exact name the examples use.

git clone https://github.com/WarrenBrowse/warren-cli && cd warren-cli
./docker/build.sh -t ghcr.io/warrenbrowse/warren-vpn:beta

The neighbour that must ride the tunnel then joins the Warren container namespace, and waits for it to be connected before starting.

services:
  warren:
    image: ghcr.io/warrenbrowse/warren-vpn:beta
    cap_add: [NET_ADMIN]
    devices: [/dev/net/tun]
    environment:
      - WARREN_MNEMONIC_FILE=/run/secrets/warren_mnemonic
      - WARREN_RELAY_LOCATION=fi
    secrets: [warren_mnemonic]
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    network_mode: "service:warren"
    depends_on:
      warren:
        condition: service_healthy

secrets:
  warren_mnemonic:
    file: ./warren_mnemonic.txt

A Linux server, no container

The Warren client is a daemon (warren-daemon) and a command (warren). Both run without Electron, without a screen and without a graphical session: a machine reachable over SSH is enough. The warren-cli repository publishes ready-to-install packages (deb, rpm, generic tarball, macOS, Windows), their checksums, the matching service (systemd, OpenRC or sysvinit), and a one-line installer that reads the host and picks for you.

curl -fsSL https://raw.githubusercontent.com/WarrenBrowse/warren-cli/main/scripts/install.sh | sudo sh

Then you create your account, add time with your code, pick a country and connect.

warren account create
warren account redeem <code>
warren relay set location FR
warren connect
warren status

One Warren daemon per machine: the server package and the desktop app would claim the same socket and the same firewall identity, so they exclude each other. Alpine and the other musl systems are not covered, and the installer says so rather than leaving you a binary that will not start.

Repository: WarrenBrowse/warren-cli

Routers, Apple TV, gluetun: the local gateway

A router, an Apple TV or a console often carries a single VPN client, and that client speaks WireGuard. Warren has its own protocol, so those devices cannot connect to it directly.

The warren-bolthole gateway closes that gap. It implements the WireGuard protocol so that stock WireGuard clients can use Warren, and runs with no privilege at all on a machine on your network: a NAS, a Raspberry Pi, a server, a container. On the LAN side your devices connect with their usual client; on the internet side everything leaves in a single Warren tunnel to the exit.

The warren-bolthole init command writes one configuration file per device, imported as is: a QR code in a phone's WireGuard app, a file on an Apple TV, LuCI on OpenWrt or a GL.iNet's panel. A router counts as one device and brings along whatever has no VPN client of its own, a console for instance. An existing gluetun stack keeps its stock image: provider custom, type wireguard, and the environment file the gateway generates.

All of it has been proven against a real exit on the network: stock wg-quick in kernel and in userspace mode, an unmodified gluetun, DNS resolved inside the tunnel with no local leak, and NAT-PMP port forwarding reaching a service behind a device, checked from a neutral point on the internet.

The gateway lives in the Rust SDK repository, warren-sdk-rs, and builds with cargo today. Getting it running:

export WARREN_MNEMONIC_FILE=/etc/warren/mnemonic
export WARREN_BOLTHOLE_LAN=1 WARREN_BOLTHOLE_LISTEN=0.0.0.0:51820
warren-bolthole init --peers 2 --label tv --label router
warren-bolthole show tv --qr
warren-bolthole run
  • Every device behind one gateway shares a single Warren session: one exit address, one device slot on the account, one port forwarding quota, shared bandwidth. Each client file is a key to your account: keep them for your own devices. Devices are isolated from each other by default.
  • Warren's obfuscation begins at the gateway. Between your device and the gateway it is ordinary WireGuard, recognizable by any traffic inspection. On your local network that is exactly the point; never publish the gateway's UDP port to the internet.
  • When the Warren tunnel goes down, the gateway goes silent: it stops answering the devices until egress is proven again, and nothing can bypass the tunnel. The device's kill switch stays the device's own setting: turn on "Block connections without VPN" on Android, your router's equivalent, or gluetun's built-in firewall.

"WireGuard" is a registered trademark of Jason A. Donenfeld. This project is not affiliated with or endorsed by the WireGuard project.

Repository: WarrenBrowse/warren-sdk-rs