This guide walks through the full workflow for setting up your own VPN server using Linode.
- Navigate to the "Linodes" (i.e. instance) page in your Linode dashboard.
- 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.
- 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
- 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
- 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
- Restart sshd:
systemctl restart sshd
- 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
- Verify password login is rejected:
ssh <your-user>@<server-ip-address> -p 69
# Should return: Permission denied
- On your local machine, create/edit
~/.ssh/config:
nvim ~/.ssh/config
- Add an entry:
Host <alias>
User <your-user>
Port 69
IdentityFile ~/.ssh/id_rsa
HostName <server-ip-address>
- Now you can log in with just:
ssh <alias>
- Log in to your server and install wget:
sudo apt install wget
- 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
- 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
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).
- Install the PAM module:
sudo apt install libpam-google-authenticator
- 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
- Edit
/etc/ssh/sshd_config:
ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey,password publickey,keyboard-interactive
- Restart sshd and verify login in a separate terminal before closing your session.
- Install packages:
sudo apt install unattended-upgrades apt-listchanges bsd-mailx
- Enable security updates:
sudo dpkg-reconfigure -plow unattended-upgrades
- Edit
/etc/apt/apt.conf.d/50unattended-upgradesand 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";
- Verify with a dry run:
sudo unattended-upgrades --dry-run
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.