Skip to content

Instantly share code, notes, and snippets.

@emrekgn
Last active June 12, 2026 16:44
Show Gist options
  • Select an option

  • Save emrekgn/1a77d8f6a0c62aab022fc23201d544b3 to your computer and use it in GitHub Desktop.

Select an option

Save emrekgn/1a77d8f6a0c62aab022fc23201d544b3 to your computer and use it in GitHub Desktop.
How to make your own VPN

How to make your own VPN server

This guide walks through the full workflow for setting up your own VPN server using Linode.


1. Prerequisites

  1. A Linode account

2. Creating a VPS

  1. Navigate to the "Linodes" (i.e. instance) page in your Linode dashboard.
  2. Click the "Create" button and; 2.1. Choose a "Distribution" (e.g. this guide assumes it's Ubuntu) 2.2. a "Region" where you want your Linode to run. 2.3. Choose the cheapest "Linode Plan" (i.e. Nanode 1GB RAM plan -> $6 monthly at the time of writing this guide) is sufficient for most case and you can change this setting later if you want. 2.4. Set a strong "Root Password". You don't need to upload your SSH key at this step. 2.5. Don't forget to check "Private IP" checkbox to assign a public private IP address. 2.6. Click the "Create" button.

3. Accessing the Server & Initial Setup

  1. Once our server is up & running, we can copy the IP address from the Linode server control panel and; 1.1. Type in the terminal:
ssh root@<server-ip-address>

1.2 Enter the root password that you specified in the previous section. 1.3 Once you are in, we should update our server:

apt-get update && apt-get upgrade

1.4 You may also want to install your preferred text editor:

apt install vim
  1. Create a new user account that isn't root to avoid exposing root login on an SSH server:
useradd -G sudo -m <your-user> -s /bin/bash

2.1 Set a password for that user by typing:

passwd <your-user>

2.2 Now we can copy the public SSH key to the server. This'd allow us to SSH without password. Open another terminal and type:

ssh-copy-id <your-user>@<server-ip-address>

You'll be prompted to enter your password here. Don't close the other window yet.

FAQ: I don't have an SSH key pair on my local machine. What do I do: Just generate a new pair by typing: ssh-keygen -t rsa -b 4096

4. Hardening SSH

  1. Edit the SSH daemon config:
nvim /etc/ssh/sshd_config

1.1. Change the default port (reduces noise from automated scanners):

# Port 22
Port 69

1.2. Disable password authentication:

PasswordAuthentication no

1.3. Disable root login:

PermitRootLogin no
  1. Restart sshd:
systemctl restart sshd
  1. Without closing the current window, verify key-based login works from your local machine:
ssh -i ~/.ssh/id_rsa <your-user>@<server-ip-address> -p 69
  1. Verify password login is rejected:
ssh <your-user>@<server-ip-address> -p 69
# Should return: Permission denied

5. Creating a Server Alias

  1. On your local machine, create/edit ~/.ssh/config:
nvim ~/.ssh/config
  1. Add an entry:
Host <alias>
    User <your-user>
    Port 69
    IdentityFile ~/.ssh/id_rsa
    HostName <server-ip-address>
  1. Now you can log in with just:
ssh <alias>

6. Setting up OpenVPN

  1. Log in to your server and install wget:
sudo apt install wget
  1. Download the openvpn-install road warrior script and review it before running:
sudo bash openvpn-install.sh

2.1. When asked for a port, prefer 443 over the default 1194 — it's less likely to be blocked on restrictive networks. 2.2. Choose a DNS resolver (e.g. 1.1.1.1). 2.3. Choose a client name. The script will produce a .ovpn config file in /root/. 3. Move the config file to your user's home directory:

sudo mv /root/<client-name>.ovpn ~
sudo chown <your-user> <client-name>.ovpn
  1. Disable VPN logs by editing the server config:
sudo nvim /etc/openvpn/server/server.conf

Change verb 3 to verb 0, then restart the service:

systemctl restart openvpn-server@server.service

7. Downloading the Config File

On your local machine:

sftp <alias>
get <client-name>.ovpn
exit

Import the .ovpn file into your VPN client (Tunnelblick on Mac, OpenVPN Connect on Windows, NetworkManager on Linux).


Optional: Multi-Factor Authentication

  1. Install the PAM module:
sudo apt install libpam-google-authenticator
  1. Run the setup wizard (answer yes to all except "multiple users" and "30-second tokens"):
google-authenticator

Save the recovery codes. Scan the QR code with an OTP app (e.g. AndOTP, OTP Auth). 3. Edit /etc/pam.d/sshd: comment out @include common-auth and append:

auth required pam_google_authenticator.so
  1. Edit /etc/ssh/sshd_config:
ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey,password publickey,keyboard-interactive
  1. Restart sshd and verify login in a separate terminal before closing your session.

Optional: Unattended Upgrades

  1. Install packages:
sudo apt install unattended-upgrades apt-listchanges bsd-mailx
  1. Enable security updates:
sudo dpkg-reconfigure -plow unattended-upgrades
  1. Edit /etc/apt/apt.conf.d/50unattended-upgrades and set:
Unattended-Upgrade::Mail "your@email.com";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "05:00";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
  1. Verify with a dry run:
sudo unattended-upgrades --dry-run

Optional: Mosh

Install on both local and remote machines for connection persistence across network changes:

sudo apt install mosh

Use mosh <alias> as a drop-in replacement for ssh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment