I recently wanted to setup an Ubuntu virtual machine on my Proxmox server so that my friends and I could share a server for hosting things on. The issue was that I am currently using the default ports for the services we wanted to run on my existing internet connection. So the obvious options were as follows:
- Run the new services on non-default ports.
- Pay for a second internet connection/second IP address.
This either costs money, or causes unneccesary hassel. This is where the VPS comes in, im using an Amazon Web Services t2.micro instance based in London, (as close as possible to home to avoid performance issues), but you can use any server with a dedicated IP or DMZ which you aren’t using for any other services, ideally with a dedicated IP so not to cause double NAT issues.
So, to start, I’m assuming you have both your client (my local VM) and your server (my remote VPS) setup with Ubuntu and connected to the internet. On both machines, begin by installing wireguard, we are going to use wireguard to create a VPN tunnel between the VPS (server) and the VM (client).
$ sudo apt update $ sudo apt install wireguard
Now we need to generate a public and private key. This command uses generates a private key, with the ‘wg genkey’ command, creates a file called privatekey, then pipes the output of ‘wg genkey’ into ‘wg pubkey’, which takes the private key and outputs a matching public key, again, run the following command on both the client and the server.
$ wg genkey | sudo tee /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey
You should now have 2 files in ‘/etc/wireguard’, ‘publickey’, and ‘privatekey’. You can view them using the ‘cat’ command. You will need them later.
We now need to begin creating our config files for the wireguard VPN interface. We can start on the server, begin by running:
$ sudo vim /etc/wireguard/wg0.conf
This creates the file wg0.conf in /etc/wireguard, in the command above im using vim, but you can use your preferred text editor. In the file you should insert the following, making sure to replace the PublicKey with the public key from the client, and PrivateKey with the private key from the server.
[Interface] Address = 10.66.66.1/32 ListenPort = 51820 PrivateKey = <Server PrivateKey here> PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] PublicKey = <Client PublicKey here> AllowedIPs = 10.66.66.2/32
The ‘PostUp’ and ‘PostDown’ sections enable NAT on the VPN to allow the client to connect to the internet via the server.
Now open the same file on the client but instead insert this:
[Interface] PrivateKey = <Client PrivateKey here> Address = 10.66.66.2/32 [Peer] PublicKey = <Server Privatekey here> Endpoint = <Server IP Address Here>:51820 AllowedIPs = 0.0.0.0/0
Same thing as before, but we need to set the endpoint to the server, and the PrivateKey and PublicKey are swapped.
Now run on both the client and the server:
$ sudo wg-quick up wg0
This will set the interface ‘wg0’ up and start wireguard, creating a tunnel between both machines.
You can check the connection is successful by seeing if you can ping the client from the server, run this on the client:
$ ping 10.66.66.1
If you did everything correctly, you should see the following output!:
PING 10.66.66.1 (10.66.66.1) 56(84) bytes of data. 64 bytes from 10.66.66.1: icmp_seq=1 ttl=64 time=14.6 ms 64 bytes from 10.66.66.1: icmp_seq=2 ttl=64 time=15.3 ms 64 bytes from 10.66.66.1: icmp_seq=3 ttl=64 time=15.5 ms 64 bytes from 10.66.66.1: icmp_seq=4 ttl=64 time=15.5 ms --- 10.66.66.1 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 14.612/15.224/15.500/0.358 ms
You can also use ‘wg show’ to check the connection.
$ wg show interface: wg0 public key: (hidden) private key: (hidden) listening port: 54832 fwmark: 0xca6c peer: endpoint: (hidden) allowed ips: 0.0.0.0/0, ::/0 latest handshake: 1 minute, 20 seconds ago transfer: 663.55 MiB received, 87.98 MiB sent
On both the client and the server, run this command to start up the VPN on boot.
$ sudo systemctl enable wg-quick@wg0
Almost there! We are done on the client now, we just need to enable some iptable rules on the server, to forward all ports from the server to the client via the VPN tunnel.
Run this script on the server:
sudo iptables -A FORWARD -i eth0 -o wg0 -p tcp --syn --dport 1:21 -m conntrack --ctstate NEW -j ACCEPT sudo iptables -A FORWARD -i eth0 -o wg0 -p tcp --syn --dport 23:51819 -m conntrack --ctstate NEW -j ACCEPT sudo iptables -A FORWARD -i eth0 -o wg0 -p tcp --syn --dport 51821:65535 -m conntrack --ctstate NEW -j ACCEPT sudo iptables -A FORWARD -i eth0 -o wg0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT sudo iptables -A FORWARD -i wg0 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 1:21 -j DNAT --to-destination 10.66.66.2 sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 23:51819 -j DNAT --to-destination 10.66.66.2 sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 51821:65535 -j DNAT --to-destination 10.66.66.2
And thats it! Thanks for reading, the only things you need to know now are:
The only ports you won’t be able to use now are 51820, and 22, because they are in use by the server.
- You should now be able to access the clients ports and services on the IP address that was assigned to the server!
- I would highly reccommend installing UFW firewall on the client.
- DO NOT use these rules in a production environment! I am using a disposable VPS
- If you want to be extra safe you should manually forward the ports you need from the server.