Self hosting your VPN using OpenVPN
šŸ”Œ

Self hosting your VPN using OpenVPN

Created
Nov 14, 2022 04:07 AM
Last Updated
Last updated April 13, 2023
Owners
Tags
devops
docker
development
self-hosted
cloud
Status
Complete
Ā 

Welcome Welcome šŸ‘!

Ā 
Ā 
Ā 

What the heck is a VPN?

A virtual private network, or VPN, is an encrypted connection over the Internet from a device to a network. The encrypted connection helps ensure that sensitive data is safely transmitted. It prevents unauthorized people from eavesdropping on the traffic and allows the user to conduct work remotely. VPN technology is widely used in corporate environments.
Ā 

What are the available VPN providers in the market?

  1. Express VPN
    1. notion image
  1. Nord VPN
    1. notion image
  1. Surfshark
    1. notion image
  1. OpenVPN
    1. notion image
  1. Tailscale
    1. notion image
      Ā 

Why to use a third party VPN provider and why not?

Why NOT?

  1. When you use a VPN service, your activity is only encrypted until it reaches the endpoint for that service. All of your activities can be monitored and logged by that VPN provider.
  1. No support for ad-blocking and trackers online.
  1. Probable breach/sell of data.
  1. Data transfer speed caps.

Why you should?

  1. You can switch to multiple countries, you can still do it with self hosted, but the infrastructure would cost you more than a regular VPN service provider.
Ā 

Ā 

What is OpenVPN?

notion image
OpenVPNĀ is a self-hostedĀ virtual private networkĀ (VPN) system that implements techniques to create secure point-to-point or site-to-site connections in routed or bridged configurations and remote access facilities. It implements bothĀ client and serverĀ applications.
OpenVPN allowsĀ peersĀ toĀ authenticateĀ each other usingĀ pre-shared secret keys,Ā certificatesĀ orĀ username/password. When used in a multiclient-server configuration, it allows the server to release an authentication certificate for every client, usingĀ signaturesĀ andĀ certificate authority.
It uses theĀ OpenSSLĀ encryptionĀ libraryĀ extensively, as well as theĀ TLSĀ protocol, and contains many security and control features. It uses a custom security protocol[11]Ā that utilizesĀ SSL/TLSĀ for key exchange.
Ā 
Enough talk šŸ˜¬, is it free?
Ā 
Yes, OpenVPN is open-source and free to use software, which means you pay only for the infrastructure you setup
Ā 
GitHub:
openvpn
OpenVPN ā€¢ Updated Jan 26, 2024
Ā 

What is and Why Docker šŸ‹, why not install bare-metal?

> The future is container(ising) your software, easy replication of your infra, auto recovery on failureā€¦ā€¦ā€¦
notion image
Ā 
Read more about configuration drifts and how Docker solves it here
Ā 

Talk is cheap, guide me through the setup.

To use a VPN you need an always on computing power, we will harness the power of the cloud for this case.
To technically state, I would be using Microsoft Azureā€™s Virtual Machines

Microsoft! do the honors (an Introduction to Msft azure playform)

Video preview

Ā 

