Guide
Opening a port through the tunnel
Port forwarding lets connections in through your tunnel. Without it, your torrent client downloads but shares far less, because other peers cannot reach you. It also lets you host a service from home or open your NAT in a game. Warren does it over NAT-PMP, inside the tunnel, and every one of its exits offers it.
- Plans
- All of them, the free beta included. Nothing extra to pay.
- Platforms
- macOS, Windows and Linux: the desktop app, the warren command, the Docker image.
- Mobile
- Android and iOS: one port, picked in the settings, requested when the tunnel connects.
How it works
When you turn port forwarding on, your device asks the exit for a port over NAT-PMP, inside the tunnel. The request never travels in the clear, and the exit does not know who it is answering.
The exit grants a public port between 49152 and 65535 and sends everything arriving on it back to your machine. That number is both the public port and the port your software listens on locally.
You can hold five ports at once, across the whole network. Each rule covers TCP and UDP together, or one of the two.
The port follows you. The app asks for the same number again on every reconnection and every exit change, so it moves rarely. On the exit side nothing is written to disk: allocations stay in RAM and are gone when the machine powers off.
Before you start
- Turn off UPnP and NAT-PMP in your torrent client. Left on, it opens a port of its own against the one the exit just granted you, and you spend the evening working out which of the two wins.
- One number for both ends. The public port is also your local listening port, and the app refuses any other combination. You copy one number into one field of your client.
- An open port is reachable from the internet, by anyone. Only put behind it what you really mean to expose.
Warren does not look at what you host and does not restrict what you use the port for. Bulă's legal advice: "Don't do anything illegal, it's bad." If a third party reports abuse coming from your port, the team closes it and records a warning against your account, which you see in the app. Three within ninety days revoke the account for twelve months. Details and how to contest, on the Reports page
In the desktop app
The screen is the same on macOS, Windows and Linux.
Each port you add is opened on the exit and forwarded to the same port on your device. Changes apply immediately, no reconnection needed.
- Open Settings, then Port forwarding, and turn the switch on.
- "+ Add a port", then a protocol (TCP+UDP, UDP or TCP) and a number between 49152 and 65535. The app suggests a free one at random if you have no preference, and refuses anything outside the range.
- Five rules at most. The limit covers the whole network, whichever exit you use.
- Once the exit grants it, the rule reads "open: 51413" in green. The "Copy port number" button right next to it copies that number alone, ready to paste into your client.
If that number is already taken on the exit, the rule turns to "port in use" and the app offers two ways out: "Assign a free port", which hands you another number straight away, or "Choose another exit", which keeps your number and moves you elsewhere.
The setting "Notify me when a public port changes" is on by default. On every new port, a system notification shows "Port forwarding: public port 51413 is open", then "Port forwarding: public port 51413 is no longer open" when it goes. Its "Open port forwarding" button brings you back to the screen. While the app window is visible, no notification shows.
On the home screen, while you are connected, a chip carries the state: "Port forwarding: 51413 TCP+UDP".
The screen links back here, through "How to set up your torrent client".
The forwarded_port file
The app writes the active public ports to a text file, one port per line, in the order of your rules. When nothing is open or the tunnel goes down, the app empties the file and leaves it in place, so a script watching it always finds it. It sits next to gui_settings.json, in the app's user-data directory.
| System | Path |
|---|---|
| macOS | ~/Library/Application Support/Warren VPN/forwarded_port |
| Windows | %LOCALAPPDATA%\Warren VPN\forwarded_port |
| Linux | ~/.config/Warren VPN/forwarded_port |
The beta app writes to the same folder as the regular app: the folder name does not change between channels. When in doubt, look for the folder that holds gui_settings.json.
Letting the app configure your torrent client
Under the list of rules, the "Torrent client" block offers to do the job for you: "Warren can enter the public port into your torrent client and update it whenever it changes. Enable the client's web interface first."
The app talks to qBittorrent, Transmission and Deluge through their web interface. Turn it on in your client and set a username and password there: those are what you give the app. It lives under Options then Web UI in qBittorrent, and Preferences then remote access in Transmission. Deluge has a separate web interface that ships with the password deluge, the same for everyone: change it before anything else.
- "Client": qBittorrent, Transmission, Deluge, or "None" to leave the block idle.
- "Web interface address": http://127.0.0.1:8080 for qBittorrent, http://127.0.0.1:9091 for Transmission, http://127.0.0.1:8112 for Deluge.
- "Username" and "Password": the ones you set in the client's web interface (Deluge only asks for the password). The app encrypts the password with the system keychain, then the field reads "Saved".
- "Rule": the one whose port goes to the client, when you run several.
- "Test connection" answers right away, for instance "Connected to qBittorrent 5.0.4, listening on port 51413". "Apply now" sends the current port without waiting for the next change.
Under the block, one line always says where the client stands:
- "qBittorrent now listens on port 51413": it went through.
- "Cannot reach qBittorrent at http://127.0.0.1:8080": the client is off, or the address is wrong.
- "qBittorrent refused the login": wrong username or password.
- "qBittorrent rejected the port: ...": the client answered but refuses that number.
- "Waiting for a public port": the rule has not been granted one yet.
- "This system cannot store the password securely": the app found no keychain to encrypt the password with and does not save the settings. It happens on a Linux with no unlocked keyring. What you typed stays in the field.
When the exit grants a public port other than your rule's own number, the app re-points the rule onto the granted port, on both sides, then sends it to the client. You did not choose that number, and it becomes your local listening port: the app therefore only accepts a port between 49152 and 65535 from the exit, which keeps it off your SSH.
When the client does not answer, the app tries again three times, after 2, 5 then 10 seconds: a silent torrent client is often restarting. A refused password is not retried, because qBittorrent bans an address that gets it wrong several times in a row.
While it sets the port, the app also turns off the client's own UPnP and NAT-PMP, for the reason given under "Before you start".
Client by client
If you would rather do it by hand, the steps are the same in all three: turn off UPnP and NAT-PMP, set the port the exit granted, and stop the client from changing it at the next start.
qBittorrent
- Tools, Options, Connection.
- Untick "Use UPnP / NAT-PMP port forwarding from my router".
- Set "Port used for incoming connections" to your port.
- Untick "Use different port on each startup".
Transmission
- Preferences, Network.
- Set the peer listening port to your port.
- Untick "Randomize port on launch".
- Untick "Use port forwarding from my router".
Deluge
- Preferences, Network.
- Untick "Use Random Ports".
- Set the incoming port range to your port twice, as the start and the end.
- Untick UPnP and NAT-PMP.
From the command line
The warren command ships with every release of the app. It also installs on its own, on a machine with no screen, and drives the same five rules under the same constraints.
warren port-forward enable --internal-port 51413 --protocol both
warren port-forward status
# 51413/TCP+UDP: MAPPED, public port 51413 The other subcommands follow: add and remove for several rules, disable to turn everything off, get to read the configuration back, lifetime for the lease duration requested.
For a script, --json always prints the same fields. An empty field stays present and reads null.
warren port-forward status --json
{"mappings":[{"internal_port":51413,"protocol":"both","state":"mapped","external_port":51413,"lifetime_granted_secs":3600,"error_reason":null,"error_message":null,"retry_after_secs":null,"attempts_remaining":null,"window_reset_secs":null}]} --wait blocks until every rule holds its port, then exits with a code: 0 everything is open, 1 there is nothing to wait for, 2 the timeout expired, 3 a rule failed. Here the port lands in a variable, ready for the rest of a startup script.
port=$(warren port-forward status --wait --timeout 60 --json | jq '.mappings[0].external_port') --watch follows the changes, one JSON line per change. With --exec, Warren runs your command every time a public port changes. A renewal that keeps the same number does not trigger it.
warren port-forward status --watch --exec 'sh /usr/local/bin/warren-qbt.sh {{PORT}}' The script it calls, here for qBittorrent and its web API:
#!/bin/sh
# warren-qbt.sh: push the public port into qBittorrent. Called with the port as
# its only argument, and does nothing when the grant is gone (empty argument).
set -e
case "$1" in '' | *[!0-9]*) exit 0 ;; esac
curl -s -c /tmp/qb.cookie \
--data 'username=admin&password=CHANGEME' \
http://127.0.0.1:8080/api/v2/auth/login
curl -s -b /tmp/qb.cookie \
--data-urlencode 'json={"listen_port":'"$1"',"random_port":false,"upnp":false}' \
http://127.0.0.1:8080/api/v2/app/setPreferences In the command, {{PORT}} is replaced by the public port. The environment also carries WARREN_PF_PORT, WARREN_PF_INTERNAL_PORT, WARREN_PF_PROTOCOL and WARREN_PF_STATE, which reads mapped when the port arrives and lost when it goes.
Docker
The warren-vpn image carries the tunnel for the rest of the stack. Its port forwarding uses the variables gluetun users already know: one for the internal port, another for the command to run when the public port changes, with {{PORT}} replaced by the number.
The active port is also written to /tmp/warren/forwarded_port, in case a neighbouring container would rather watch a file.
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_PORT_FORWARD_INTERNAL_PORT=6881
- WARREN_PORT_FORWARD_PROTOCOL=both
- WARREN_PORT_FORWARD_UP_COMMAND=sh /scripts/qbt-port.sh {{PORT}}
volumes:
- ./warren-qbt.sh:/scripts/qbt-port.sh:ro
secrets: [warren_mnemonic]
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
network_mode: "service:warren"
depends_on:
warren:
condition: service_healthy
secrets:
warren_mnemonic:
file: ./warren_mnemonic.txt The script mounted in the example is the one from the previous section: it takes the port as an argument and writes it into the client. The three ready-made recipes, one per client, live in docker/examples/ of the warren-cli repository, with the curl calls already written and tested.
Docker replaces the network namespace when it restarts the warren container, and the torrent client keeps a handle on the destroyed one: it shows zero peers, with no error, until it is restarted too. depends_on only orders the first start. After any warren restart: docker compose restart qbittorrent.
Repository: WarrenBrowse/warren-cliBinding the client to the tunnel interface
Warren's kill switch already blocks anything trying to leave outside the tunnel, so binding your client to the interface is belt and braces. It still helps: a bound client stops on its own when the tunnel drops, instead of hammering away at refused connections.
You need the interface name, and it is not guessable everywhere.
| System | Interface name |
|---|---|
| Windows | The network adapter is called Warren. |
| Linux | The kernel picks the name, usually tun0 or tun1. Compare the output of ip link before and after connecting. |
| macOS | A utunN interface whose number varies. Compare the output of ifconfig before and after connecting. |
- qBittorrent: Tools, Options, Advanced, "Network interface".
- Transmission: no setting in the preferences. Edit the bind-address-ipv4 key in settings.json while the daemon is stopped.
- Deluge: Preferences, Network, the incoming address field.
Multi-hop, IPv6, split tunneling
Multi-hop
Multi-hop does not turn port forwarding off. The NAT-PMP request goes to the same inner gateway whether or not the traffic crosses a relay, and the port follows you when the exit changes mid-session.
IPv6
The forwarded port lives on the exit's public IPv4 address and nowhere else. NAT-PMP is an IPv4 protocol, and the exit refuses a request arriving over IPv6. A peer that only has IPv6 will not reach you on that port.
Split tunneling
An application excluded from the tunnel does not leave through the exit, so nothing can reach it on the forwarded port. If you took your torrent client out of the tunnel, put it back in.
Check that the port is open
An online port checker answers "closed" as soon as nothing listens, which is the most common case: the port really is open on the exit, but your client has not started yet. In order: start your torrent client, check the rule is granted ("open: 51413" in the app, MAPPED on the command line), then test.
A "filtered" result on an unrelated port is expected too. Only your forwarded ports are open on that exit address; everything else is closed, for you as for everyone.
Frequently asked
Does my port change often?
Rarely. The app asks for the same number again on every reconnection and every exit change. It only moves if that number is already taken on the new exit, or if you pick another one yourself.
How many ports can I open?
Five at a time, across the whole network: five for your key, all your devices together, however many exits you use.
What am I allowed to run behind that port?
Warren does not restrict the use and does not look at what goes through. The limit is elsewhere: a port reported for abuse is closed, a warning is recorded against the account that held it, and three warnings within ninety days revoke the account for twelve months.
Reports: the whole procedureWhy only ports above 49152?
Because a high port cannot pass for an infrastructure service. Nobody runs a mail server on port 53000, and the hosting provider receiving a complaint knows it too. With that one constraint, Warren can leave the rest free.
Do I have to reconnect after changing a port?
No. Changes apply immediately, no reconnection needed, and the rule turns green again as soon as the exit has answered.
