Setup:
- A Linux host PC (Ubuntu 18.04/20.04) Running an up-to-date Virtual Box.
- Guest: A headless Virtual server (Ubuntu 18.04/20.04)
- Valid VPN account with a 3rd party. (in my case: NordVPN)
Goal:
- Start the virtual machine (guest) headless as a service when booting the Host machine.
- The VM must be able to log in automatically as a service without manually providing account credentials
- The VM uses a bridged network so it has a reachable IP on the LAN
- Using the VM-IP as a gateway for devices that need a VPN connection.
- No other outbound connection possible for devices using this gateway when the VPN-connection to NordVPN goes down, No internet connection is available.
NOTE: I've got my inspiration for this setup from the fine guys over @ Craft Computing. Credits to them for their awesome instruction videos. Link to the Video
Create the VM
I’ve used the following specifications to install the VPN-server in virtual box:
(not covered in this article)
1 CPUChanged to 2 Cores. 1 Core caused too much packet-loss with the UDP protocol.- 1Gb Ram
- Bridged networking (static IP or reserved IP - see later)
- 8GB VDI dynamic size
- apply all the latest upgrades to be current
- Enable SHH-Server [ sudo apt install openssh-server ]
Setting up the VM to be a VPN gateway:
Setup Staic IP address:
For Ubuntu 18.04 and up, netplan is the suggested way to set up a static IP.
sudo netplan generatesudo nano /etc/netplan/50-cloud-init.ymal
Edit as follows:
(given 192.168.1.0/24 is your network and 192.168.1.1 is your main gateway on the router,
and enp0s is your network adapter - Often it is eth0 instead. Use ifconfig to find out)
and enp0s is your network adapter - Often it is eth0 instead. Use ifconfig to find out)
│ File: /etc/netplan/50-cloud-init.yaml
─────|──────────────────────────────────────
1 │ network:
2 │ version: 2
3 │ renderer: networkd
4 │ ethernets:
5 │ enp0s3:
6 │ dhcp4: no
7 │ dhcp6: no
8 │ addresses: [192.168.1.29/24, ]
9 │ gateway4: 192.168.1.1
10 │ nameservers:
11 │ addresses: [1.1.1.1,1.0.0.1,8.8.8.8,8.8.4.4]
Now apply these setting to your VM:
sudo netplan apply
[test if you have the correct static IP setup for your VM after reboot]
Install dependencies and applications needed:
sudo apt updatesudo apt upgradesudo apt install openvpn unzip
Download the ovpn files for your provider ( in my case: NordVPN)
wget https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip
Extract the ovpn.zip & move them to the right place:
unzip ovpn.zipsudo mv ovpn_tcp /etc/openvpn/ovpn_tcpsudo mv ovpn_udp/ /etc/openvpn/ovpn_udp
Browse the list and make your choice (udp / tcp) country / server:In my case, I go for us5000.nordvpn.com.udp.ovpnBut you can go for any other of your choice from the 2 folders (5000+ servers)NOTE: you might want to acquire a new zip file on a regular basisto get the latest server list for your VPN provider.
Create a script to connect to NordVPN:
cd /etc/openvpnsudo nano auth.txtsudo nano connect.sh
Add your account credentials (one on each line)
───────┬───────────────────────────────────
│ File: auth.txt
───────┼───────────────────────────────────
1 │ Your NordVPN-UserName
2 │ Your NordVPN password
Add the following line to the file
──────────────────────────────────────────────
File: connect.sh
──────────────────────────────────────────────
sudo openvpn --config "/etc/openvpn/ovpn_udp/us5000.nordvpn.com.udp.ovpn"
--auth-user-pass /etc/openvpn/auth.txt
NOTE: "us5000.nordvpn.com.udp.ovpn"
use the server that you find works best for you (udp protocol)
Add the correct IP-tables:
cd /etc/openvpnsudo nano iptables.sh
Add the following lines:
───────┬──────────────────────────────────────────────────────────────
│ File: iptables.sh
───────┼───────────────────────────────────────────────────────────────
1 │ #!/bin/bash
2 │ # Flush all existing settings:
3 │ iptables -t nat -F
4 │ iptables -t mangle -F
5 │ iptables -F
6 │ iptables -X
7 │
8 │
9 │ # Block All:
10 │ iptables -P OUTPUT DROP
11 │ iptables -P INPUT DROP
12 │ iptables -P FORWARD DROP
13 │
14 │
15 │ # Allow Localhost communictaion:
16 │ iptables -A INPUT -i lo -j ACCEPT
17 │ iptables -A OUTPUT -o lo -j ACCEPT
18 │
19 │
20 │ # Allow communication with a DHCP server:
21 │ iptables -A OUTPUT -d 255.255.255.255 -j ACCEPT
22 │ iptables -A INPUT -s 255.255.255.255 -j ACCEPT
23 │
24 │
25 │ # Allow communication within your local network
26 │ iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT
27 │ iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT
28 │ ## Replace this CIDR with your ##
29 │
30 │ # Allow established sessions to receive traffic:
31 │ iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
32 │
33 │
34 │ # Allow TUN
35 │ iptables -A INPUT -i tun+ -j ACCEPT
36 │ iptables -A FORWARD -i tun+ -j ACCEPT
37 │ iptables -A FORWARD -o tun+ -j ACCEPT
38 │ iptables -t nat -A POSTROUTING -o tun+ -j MASQUERADE
39 │ iptables -A OUTPUT -o tun+ -j ACCEPT
40 │
41 │
42 │ # allow VPN connection
43 │ iptables -I OUTPUT 1 -p udp --destination-port 1194 -m comment
--comment "Allow VPN connection" -j ACCEPT
44 │
45 │
46 │ # Block All
47 │ iptables -A OUTPUT -j DROP
48 │ iptables -A INPUT -j DROP
49 │ iptables -A FORWARD -j DROP
50 │
51 │
52 │ echo "saving"
53 │ iptables-save > /etc/iptables/rules.v4
54 │ echo "done"
Set correct permissions and rights for the scripts generated:
cd /etc/openvpnsudo chown root:root auth.txt connect.sh iptables.shsudo chmod +x connect.sh iptables.shsudo chmod 600 auth.txt
VPN scripts that will be started as a service at boot time:
sudo nano /usr/local/bin/mystartup.shsudo chown root:root /usr/local/bin/mystartup.shsudo chmod +x /usr/local/bin/mystartup.sh
Add the following to the script:
───────┬─────────────────────────────────
│ File: mystartup.sh
───────┼──────────────────────────────────────────────
1 │ #!/bin/sh -e
2 │ sudo bash /etc/openvpn/iptables.sh &
3 │ sleep 15
4 │ sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
5 │ sudo bash /etc/openvpn/connect.sh &
6 │
7 │ exit 0
Adding a service to the VM:
Using systemd to start the vpn connection as a service at boot, we need a service script to launch "mystartup.sh"
sudo nano /etc/systemd/system/mystartup.service
File content:
───────┬─────────────────────────────────────────────────
│ File: mystartup.service
───────┼──────────────────────────────────────────────────
1 │ # mystartup.service (systemd)
2 │
3 │ [Unit]
4 │ Description=Starts the VPN connection
5 │ ConditionPathExists=/usr/local/bin/mystartup.sh
6 │
7 │ [Service]
8 │ type=forking
9 │ ExecStart=/usr/local/bin/mystartup.sh start
10 │ TimeoutSec=0
11 │ StandardOutput=tty
12 │ RemainAfterExit=yes
13 │ SysVstartPriority=99
14 │
15 │ [Install]
16 │ WantedBy=multi-user.target
Enabling "mystartup.service" as a service:
sudo systemctl enable mystartup
Starting this "mystartup.service" service:
sudo systemctl start mystartup
Stopping this "mystartup.service" service:
sudo systemctl stop mystartup
Status of this "mystartup.service" service:
sudo systemctl status mystartup
This should show something like this:
mystartup.service - Starts the VPN connection
Loaded: loaded (/etc/systemd/system/mystartup.service; enabled;
vendor preset: enabled)
Active: active (exited) since Sat 2020-08-01 10:27:31 CEST; 5h 14min ago
Main PID: 832 (code=exited, status=0/SUCCESS)
Tasks: 4 (limit: 1093)
CGroup: /system.slice/mystartup.service
├─1149 sudo bash /etc/openvpn/connect.sh
├─1150 bash /etc/openvpn/connect.sh
├─1151 sudo openvpn --config
/etc/openvpn/ovpn_udp/us5000.nordvpn.com.udp.ovpn
--auth-user-pass /etc/openvpn/auth.txt
└─1152 openvpn --config
/etc/openvpn/ovpn_udp/us5000.nordvpn.com.udp.ovpn
--auth-user-pass /etc/openvpn/auth.txt
That should be it! You can test if you have a tunnel by checking the output of ifconfig.
And also see what your external IP is with curl https://ipinfo.io/ip
And also see what your external IP is with curl https://ipinfo.io/ip
Start VM as a service at boot time of the Host:
In the assumption, your VM is named `VPN` then VirtualBox has a way of starting VM’s as a service described in the VirtualBox documentation. However, It seems to fail more than work.
In Recent distribution driven by the "systemd" implementation, it is fairly easy to create a service for this.
- Your user must be a member of the vboxusers group:
sudo usermod -aG vboxusers YourUserName
- Create a service file in /etc/systemd/system
sudo nano /etc/systemd/system/autostart_vpn.service
───────┬────────────────────────────────────────────────
│ File: /etc/systemd/system/autostart_vpn.service
───────┼────────────────────────────────────────────────
1 │ [Unit]
2 │ Description=VM VPN
3 │ After=network.target vboxdrv.service
4 │ Before=runlevel2.target shutdown.target
5 │
6 │ [Service]
7 │ User=YourUserName
8 │ Group=vboxusers
9 │ Type=forking
10 │ Restart=yes
11 │ TimeoutSec=7min
12 │ IgnoreSIGPIPE=no
13 │ KillMode=process
14 │ GuessMainPID=no
15 │ RemainAfterExit=yes
16 │
17 │ ExecStart=/usr/bin/VBoxManage startvm VPN --type headless
18 │ ExecStop=/usr/bin/VBoxManage controlvm VPN acpipowerbutton
19 │
20 │ [Install]
21 │ WantedBy=multi-user.target
- Enable the service “autostart_vpn.service”:
sudo systemctl enable autostart_vpn - Start the service:
sudo systemctl start autostart_vpn
The next time your host boots, it will fire up a VM that can serve your network as a VPN gateway.
Enjoy.
Excellent write-up on how to get this going! I used this and a video on YouTube from Craft Computing to setup mine. Everything works good with the primary subnet the server and my computers are on, but I can't get other subnets like my streaming subnet, IoT devices to work with this setup for nothing. They just won't pass traffic over the VPN even though I can ping them just fine from the server console. Any ideas how to get this to work with multiple subnets?
ReplyDeleteThank you for your comment, Glad I could be of help.
DeleteYou might want to setup the VPN on your main subnet. Or run multiple VPN-VM's. one for each subnet. But make sure to check your devices if you have IPv6 enabled. This solution is IPv4 only, and if your devices have both enabled, they might choose to bypass the VPN and go strait to the main network using IPv6. Alternatively, you could run a pfSense router on an old computer or virtualize it, and setup a VPN for your entire network and or selective VLans.
Been trying to get this working for days and finally got it working thanks to this post. Thanks for the time and effort to write it up!
ReplyDelete