How to properly set up PIA VPN on a Raspberry Pi with a killswitch

How to properly set up PIA VPN on a Raspberry Pi with a killswitch

Intro

This post was written on the 14th of November 2020. I feel the need to start with that because all of the guides out there on the internet are too old and do not work anymore. I never liked dealing with OpenVPN, let alone on a Raspberry Pi but here we are. I needed this setup because I want to turn one of my Raspberry Pis into a seedbox, and I sleep much better at night when it's behind a VPN. My personal choice is PIA. I'd have a hard guess that this setup / method works with anything that uses OpenVPN however. Mine runs the latest (as of November 2020) Raspberry Pi OS on a Raspberry Pi 3, but it will work on the 4 as well. We will be running PIA via OpenVPN fully in headless mode.

I took help from the following articles:

Setup

  1. The usual...

    sudo apt update && sudo apt upgrade -y
    
  2. Check if you have an internet connection to begin with. Take note of the IP address displayed there, that's your current public IP without the VPN.

    curl https://ipleak.net/json/
    
  3. Install OpenVPN on your Raspberry

    sudo apt install openvpn -y
    
  4. Create a login file for OpenVPN. Since PIA VPN uses auth-pass in its configuration, we need to save the PIA username + password in a file on the server - the same you use to log into the desktop app or website. While this is not technically "best practice", I could not come up with a safer way. As long as your Pi is well secured, it should not be a problem.

    sudo bash -c 'echo "USERNAME" >> /etc/openvpn/login'
    sudo bash -c 'echo "PASSWORD" >> /etc/openvpn/login'
    
  5. Download PIA OpenVPN config file. Go to PIA OpenVPN Configurator and create a configuration file for your favorite location. Couple very important things here:

    • I got access denied - authentication failure on some of the servers, the others worked perfectly. Try another server if you face this issue as well.
    • You can only have a single location at a time. There is no automatic failover or connection to another region. Make sure to choose one that is reliable 24/7. For me for example, the closest server is always very busy with high latency throughout the evening, so I chose one that's a bit further but never as congested. Your speed should not be affected that much anyways as long as it's decently close.
    • Use the Recommended TCP configuration. When I tried with the recommended UDP configuration files, there was a successful connection and ping went through as well, but nothing else. I had a connection on paper, but there was no data flow. I don't know why this happened, but switching to the TCP/:502 setup solved the problem instantly.
  6. Save your configuration with nano /etc/openvpn/client/<country>.conf. Name it something simple, for example us-california.conf as this filename will become the name of the OpenVPN service later. Modify the file you just created (I suggest nano) at the following line: auth-user-pass -> auth-user-pass /etc/openvpn/login. If you do not do this, OpenVPN will ask for a username and password each time you want to connect, and that's not a good headless setup.

  7. Try the connection, this is where the new systemctl magic comes in.

    sudo systemctl start openvpn-client@<country>
    

    So based on the above example, <country> is us-californa. This should give you a some nice lines signaling that you are connected to the VPN.

  8. Type the following command, this will give you information about your connection. It will show you your current public IP address and you'll compare that to the one from before. If they match, your VPN is not working correctly. The goal is for them not to match of course.

    curl https://ipleak.net/json/
    

    You can stop and start the OpenVPN service with replacing start with stop or get information about the service with status.

  9. Enable the service so it starts at boot. We want the connection to automatically get established after each reboot. When you enable a service with systemctl, it will run at boot if the server gets restarted. Replace country as above.

    sudo systemctl enable openvpn-client@<country>
    
  10. Reboot with sudo reboot. After the server has started again, SSH in and test if your connection is up with the same command curl https://ipleak.net/json/. Take note of the IP address and make sure you are indeed connecting through your new VPN tunnel.

  11. Set up iptables rules. This is where we'll set up that all packets - directed outside of your local network - get dropped that are not going through the VPN tunnel. Execute these commands together otherwise you will be locked out of your server before you can finish. Copy the whole thing and paste as one.

    This allows in/output through port udp:53 and tcp:502 as discussed above. If you are using a different configuration than the recommended TCP one, make sure to change these commands accordingly. Change tcp to udp and 502 to 1198.

    Make sure to change the 192.168.0.0 to your local network's address, while keeping the /24 CIDR.

    # Allow loopback device (internal communication)
    sudo iptables -A INPUT -i lo -j ACCEPT
    sudo iptables -A OUTPUT -o lo -j ACCEPT
    
    #Allow all local traffic.
    sudo iptables -A INPUT -s 192.168.0.0/24 -j ACCEPT
    sudo iptables -A OUTPUT -d 192.168.0.0/24 -j ACCEPT
    
    # Allow VPN establishment
    # Only 2 ports open, 1 for DNS and 1 for VPN
    # If establishing thru an IP and not a name, the ones with port 53 can be removed
    # Port 1198 may be different depending on the VPN
    sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
    sudo iptables -A INPUT -p udp --sport 53 -j ACCEPT
    sudo iptables -A OUTPUT -p tcp --dport 502 -j ACCEPT
    sudo iptables -A INPUT -p tcp --sport 502 -j ACCEPT
    
    #Accept all TUN connections (tun = VPN tunnel)
    sudo iptables -A OUTPUT -o tun+ -j ACCEPT
    sudo iptables -A INPUT -i tun+ -j ACCEPT
    
    #Set default policies to drop all communication unless specifically allowed
    sudo iptables -P INPUT DROP
    sudo iptables -P OUTPUT DROP
    sudo iptables -P FORWARD DROP
    
  12. As I said I'm not a pro in iptables but these commands work well, just make sure if you modify any of it not to execute something you don't fully understand. If you are still connected, execute the command curl https://ipleak.net/json/ to check if you still have a connection to the internet and it is still going through the VPN tunnel. If it doesn't work, make sure to start the openvpn-client@<country> service.

  13. Install iptables-persistent so the configuration persists even after a reboot. When asked if you'd like to save the current configuration, click yes. The server will restart automatically, SSH in again when it comes back up.

    sudo apt-get install iptables-persistent -y && sudo netfilter-persistent save && sudo systemctl enable netfilter-persistent && sudo reboot
    
  14. Test if the killswitch is still working. With the following commands you can start & stop the OpenVPN service, as well as get the current status of it. You can execute the usual curl https://ipleak.net/json/ to test your connection. Remember, when the OpenVPN service is not running, you must not have any kind of internet connection.

    sudo systemctl start openvpn-client@<country>
    sudo systemctl stop openvpn-client@<country>
    sudo systemctl status openvpn-client@<country>