| 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. |