back to homepage

Configuring WireGuard VPN on Oracle

My favourite kind of price is free. Hence, on perusing through all those affiliate web articles which blindly market VPN services and assign them arbitrary ratings, I had an epiphany—why not build my own VPN on free cloud compute? Oracle has a generous free tier, perhaps to compensate for their horrible UI/UX.

I signed up for an Oracle cloud account and spun up my free eligble Ubuntu 22.04 minimal instance. It has a solid gigabyte of RAM and a single CPU core, comfortably enough for a basic WireGuard setup.

The First Attempt

I followed this DigitalOcean article to setup WireGuard. It didn't work. To troubleshoot, I checked ss -lun 'sport = :51820' and saw two lines, indicating that WireGuard indeed was listening on the proper port. At this point, I suspected a firewall issue, so I tried nc -l -p 33333 on the server and telnet [IP] 33333 on my desktop. Telnet returned an error. Okay, so the ports probably aren't open. I tried allowing the ports with iptables but that did nothing. I allowed both TCP and UDP just in case, even though I knew that WireGuard only works over UDP.

$ sudo iptables -A INPUT -p tcp --dport 51820 -j ACCEPT
$ sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT

Maybe I needed to explicitly open the port on Oracle's end? After much roaming around, I managed to navigate to the security list panel that enabled me to add a couple rules to enable ingress and egress traffic for 51820. I tested again, but WireGuard stayed frustratingly silent. I carefully checked the firewalls on the server again. I used a minimal Ubuntu installation so UFW wasn't present. I meticulously checked each rule in the INPUT chain of iptables and found this:

REJECT     all  --  anywhere     anywhere     reject-with icmp-host-prohibited

This rule rejected all traffic and came before the new iptable rules I added. After this experience with iptables, I can see why UFW exists. I also needed to drop a single rule in the FORWARD chain. But after that, WireGuard worked perfectly! I was able to curl ifconfig.me and get the IP address of the server instead of my desktop.

The only problem is that this current setup doesn't include IPV6. My ISP has IPV6 and defaults to it so a VPN without IPV6 is really inconvenient. To ensure I was using the WireGuard VPN I had to disable IPV6, do whatever, then enable it again.

$ sudo sysctl -w net.ipv6.conf.wlan0.disable_ipv6=1
$ ...
$ sudo sysctl -w net.ipv6.conf.wlan0.disable_ipv6=0

Fun fact, I was mindlessly messing around with iptables when I accidentally set the policy of the INPUT chain to drop. Immediately, the SSH connection became unresponsive and I realized my mistake. But there was no need to worry, iptables isn't persistent by default and I simply had to restart the instance through Oracle's web interface.

Anyway, that was my first attempt at a VPN. In the second attempt, I enable IPV6.

The Second Attempt

I couldn't figure out how to enable IPV6 for my Ubuntu server. I contacted Oracle's support team and they claimed that I couldn't—the only way was to create a new virtual cloud network (VCN) and delete the current one. Okay, so I created a new VCN. But I couldn't attach it to my Ubuntu instance, because the instance isn't the right "shape." Okay, okay, okay. A bit annoying but I can just delete my current instance and VCNs and start from scratch, making sure to enable IPV6 when I create my new instance.

I pressed the red "terminate" button for my instance, and it didn't delete itself. I couldn't terminate it again, the button was grayed out. I thought I screwed everything up but when I asked Oracle support they assured me that on deleting an instance, it would remain visible in the instance list but remove itself automatically in around 24 hours—no further action necessary. If an instance is deleted, than why does it remain in the instance list without any UI indication?

After waiting a day my instance list is blank. I have to delete the VCNs now. I press the red button to terminate the VCN, and it prompts me to scan for the "associated resources" to delete first. Naturally, I click the scan button then the delete all button. But, I got this obscure error referring to some type of conflict between route tables. Again, I asked Oracle support, and after a lot of prodding I found out I needed to manually go to the route table attached to the VCN and delete each route rule manually. Why? Why can't oracle delete the damn route table rules automatically?

Phew. Three paragraphs later, we finally have deleted everything and can start from scratch. I create a new instance, pick the right shape and operating system, double-check all the settings, and then expand the VCN section to click the checkbox to assign an IPV6 address—wait, why is the checkbox grayed out? I read the message above and it says to configure this part of the VCN and subnet I have to create my own VCN and subnets first, then attach it to the instance on creation.

