First, you’ll need to obtain your “.ovpn” configuration file from your VPN provider. Find and replace <config file> with the name of the file excluding the file extension.
There are two stages to this guide:
- VPN Client Connection/ Configuration
- UFW Firewall Configuration (to ensure traffic can only use VPN and prevent DNS Leak)
If you are using docker containers be sure to check the considerations at the end of this article.
VPN Client Connection/ Configuration
Prepare the configuration file:
# Disable IPv6 echo "#disable ipv6" | sudo tee -a /etc/sysctl.conf echo "net.ipv6.conf.all.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf echo "net.ipv6.conf.default.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf echo "net.ipv6.conf.lo.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf sudo sysctl -p # Move config file to /etc/openvpn mv <config file>.ovpn /etc/openvpn/<config file>.conf # Create .secrets file echo '<username>' >> /etc/openvpn/.secrets echo '<password>' >> /etc/openvpn/.secrets chmod 600 /etc/openvpn/.secrets # Modify config file vi <config file>.conf # Ensure you have no other auth-user-pass lines defined auth-user-pass .secrets # Add redirect-gateway to force traffic down TUN interface redirect-gateway # Add DNS server update script execution to config file script-security 2 up /etc/openvpn/update-resolv-conf down /etc/openvpn/update-resolv-conf # Save/close config file
We’ll now configure OpenVPN client to automatically connect to this VPN interface on startup:
# Edit /etc/default/openvpn, un-comment AUTOSTART="all" then save/close vi /etc/default/openvpn # Start / enable openvpn service at boot sudo systemctl start openvpn sudo systemctl enable openvpn
Confirm the VPN tunnel is up and public IP is that of the VPN provider:
# Look for a tun0 interface, if found you are connected! ifconfig # Check public IP is "hidden"/ different vs. machine not on the VPN curl ipinfo.io/ip
UFW Firewall Configuration
We’ll configure UFW to allow only allow outbound traffic to the VPN provider (“tun0” in this example) interface.
First we must enable forwarding:
# Set the DEFAULT_FORWARD_POLICY policy to ACCEPT vi /etc/default/ufw
Next we’ll configure the necessary UFW rules to facilitate the outbound traffic to the VPN provider, but block everything else. You’ll need to change:
- <VPN Server IP> to IPv4 address as-per the “remote xx.xx.xx.xx” line in your OpenVPN configuration file.
- <port> to the remote OpenVPN port (usually 1194 or 443)
- <LAN subnet> to network/subnet that represents your network – i.e. 172.16.0.0/16.
# Defaults ufw default deny incoming ufw default deny outgoing # Allow SSH from local LAN ufw allow from <LAN subnet> to any port 22 # UFW rule to ensure we only hit the VPN ufw allow out to <VPN server IP> port <port> ufw allow out to <LAN subnet> ufw allow out on tun0 # Enable the firewall ufw enable
If DNS lookups on the client fail you’ve missed the configuration lines from your OpenVPN configuration file, as above, you want to force DNS lookups over the VPN otherwise you’re leaking DNS requests, reducing the privacy value of your VPN.
# Add DNS server update script execution to config file script-security 2 up /etc/openvpn/update-resolv-conf down /etc/openvpn/update-resolv-conf
Considerations when using Docker Containers
If you want your docker containers to sit behind the VPN, ensure you use the “–net=host” argument. As per: https://docs.docker.com/engine/userguide/networking/default_network/container-communication/
Docker’s forward rules permit all external source IPs by default.
By default containers will use the docker0 interface and thus when your VPN goes down, they will still have external/ internet access. This statement only applies when using the default docker0 interface, not when binding the container to the “host” interface.
My experience shows that the default docker forward rule associated with the docker0 interface overrides any UFW rule (i.e. as defined above).
You can test container connectivity using the commands below:
# Test there is NO connectivity from container when VPN is down systemctl stop openvpn docker exec -it <container_name> /bin/bash ping 188.8.131.52 # Test this IS connectivity from container when VPN is up systemctl start openvpn docker exec -it <container_name> /bin/bash ping 184.108.40.206