Technical Setup šŸ’»

  1. After you have signed up for Azure, and have a billing method/credit setup in your account, visit: https://portal.azure.com/#home
    1. You should be greeted with a dashboard similar to this.
      1. notion image
  1. Create a resource, in Azure any VM/Database you setup, is called a resource.
    1. notion image
      notion image
      Ā 
      notion image
    2. Please specify:
      1. A name for the virtual machine
      2. A region where you want the vpn connection to be made. (this is a very crucial step, keep it in mind)
      3. A machine size, there are a plethora of options to select, please check the pricing page of Azure, anyway the vm should have >1GB RAM
      4. notion image
        After the instance details are specified, come down to setup login creds to the vm.
        šŸ”
        I have selected SSH pub-key based auth to the vm, since it would provide more security than password based security, as I need to carry the private key with me to login to the vm.
        notion image
      Ā 
    3. Now we are pretty much done setting up the VM, click the Review + create button to Azure do the magic creating the vm for you. We wonā€™t fiddle with next options, as this is just a demo, if you want you can fiddle around with other options.
      1. notion image
        šŸŖ„
        Give a moment for the VM to be created. Also, I would be providing the azure automation template JSON āœØ if you do not want to go through the above steps.

        JSON template

        { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "type": "string" }, "networkInterfaceName": { "type": "string" }, "networkSecurityGroupName": { "type": "string" }, "networkSecurityGroupRules": { "type": "array" }, "subnetName": { "type": "string" }, "virtualNetworkName": { "type": "string" }, "addressPrefixes": { "type": "array" }, "subnets": { "type": "array" }, "publicIpAddressName": { "type": "string" }, "publicIpAddressType": { "type": "string" }, "publicIpAddressSku": { "type": "string" }, "pipDeleteOption": { "type": "string" }, "virtualMachineName": { "type": "string" }, "virtualMachineComputerName": { "type": "string" }, "virtualMachineRG": { "type": "string" }, "osDiskType": { "type": "string" }, "osDiskDeleteOption": { "type": "string" }, "virtualMachineSize": { "type": "string" }, "nicDeleteOption": { "type": "string" }, "adminUsername": { "type": "string" }, "adminPublicKey": { "type": "secureString" } }, "variables": { "nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]", "vnetName": "[parameters('virtualNetworkName')]", "vnetId": "[resourceId(resourceGroup().name,'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]", "subnetRef": "[concat(variables('vnetId'), '/subnets/', parameters('subnetName'))]" }, "resources": [ { "name": "[parameters('networkInterfaceName')]", "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2021-03-01", "location": "[parameters('location')]", "dependsOn": [ "[concat('Microsoft.Network/networkSecurityGroups/', parameters('networkSecurityGroupName'))]", "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", "[concat('Microsoft.Network/publicIpAddresses/', parameters('publicIpAddressName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "subnet": { "id": "[variables('subnetRef')]" }, "privateIPAllocationMethod": "Dynamic", "publicIpAddress": { "id": "[resourceId(resourceGroup().name, 'Microsoft.Network/publicIpAddresses', parameters('publicIpAddressName'))]", "properties": { "deleteOption": "[parameters('pipDeleteOption')]" } } } } ], "networkSecurityGroup": { "id": "[variables('nsgId')]" } } }, { "name": "[parameters('networkSecurityGroupName')]", "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2019-02-01", "location": "[parameters('location')]", "properties": { "securityRules": "[parameters('networkSecurityGroupRules')]" } }, { "name": "[parameters('virtualNetworkName')]", "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2021-01-01", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": "[parameters('addressPrefixes')]" }, "subnets": "[parameters('subnets')]" } }, { "name": "[parameters('publicIpAddressName')]", "type": "Microsoft.Network/publicIpAddresses", "apiVersion": "2020-08-01", "location": "[parameters('location')]", "properties": { "publicIpAllocationMethod": "[parameters('publicIpAddressType')]" }, "sku": { "name": "[parameters('publicIpAddressSku')]" } }, { "name": "[parameters('virtualMachineName')]", "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2022-03-01", "location": "[parameters('location')]", "dependsOn": [ "[concat('Microsoft.Network/networkInterfaces/', parameters('networkInterfaceName'))]" ], "properties": { "hardwareProfile": { "vmSize": "[parameters('virtualMachineSize')]" }, "storageProfile": { "osDisk": { "createOption": "fromImage", "managedDisk": { "storageAccountType": "[parameters('osDiskType')]" }, "deleteOption": "[parameters('osDiskDeleteOption')]" }, "imageReference": { "publisher": "canonical", "offer": "0001-com-ubuntu-server-focal", "sku": "20_04-lts-gen2", "version": "latest" } }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaceName'))]", "properties": { "deleteOption": "[parameters('nicDeleteOption')]" } } ] }, "osProfile": { "computerName": "[parameters('virtualMachineComputerName')]", "adminUsername": "[parameters('adminUsername')]", "linuxConfiguration": { "disablePasswordAuthentication": true, "ssh": { "publicKeys": [ { "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]", "keyData": "[parameters('adminPublicKey')]" } ] } } }, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true } } } } ], "outputs": { "adminUsername": { "type": "string", "value": "[parameters('adminUsername')]" } } }

      Ā 
      Log in to your created VM instance using SSH and install docker and docker-compose on it (Compose isĀ a tool for defining and running multi-container Docker applications With Compose, you use a YAML file to configure your application's services.) Here are the setup, I am leaving Docker setup on you, or just Ctrl + C, Ctrl + V the below code using aptitude to install docker and docker-compose.
      sudo apt-get update -y sudo apt-get upgrade -y # Install Docker from repository sudo apt install docker.io -y # Enable the docker daemon. systemctl start docker systemctl enable docker # Check whether docker is installed. docker --version ####################################### # Install docker-compose ####################################### D_COMP_URL="https://github.com/docker/compose/releases/download/v2.12.0/docker-compose-$(uname -s)-$(uname -m)" # Print the evironment variable set | grep D_COMP_URL sudo curl -SL $D_COMP_URL -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose docker-compose --version
      docker and docker-compose bootstrap script.
    4. Visit the template repository, and either fork/clone/use the template in your github account.
      1. šŸ›”ļø
        If you share your VPN with others it's highly recommended changing the admin password for the PiHole dashboard in theĀ docker-compose.ymlĀ file now.
        After you've installed all the pre-requisites you can run the below in bash shell.
        sudo docker-compose up -d
        šŸ¤“
        You can use my version or the repo version of the docker-compose script as a reference.
        nooobcoderā€™s docker-compose.yaml
        version: "3.5" services: openvpn: container_name: openvpn build: ./openvpn-docker ports: - 1194:1194/udp networks: vpn-net: ipv4_address: 172.20.0.3 environment: REQ_COUNTRY: US REQ_PROVINCE: California REQ_CITY: San Francisco REQ_ORG: Copyleft Certificate Co REQ_OU: My Organizational Unit REQ_CN: MyOpenVPN volumes: - ./openvpn/pki:/etc/openvpn/pki - ./openvpn/clients:/etc/openvpn/clients - ./openvpn/config:/etc/openvpn/config cap_add: - NET_ADMIN restart: unless-stopped pihole: container_name: pihole image: pihole/pihole:latest depends_on: - "openvpn" ports: - 80:80/tcp networks: vpn-net: ipv4_address: 172.20.0.2 environment: TZ: "Asia/Kolkata" WEBPASSWORD: "sUpEr.l0nG.p@$$w0rd" DNS1: 208.67.222.222 # OpenDNS DNS2: 208.67.220.220 ServerIP: 172.20.0.2 volumes: - ./pihole/pihole:/etc/pihole - ./pihole/dnsmasq.d:/etc/dnsmasq.d cap_add: - NET_ADMIN restart: unless-stopped networks: vpn-net: driver: bridge ipam: driver: default config: - subnet: 172.20.0.0/16
        notion image
        Ā 
        After this is done you'll find two new folders inside of this repository - theĀ /openvpnĀ folder will contain all of your certificates as well as an easy-rsa configuration file.Ā /piholeĀ will contain the content ofĀ /etc/piholeĀ andĀ /etc/dnsmasq.d
        If you want to migrate settings, or your query-database you can now copy it into the corresponding folder inĀ /pihole Ā šŸ˜Š The PiHole admin dashboard can only be reached through the vpn.

        GeneratingĀ .ovpnĀ files

        Before you generate any client certificate you must update the host inĀ client configuration. This file will be used as base-configuration for eachĀ .ovpnĀ file! You probably at least want to change the IP address to your public one.
        Ā 
        sudo docker exec \ openvpn bash \ /opt/app/bin/genclient.sh <name> <password?>
        Ā 
        You can find youĀ .ovpnĀ file underĀ /openvpn/clients/<name>.ovpn, make sure to change the remote ip-address / port / protocol.
        notion image

        RevokingĀ .ovpnĀ files

        sudo docker exec openvpn bash /opt/app/bin/rmclient.sh <name>
        Revoked certificates won't kill active connections, you'll have to restart the service if you want the user to immediately disconnect:
        sudo docker-compose restart openvpn

        FAQ & Recipes

        Launching multiple openvpn instances with different protocol/port config

        First copy theĀ openvpnĀ directory includingĀ openvpn/configĀ (copy just theĀ configĀ folder!), then add another service toĀ docker-compose.yml.
        Example assuming we want to name our second openvpn instanceĀ openvpn-tcp-443:
        mkdir openvpn-tcp-443 cp -r openvpn/config openvpn-tcp-443
        You can now make changes to our new config files inĀ openvpn-tcp-443/config. ChangeĀ protoĀ toĀ tcpĀ andĀ portĀ toĀ 443, you'll also need to comment outĀ explicit-exit-notify 1Ā as this is only compatible withĀ proto udpĀ (update bothĀ server.confĀ andĀ client.conf!).
        Now add our new service:
        # ... other services openvpn-tcp-443: container_name: openvpn-tcp-443 build: ./openvpn-docker ports: - 443:443/tcp volumes: - ./openvpn/pki:/etc/openvpn/pki # Keep the PKI - ./openvpn-tcp-443/clients:/etc/openvpn/clients - ./openvpn-tcp-443/config:/etc/openvpn/config # !! We're using our second configuraion cap_add: - NET_ADMIN restart: unless-stopped # ... other services
        Keep in mind that if you want to generate a client-config for that service we've just made you'll have to use the openvpn-tcp-443 container e.g.Ā sudo docker exec openvpn-tcp-443 bash /opt/app/bin/genclient.sh <name>.

        Troubleshooting

        Port 53 is already in use

        ERROR: for pihole Cannot start service pihole: driver failed programming external connectivity on endpoint pihole (...): Error starting userland proxy: listen tcp 0.0.0.0:53: bind: address already in use
        You'll need to disable the local dns-server, seeĀ thisĀ andĀ thisĀ askubuntu thread. You can stop, disable and mask theĀ systemd-resolvedĀ service using the following commands:
        sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolved sudo systemctl mask systemd-resolved

        Pi-hole Dashboard

        notion image
        notion image
        notion image
        Ā 
        Ā 
        Ā 
        Ā 
        Ā 

        VPN and Ad-blocking in action šŸ¤ššŸ›‘

        1. VPN Dashboard
        1. VPN Dashboard
        2. Ad Blocking in action
        2. Ad Blocking in action
        3. PiHole Dashboard killing the ads
        3. PiHole killing ads
        4. Proving VPN is in action using geolocation of ip-address
        4. Proving VPN is in action using geolocation of ip-address
        notion image
        notion image
        notion image
        notion image
        notion image
        notion image
        Ā