Title: How to use Proton VPN port forwarding | |
Author: Solène | |
Date: 31 August 2024 | |
Tags: network privacy security openbsd linux | |
Description: In this blog post, you will learn how to automate Proton | |
VPN port forwarding | |
# Introduction | |
If you use Proton VPN with the paid plan, you have access to their port | |
forwarding feature. It allows you to expose a TCP and/or UDP port of | |
your machine on the public IP of your current VPN connection. | |
This can be useful for multiple use cases, let's see how to use it on | |
Linux and OpenBSD. | |
Proton VPN documentation: port forwarding setup | |
If you do not have a privacy need with regard to the service you need | |
to expose to the Internet, renting a cheap VPS is a better solution: | |
cheaper price, stable public IP, no weird script for port forwarding, | |
use of standard ports allowed, reverse DNS, etc... | |
# Feature explanation | |
Proton VPN port forwarding feature is not really practical, at least | |
not as practical as doing a port forwarding with your local router. | |
The NAT is done using NAT-PMP protocol (an alternative to UPnP), you | |
will be given a random port number for 60 seconds. The random port | |
number is the same for TCP and UDP. | |
Wikipedia page about NAT Port Mapping Protocol | |
There is a NAT PMPC client named `natpmpc` (available almost everywhere | |
as a package) that need to run in an infinite loop to renew the port | |
lease before it expires. | |
This is rather not practical for multiple reasons: | |
* you get a random port assigned, so you must configure your daemon | |
every time | |
* the lease renewal script must run continuously | |
* if something wrong happens (script failing, short network failure) | |
that prevent renewing the lease, you will get a new random port | |
Although it has shortcomings, it is a useful feature that was dropped | |
by other VPN providers because of abuses. | |
# Setup | |
Let me share a script I am using on Linux and OpenBSD that does the | |
following: | |
* get the port number | |
* reconfigure the daemon using the port forwarding feature | |
* infinite loop renewing the lease | |
You can run the script from supervisord (a process manager) to restart | |
it upon failure. | |
Supervisor official project website | |
In the example, the Java daemon I2P will be used to demonstrate the | |
configuration update using sed after being assigned the port number. | |
## OpenBSD | |
Install the package `natpmpd` to get the NAT-PMP client. | |
Create a script with the following content, and make it executable: | |
``` | |
#!/bin/sh | |
PORT=$(natpmpc -a 1 0 udp 60 -g 10.2.0.1 | awk '/Mapped public/ { print $4 }') | |
# check if the current port is correct | |
grep "$PORT" /var/i2p/router.config || /etc/rc.d/i2p stop | |
# update the port in I2P config | |
sed -i -E "s,(^i2np.udp.port).*,\1=$PORT, ; s,(^i2np.udp.internalPort).*,\1=$PO… | |
# make sure i2p is started (in case it was stopped just before) | |
/etc/rc.d/i2p start | |
while true | |
do | |
date # use for debug only | |
natpmpc -a 1 0 udp 60 -g 10.2.0.1 && natpmpc -a 1 0 tcp 60 -g 10.2.0.1 || {… | |
sleep 45 | |
done | |
``` | |
The script will search for the port number in I2P configuration, stop | |
the service if the port is not found. Then the port line is modified | |
with sed (in all cases, it does not matter much). Finally, i2p is | |
started, this will only do something in case i2p was stopped before, | |
otherwise nothing happens. | |
Then, in an infinite loop with a 45 seconds frequency, there is a | |
renewal of the TCP and UDP port forwarding happening. If something | |
wrong happens, the script exits. | |
### Using supervisord | |
If you want to use supervisord to start the script at boot and maintain | |
it running, install the package `supervisor` and create the file | |
`/etc/supervisord.d/nat.ini` with the following content: | |
``` | |
[program:natvpn] | |
command=/etc/supervisord.d/continue_nat.sh ; choose the path of your script | |
autorestart=unexpected ; when to restart if exited after running (def: unexpect… | |
``` | |
Enable supervisord at boot, start it and verify it started (a | |
configuration error prevents it from starting): | |
``` | |
rcctl enable supervisord | |
rcctl start supervisord | |
rcctl check supervisord | |
``` | |
### Without supervisord | |
Open a shell as root and execute the script and keep the terminal | |
opened, or run it in a tmux session. | |
## Linux | |
The setup is exactly the same as for OpenBSD, just make sure the | |
package providing `natpmpc` is installed. | |
Depending on your distribution, if you want to automate the script | |
running / restart, you can run it from a systemd service with auto | |
restart on failure, or use supervisord as explained above. | |
If you use a different network namespace, just make sure to prefix the | |
commands using the VPN with `ip netns exec vpn`. | |
Here is the same example as above but using a network namespace named | |
"vpn" to start i2p service and do the NAT query. | |
```shell | |
#!/bin/sh | |
PORT=$(ip netns exec vpn natpmpc -a 1 0 udp 60 -g 10.2.0.1 | awk '/Mapped publi… | |
FILE=/var/i2p/.i2p/router.config | |
grep "$PORT" $FILE || sudo -u i2p /var/i2p/i2prouter stop | |
sed -i -E "s,(^i2np.udp.port).*,\1=$PORT, ; s,(^i2np.udp.internalPort).*,\1=$PO… | |
ip netns exec vpn sudo -u i2p /var/i2p/i2prouter start | |
while true | |
do | |
date | |
ip netns exec vpn natpmpc -a 1 0 udp 60 -g 10.2.0.1 && ip netns exec vpn na… | |
sleep 45 | |
done | |
``` | |
# Conclusion | |
Proton VPN port forwarding feature is useful when need to expose a | |
local network service on a public IP. Automating it is required to | |
make it work efficiently due to the unusual implementation. |