So. So. I go ahead and create my own VCN and subnet, configure everything to the best of my ability. I didn't understand many of the options and checkboxes but I did make sure to enable IPV6. Then, I created an instance, attached the VCN and subnet to it. I excitingly try SSHing into the machine and—the connection hangs. I couldn't SSH into the instance. So I had to debug why, and I observed that the SSH port isn't opened.

$ nmap -Pn -p 22 [SERVER IP]
Starting Nmap 7.95 ( https://nmap.org ) at 2024-08-19 14:07 EDT
Nmap scan report for [SERVER IP]
Host is up.

PORT   STATE    SERVICE
22/tcp filtered ssh

Nmap done: 1 IP address (1 host up) scanned in 2.02 seconds

After contacting Oracle support again and looking around carefully in the Oracle web interface, I noticed I didn't have an internet gateway. So I created one and attached it to the route table. I then went to configure the route table, but got this error that stated, "Rules in the route table must use private IP as a target. Or the route table can be empty (no rules)." From a Reddit post, it turns out I needed to not attach the internet gateway to my route table when I created the gateway. Finally, after deleting and re-creating the internet gateway without attaching the route table, I added a couple route rules and tested the SSH again.

$ sudo chmod 0600 ssh-key-2024-08-19.key
$ ssh -i ssh-key-2024-08-19.key ubuntu@[SERVER IP]
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 6.5.0-1023-oracle x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
   just raised the bar for easy, resilient and secure K8s cluster deployment.
...

It works! I could SSH into my machine! I proceeded to run some commands to get WireGuard up and going.

$ sudo apt update
$ sudo apt install wireguard
$ wg genkey | sudo tee /etc/wireguard/private.key
$ sudo chmod go= /etc/wireguard/private.key
$ sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key

From the result of ip a my interface is named ens3. I followed the WireGuard configuration example provided in the DigitalOcean article.

# /etc/wireguard/wg0.conf for server
[Interface]
PrivateKey = [SERVER PRIVATE KEY]
Address = 10.8.0.1/24, fdfd:0704:cc10::1/64
ListenPort = 51820
SaveConfig = true

PostUp = iptables -t nat -I POSTROUTING -o ens3 -j MASQUERADE
PostUp = ip6tables -t nat -I POSTROUTING -o ens3 -j MASQUERADE
PreDown = iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE
PreDown = ip6tables -t nat -D POSTROUTING -o ens3 -j MASQUERADE

I setup the iptables, making sure to persist my changes and prepend the rule to open 51820. I persist the changes of iptables too.

$ sudo apt-get install iptables-persistent
$ sudo iptables -I INPUT -p udp --dport 51820 -j ACCEPT
$ sudo iptables -D FORWARD 1
$ sudo iptables-save | sudo tee /etc/iptables/rules.v4
$ sudo netfilter-persistent save
$ sudo systemctl enable netfilter-persistent

I went to configure ip6tables but it literally has no rules and the policy for all chains is to accept. Probably not ideal from a security stand point, but I left it alone.

I started configuring the peer (my desktop) which is simple enough.

# /etc/wireguard/wg0.conf for peer
[Interface]
PrivateKey = [PEER PRIVATE KEY]
Address = 10.8.0.2/24
Address = fdfd:0704:cc10::2/64

[Peer]
PublicKey = [SERVER PUBLIC KEY]
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = [SERVER IP]:51820

On the server I added my desktop as a peer.

$ sudo wg set wg0 peer [PEER PUBLIC KEY] allowed-ips 10.8.0.2,fdfd:0704:cc10::2

Finally, with bated breath, I tested the VPN and it worked!

$ sudo wg-quick up wg0
$ curl --ipv4 ifconfig.me
[SERVER IPV4 ADDRESS]
$ curl --ipv6 ifconfig.me
[SERVER IPV6 ADDRESS]
$ sudo wg-quick down wg0

Without the VPN I get 37.9 Mbps download and 30.1 Mbps upload, with 6 ms latency on the Google speed test. With the WireGuard VPN I get 44.1 Mbps download and 25.4 Mbps upload, with 22 ms latency. Somehow the download is faster with the VPN turned on? This is probably just a fluke.

Overall, the WireGuard VPN took only three evenings to setup. The first day to experiment, the second day to wait for the first day's instance and VCNs to delete, and the third day to setup the final VPN. Not bad.