Create your own private VPN with Headscale, Tailscale, and Oracle Cloud Free Tier

 

I've blogged about Oracle's free tier before and you might be wondering "What can I do with a free online compute instance?" How about setting up your own VPN! Instructions:

1. Follow my other guide to create an Oracle Cloud free tier account but use the "Canonical Ubuntu 22.04 Minimal aarch64" image and keep the default of size 1 core OCPU, 6 GB memory -- this will be for our Headscale server, which doesn't require many resources (we'll use the remainder of our free tier allotment for the Tailscale exit node)

2. Once the instance is running, set the static IP and add the following ports to the Oracle Cloud Ingress Rules:

  • TCP: 80, 443, 50443
  • UDP: 3478, 41641

  • 3. Purchase a domain from your desired registrar. In this guide I'll use mydomain.com as the example.

    4. In the domain registrar DNS settings, create an A record for a subdomain Host (in this example I'll use vpn.mydomain.com), and the Public IP address from Step 1 above for the value. Wait 1-24 hours for the setting to propagate: https://dnschecker.org/

    5. On your own computer, create an ED25519 SSH key, which is shorter and slightly more performant compared to RSA while maintaining equivalent security: ssh-keygen -t ed25519

    6. Now, SSH into the compute instance and switch to using the new key:

    sudo su -

    apt update

    systemctl stop ssh

    apt autopurge -y openssh-server openssh-client xz-utils fuse3

    apt install -y dialog nano less tinysshd ca-certificates --reinstall

    echo 'CONTENTS OF YOUR ED25519 SSH KEY IN STEP 3 ABOVE HERE' > ~/.ssh/authorized_keys

    (systemctl is-enabled tinysshd.socket && systemctl restart tinysshd.socket) || (systemctl start tinysshd.socket && systemctl enable tinysshd.socket)

    (systemctl is-enabled systemd-networkd && systemctl restart systemd-networkd) || (systemctl start systemd-networkd && systemctl enable systemd-networkd)


    7. Test you can login via a new terminal on your local machine: ssh -i id_ed25519 root@YOUR.CLOUD.IP.ADDRESS

    8. Set up automatic OS updates, apply any pending updates, then restart the compute instance:

    apt install -y unattended-upgrades update-notifier-common

    sed -i 's/^\/\/Unattended-Upgrade::Remove-Unused-Dependencies.*$/Unattended-Upgrade::Remove-Unused-Dependencies "true";/' /etc/apt/apt.conf.d/50unattended-upgrades

    sed -i 's/^\/\/Unattended-Upgrade::Automatic-Reboot .*$/Unattended-Upgrade::Automatic-Reboot "true";/' /etc/apt/apt.conf.d/50unattended-upgrades

    sed -i 's/^\/\/Unattended-Upgrade::Automatic-Reboot-WithUsers.*$/Unattended-Upgrade::Automatic-Reboot-WithUsers "true";/' /etc/apt/apt.conf.d/50unattended-upgrades

    echo -e "APT::Periodic::Update-Package-Lists \"1\";\nAPT::Periodic::Unattended-Upgrade \"1\";\nAPT::Periodic::AutocleanInterval \"7\";" > /etc/apt/apt.conf.d/20auto-upgrades

    apt upgrade -y && apt dist-upgrade -y && apt autopurge -y && apt clean

    reboot

    9. Login once again and remove any old accounts

    userdel -r ubuntu

    userdel -r opc


    10. Now we can install Headscale. Note: I'll be using the latest beta version since it's a major rewrite of the functionality.

    cd /tmp

    curl -sLO https://github.com/juanfont/headscale/releases/download/v0.23.0-beta1/headscale_0.23.0-beta1_linux_arm64.deb

    apt install ./headscale*.deb

    echo '{"acls":[{"action":"accept","src":["*"],"dst":["*:*"]}]}' > /etc/headscale/acl.hujson

    chmod 644 /etc/headscale/acl.hujson

    apt install -y wireguard-tools

    wg genkey > /etc/headscale/private.key

    chmod 400 /etc/headscale/private.key

    systemctl enable headscale


    11. We next need to configure Headscale: nano /etc/headscale/config.yaml

    • server_url: https://vpn.mydomain.com:443
    • listen_addr: 0.0.0.0:443
    • grpc_listen_addr: 0.0.0.0:50443
    • allocation: random
    • acme_email: "youremail@mydomain.com"
    • tls_letsencrypt_hostname: "vpn.mydomain.com"
    • policy > path: "/etc/headscale/acl.hujson"
    • base_domain: vpn.mydomain.com

    Since we'll be using Tailscale like a traditional VPN, we don't need to allow devices to communicate with each other so we'll set this

    • magic_dns: false

    You can also optionally change the DNS upstream servers:

    • nameservers:
    •    - 1.1.1.2
    •    - 1.0.0.2

    Save and close the config.yaml file.

    12. Although we already allowed the necessary ports in Step 2 above, Ubuntu has its own firewall you need to allow access:

    iptables -I INPUT 6 -m state --state NEW -p tcp --dport 80 -j ACCEPT

    iptables -I INPUT 6 -m state --state NEW -p tcp --dport 443 -j ACCEPT

    iptables -I INPUT 6 -m state --state NEW -p tcp --dport 50443 -j ACCEPT

    iptables -I INPUT 6 -m state --state NEW -p udp --dport 41641 -j ACCEPT

    iptables -I INPUT 6 -m state --state NEW -p udp --dport 3478 -j ACCEPT

    netfilter-persistent save

    13. Now we're ready to start Headscale:

    systemctl start headscale

    sleep 10

    systemctl status headscale

    14. It should say Headscale is "active (running)". You can also browse to https://vpn.mydomain.com/windows and see instructions. If not, please troubleshoot.

    Note: Headscale does not have a native graphical user interface (GUI) - you interact with it solely via the command line interface (CLI). Some community-supported GUI options exist, but this guide will focus on the command line.

    15. Create a user account for the VPN exit node we're about to create (change bold to your desired name): headscale users create mynet

    16. Now that Headscale is running, let's create our Tailscale exit node! Follow Step 1 above again to create a new cloud compute instance with size 3 core OCPU, 18 GB memory

    17. Follow Steps 6-9 above to update and harden the instance.

    18. Follow Step 12 above to open the necessary OS ports.

    19. Now we can install and configure the Tailscale exit node with Linux optimizations:

    curl -fsSL https://tailscale.com/install.sh | sh

    echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.d/99-tailscale.conf

    echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.d/99-tailscale.conf

    sysctl -p /etc/sysctl.d/99-tailscale.conf

    printf '#!/bin/sh\n\nethtool -K %s rx-udp-gro-forwarding on rx-gro-list off \n' "$(ip route show 0/0 | cut -f5 -d" " | head -n1)" | tee /etc/networkd-dispatcher/routable.d/50-tailscale

    chmod 755 /etc/networkd-dispatcher/routable.d/50-tailscale

    /etc/networkd-dispatcher/routable.d/50-tailscale

    tailscale up --advertise-exit-node --login-server=https://vpn.mydomain.com:443

    20. It will provide a URL for you to open. Click on it and copy the command to authenticate the request. Paste the command into your Headscale server terminal (changing USERNAME to the user you created in Step 15 above). It should respond with Node yournode registered

    21. Then enable the new exit node:

    headscale routes enable -r 1

    headscale routes enable -r 2

    22. Whew! The Headscale server and Tailscale exit nodes are now all set up. Let's try it out! Install the Tailscale client on a device. In this example, I'll use Android.

    23. After installing Tailscale from the Google Play Store, open it. Tap "Get Started". Tap "OK" at the VPN prompt. At the screen with the "Log in" button, quickly tap the gear icon in the top-right corner. (If you wait too long and it redirects you to a login page with various SSO options, tap the back button to go back to the prior screen).

    24. On the Settings page, tap Accounts.

    25. On the Accounts page, tap the three vertical button icon in the top-right corner and select Use an alternate server

    26. Type https://vpn.mydomain.com and then tap "Add account"

    27. Copy the resulting command shown to your Headscale server to authenticate.

    28. Once you get the Node yournode registered message, go back to the mobile app. In the EXIT NODE dropdown, select the exit node you created above. It should now appear in blue at the top of the Tailscale app screen and you should now be connected! Browse to https://www.whatismyip.com/ to verify.

    Enjoy.


    Comments

    Popular Posts