OK, I am going away for the long weekend and won't be near an internet connection for 5 days, but really wanted to post this for everyone that seemed really exicted
for this. It's a little rough and not proof read, or formatted as cleanly as I would like. ( I will do this when I am back. But it should
be accurate or close enough
Please let me know where I make no sense, spelt things wrong (guessing there are at least 1000 spelling mistakes), left words out or have just been generally confusing. Hopefully by this time next week it will be nice and clean and beautiful.
Also, feel free to leave questions, comments and troubleshoot queries - more than happy to help!
Until we meet again and with nothing else to say I present to you... Noob-2-Nerd Tutorial : OpenVPN in AWS with Dynamic DNS on a Headless Ubuntu Server Totally need a catchier name Introduction:
This tutorial aims to teach and prcatice Linux administration skills whilst making a functional private VPN server. We will be using and learning about Amazon Web Services (AWS)
, Ubuntu server 16.04
, Dynamic DNS
, and OpenVPN
This tutorial will cover:
- What is AWS and what are EC2 instances
- How to to configure a virtual headless Ubuntu 16.04 server on AWS's free hosting tier.
- How to open ports in AWS's virtual firewall
- How to install and configure OpenVPN server
- How to configure Dynamic DNS
- How to install the OpenVPN client
- Using vim and to manually edit the ovpn file to work on Ubuntu as well as other config files
- How to set aliases in bash
- How to configure your ssh preferences
- and a few other bits
- A very basic understanding of how a terminal works.
- A computer with an internet connection. Preferably Ubuntu or Debian based.
- An ssh client. (For Windows users see KiTTY - a fork of PuTTY but with more features and is still being updated.)
- A credit/debit card. Don't worry, you won't be charged (if you stick to the free tier), Amazon uses it to verify your identity.
- A phone for Amazon to verify you more.
I love Linux. It is my daily driver and for a living I am a Linux/Windows Sysadmin and desktop support. I do things my way and unless someone can give me a good reason to do it differently, I'm doing it the way I like it because what does it matter how I get from A to B? A lot of Linux purists, particually on the sysadmin side will critize your choice in text editor, choosing GUI over CLI, your desktop environment and anything else. Well, boohoo for them. I use vim, but if you like nano, go ahead and nano away. I like Budgie, but f you like Unity, use Unity. Do it how you like it.
In this tutorial, I will be demonstrating with vim text editor, but emacs or nano or whatever else will work just as fine. Some of the commands will be a bit different but I am sure you will figure it out.
If you are unsure about how to use any text editor and want to learn vim, keep reading this tutorial. If you prefer to start off with a more simple, user friendly text editor, do this nano tutorial first.
OK, lets get started.... AWS and EC2
AWS (or Amazon Web Services), is a cloud computing platform that offers more than just virtual machine hosting, today we are only going to touch on EC2 which is AWS's main service they provide - virtual machine hosting.
The free tier gives you more than enough to host a Linux server, however the biggest limitation is that you only get 750 hours free per month. This means you can only run 1 server for free. If people are interested, I can do another tutorial on lxc and lxd
which is akin to virtual instances we run in our Virtual Linux server, essentially extending the amount of servers we can use. Steps
Creating an EC2 Instance: Ubuntu 16.04
- Sign up for AWS here, confirm your identity with the phone call and credit card details.
- Pat yourself on the back, you have completed the first part!!
Amazon have made creating EC2 instances super easy. There is no need to go through installers. In the world of cloud computing, this is a waste of time. Instead, you will choose an AMI - or Amazon Machine Image
An AMI is essentially a vanilla template of a server that is ready to go in miliseconds of creating it. Just choose your variables such as RAM, processing power, storage space etc and you are good to go. It's amazing. Steps
- Log into AWS and navigate to your EC2 Dashboard.
- Under the create instance header, choose the blue button Launch Instance
- On the left hand side, check the box that says Free Tier Only (we don't want to spend money!!)
- Choose Ubuntu Server 16.04 LTS (HVM), SSD Volume Type - ami-965e6bf3 (Note: This may have changed, but at the time of writing this, this is the most up to date Ubunutu server available)
- Select the instance type: t2.micro (Free tier eligible)
- Select Next: Configure Instance Details
- Leave the defaults and choose Next: Configure Storage
- Set the storage amount. At the time of writing this, you get up to 30GB of SSD or Magnetic storage for free. It's recommend to have a minimum of 8 GB (default) and if you are only going to only run one EC2 instance, you may as well jack it up to 30GB).
- Click Next: Add Tags, click Next: Configure Security Groups
- We need to open some ports for OpenVPN to work properly. Configure the settings to look like this. Feel free to name the group anything you like other than 'default'
- Choose Review and Launch
- Choose Launch
- You will be prompted to create a new key pair. This consists of a public and private key that are used to securely connect to the new Ubuntu server. Download the private key and keep it somewhere safe. We need this file everytime we try to connect to the server via ssh.
Congratualtions, you have configured your first EC2 instace with a headless Ubuntu 16.04 server! It will take a little for AWS to configure everything, but it should become live within a minute or two.
You can optionally give it a name in the instance list. I've named my OpenVPN
. Connecting to the Ubuntu Server
Now that we have got the AWS stuff sorted we need to connect to our new server. If you are on Linux, (which, since this is /linux4noobs
you should be...) you can open up a terminal. If you are on Windows, go grab KiTTY. Steps for Linux
- I recommend moving the private key file to the ~/.ssh/ directory for safe keeping. To do so open up bash and enter the command.
mv path/to/the/keyfile.pem ~/.ssh/keyfile.pem Note: Just replace keyfile.pem with the filename that was downloaded.*
- Now you need to find the Public DNS name. You can get that from the list of EC2 instances. Mine is ec2-52-15-68-45.us-east-2.compute.amazonaws.com. Be careful though, this will likely change after your server is rebooted/powered off. I will discuss how to resolve this later with DDNS.
- Connect via ssh using the .pem file to identify yourself, ubuntu as the username and the public DNS as the server address:
ssh -i ~/.ssh/keyfile.pem [email protected] You will be prompted to add this server to the list of known hosts. Type yes and hit enter.
If you are prompted with: WARNING: UNPROTECTED PRIVATE KEY FILE! You need to set the permissions to the keyfile.pem file to only be accessible by yourself. To do so, type the below command and try and ssh in again:
chmod 700 ~/.ssh/keyfile.pem
Now we are in our server, first thing is first. We need to update it. Very easy, just enter the command:
sudo apt update && sudo apt upgrade -y
What does this do
sudo Run as super user
apt call the advanced package tool.
update tells apt to update the list of software that can be installed
&& joins to commands together
upgrade tells apt to upgrade the OS and any installed software
-y automatically accepts any prompts.
You will also likely get a purple screen stating Configuring grub-pc
, just choose keep the local version currently installed
Congratulations we now have an up-to-date Ubuntu server! Configuring the Hostname
By default the hostname for server should be the IP address which is probably in a 172. address range. You don't need to change the hostname, but if you want to go from Noob-to-Nerd it is good to practice. So, lets use vim to edit the hostname file. vim can be a bit intimidating at first, so feel free to use nano if you prefer but I will walk you through every key stroke.
All you need to know for now about vim is there are 2 (main) modes. Command mode and insert mode. Command mode allows you to type text commands that manipulate text (e.g. delete line, copy text, search, etc) while insert mode allows you to insert text.
So in the terminal type:
sudo vim /etc/hostname
This command opens the hostname file in vim with super user rights
. You will now see the hostname of the server. Mine is ip-172-31-17-240
. We want to remove this and add out own host name so we need to delete the current text with a command. To do this is easy, by default you are in command mode. To enter a command you simply just type. Now enter the command:
'dd' means delete line. After entering this command, the file should now be empty, ready for us to input text. To enter INSERT mode, enter the command:
Now you can type in the host name you want to name your Ubuntu Server. You can call it anything you like. I am naming mine OpenVPN
Once you enter your hostname it should look like this
To exit insert mode press the ESC
To save and exit, type the command:
Note: Because of historical reasons, some commands require a colon in front of them. The w means write (as in write the file), the q means quit vim and the ! means don't prompt for confirmation.
If you want to learn more about you can type :help vim-modes
You will also notice that there are a lot more modes than the 2 main ones we use)
You should be returned back to the terminal. To check if you saved the file correctly use the cat command:
The cat command will print out the contents of the file.
It is also a good idea to set the hosts file
to hold its new hostname. To do so we need to open the host file in vim, edit it and save and quit in almost the same way we did above. So type the following:
sudo vim /etc/hosts o 127.0.0.1 [HOSTNAME]
It should look similar to this
Now hit the ESC
key and type
Note: o inserts a new line below the cursor, O inserts a new line above the cursor
And dont forget to check it worked.
cat /etc/hosts Optional tools, shortcuts and settings
I like to add a few things to my Linux setups to make it a bit more flexible and homely. You don't have to do these steps, but it can be good for troubleshooting (when not if the time comes and because some linux commands should be accomplishible in less characters in my opinion.).
Since the free tier of AWS only offers dynamic internet facing IP addresses and not a static IP address
it can be necessary to find out the external IP address sometimes. The easy way for desktops is to open the browser and Google 'what is my ip', but we don't have a browser so we need to do it with a command, this is where curl
steps in... curl
is great. Its job is to simply transfer data to or from a server. It supports everything - SMB, FTP, HTTP, LDAP, POP3...the list goes on. In this case, we want it to connect to the website ifconfig.me and pull back the external IP address for our server.
Try it out with:
It will return just an external IP address.
Note: When you SSH into your server, you can also use [email protected][ExternalIPAddress]
There is one problem if you are lazy like me. That curl command is 16 characters just to get an IP address. That's too much typing. Lets make a shortcut command for this - they are called aliases.
There is a hidden file in the home directory called the .bashrc
file. This file customises your terminal envirnoment. One such customisation is setting an alias. You can take a looooooong complex command and rename it to anything you want.
A colleague of mine types hulksmash to run sudo init 6 (force restart a computer) thanks to aliases.
Now, we can edit the .bashrc
file like we did above with the hostname
file, but as I mentioned, I am lazy and opening vim is too much effort. I don't even want to open the file. Let's just append a line to the end of the .bashrc
file. We want to append the following line:
alias xip='curl ifconfig.me'
What does this do
alias tells bash that an alias to a command now exists
xip The name of the alias (you can call this anything you want. e.g. hulksmash)
curl ifconfig.me The actual command. (Make sure this is wrapped in single quotes)
We need to ask our server to say something back to us, but then redirect the output to to the .bashrc
To do so type:
echo "alias xip='curl ifconfig.me'" >> ~/.bashrc
What does this do
echo print a line to the terminal that is between "" (in this instance we are printing the line alias xip='curl ifconfig.me
>> send the echo to a file
~/.bashrc the file we are sending our echo to.
Now check it worked:
You should see the new alias in the file. Let's test it:
....and nothing. Why? Well we have not reloaded the modified .bashrc
file to be active. Lets do that:
We should now get our external IP address!
The other thing I like to add in is a speed test tool. But there is another problem; I'm not just lazy, I am also forgetful - and I can't remember the name of the speed test command line app that I use. We should search to see if it is in the database (aka the repository) of software we can install. Type:
apt search speedtest
We should get the output:
Sorting... Done Full Text Search... Done speedtest-cli/xenial 0.3.4-1 all Command line interface for testing internet bandwidth using speedtest.net
OK, it's called speedtest-cli
. Let's install it:
sudo apt install speedtest-cli -y
To use it is really simple. Just type:
The output will look like:
Retrieving speedtest.net configuration... Retrieving speedtest.net server list... Testing from Amazon.com (184.108.40.206)... Selecting best server based on latency... Hosted by RackSquared (Columbus, OH) [2.15 km]: 31.796 ms Testing download speed........................................ Download: 177.71 Mbit/s Testing upload speed.................................................. Upload: 100.99 Mbit/s
Not bad. I got 477Mbit/s down eariler, but beggards can't be choosers.
Anyway, lets continue with actually getting our OpenVPN server working. We are so close I can taste it! Installing OpenVPN Server
Now it's time for the fun stuff. Lets download and configure OpenVPN
Firstly we are going to use a tool called wget
, which just stands for web get
(i.e, download something from the web). The package we are downloading will be the script that sets up OpenVPN
(There is a manual way of downloading and installing OpenVPN
, but this is the easiest way. I can go into detail about the manual setup if people are interested.) We also want to put the scripts in a new directory. You can put it anywhere, but I like to keep everything organised under the /srv directory. So enter the commands:
sudo mkdir /srv/scripts/ cd /srv/scripts sudo wget https://git.io/vpn -O openvpn-install.sh What does this do
sudo run command with super user rights
mkdir Make a directory (the path to our directory is /srv/scripts)
wget Web Get. Download a file from the internet
-O Save the downloaded file as a new filename (in our case the file name is openvpn-install.sh).
Now lets grab our external IP address. You will need to remember this during the installation of OpenVPN
If you did the optional steps above, just enter:
If you skipped the optional steps enter:
Let's run the setup script:
Damn! That didn't work. But why? Well as far as our server is concerned, this script is just a text file. You can't execute a text file. You need to tell the server that you can, infact execute this file. To do this, we will use chmod
with the -x
changes permissions of files and directories, whilst the -x
switch tells chmod to make a file exicutable. So enter the command:
sudo chmod +x openvpn-install.sh
OK, now we can try and run the script again. But I am still feeling lazy, so instead of typing out all command again, we can all our history of commands and run the command again with far less characters typed. Just enter:
What does this do
! means run a previous command (you can use !! to run the last command again and insert more commands to it. If you forget to add sudo to the start of a long command, just run sudo !! and it will sudo the last command you executed).
-2 means run the second last command. -5 would ran the 5th last command.
You should be now greeted with:
Welcome to this quick OpenVPN "road warrior" installer I need to ask you a few questions before starting the setup You can leave the default options and just press enter if you are ok with them First I need to know the IPv4 address of the network interface you want OpenVPN listening to. IP address: 172.31.17.240
Keep the default IP address and hit ENTER
You will be asked if you want UDP
connections. This article
explains the different transmission types. We will stick with UDP, so enter 1
and hit ENTER
Now you will prompted to choose a port that OpenVPN will operate on. Remember back in the Creating an EC2 Instance: Ubuntu 16.04
, we opened up some ports
for our server to talk on? Well OpenVPN talks on 1194. You can think of ports as lanes on a freeway that only one type of traffic can go at a time: the fast lane, slow lane, commuter lane, bus lane. But instead of cars we have programs. OpenVPN only can go down lane (or port) 1194, SSH can only go down lane 22 etc. We can tell these programs they can go down other ports, but we don't have too. Keep it the default of 1194 if that is the port that was opened before, or set it to your custom port.
Note: Why do we change ports if we dont have to? Well, sometimes people scan to find open ports that they can attack. Because there are so many ports, these people usually only scan for the default ones. If we change our port from the default to something obscure like changing OpenVPN to talk on port 1989 it is less likely someone will find it. This is called security through obscurity.
You will be asked what you want to set your DNS
to. Google DNS works fine, OpenDNS has some extra functionality
like malware filtering and other bits and peices. I am going to stick with Google.
Now you will be asked about the client certificate. This is a file that authenticates the person connecting to the VPN. You can name this what you like and you can have more than just one.
If you do want more than one, re-run the script and you will only be asked for the name for the client certificate.
I am just going to stick with the default client
Now press any key
The script will now go and download OpenVPN
as well as easy-rsa
, then configure OpenVPN and generate an RSA key
Now, remember how we asked about the external IP address? We need to enter it now. If you forgot it, or didn't write it down. You can get it from the instance list in the AWS control panel.
Technically, that's it. You have a fully functional VPN server, but it is of no use yet. You need to copy the client configuration file. By default it will be found in:
In my case, my file is found in:
We will need to use a function secure copy shell
) to get this down to our local machine. scp
is based on ssh
and is very easy to use.
If your local machine is running linux, we will make a new hidden folder called .openvpn
in our home directory (~
First open a new terminal, one that is for your local machine.
Enter the following command to make a new hidden directory:
Note: a . before a directory name makes it hidden
Now let's copy down the client configuration file from our server.
Still in the terminal for our local machine, enter the command:
scp -i ~/.ssh/keyfile.pem [email protected][YOURSERVERSPUBLICIPADDRESS]:/home/ubuntu/[YOURCLIENTNAME].ovpn ~/.openvpn/[YOURCLIENTNAME].ovpn
Remember that ~/.ssh/keyfile.pem is where you placed the key to access your AWS Ubuntu server on your local computer.
What does this do scp secure copy files from a remote server
-i tells scp to use the key file to authenicate the connection to the server
ubuntu The username to use.
@[YOURSERVERSPUBLICIPADDRESS] The internet facing IP address of our server
:/home/ubuntu/[YOURCLIENTNAME].ovpn where our file is found on the remote server
~/.openvpn/[YOURCLIENTNAME].ovpn Where we are saving our file to.
The output should like something like:
client.ovpn 100% 8219 8.0KB/s 00:00
Congratulations! You should now have the OpenVPN client configuration file. Remember where this file is, we will use it later when setting up the OpenVPN client. Dynamic DNS with NoIP
One issue with AWS is that on the free tier you only get a dynamic IP address. Meaning you only get to borrow and internet address for the time your server is on for. Each time you reboot your server, you will get a new IP address, so after each reboot every time you want to connect to your VPN client you will need to log on to the AWS dashboard, look at the instances, get the IP address, update the client.ovpn file and then connect. In my book, that is waaay to much work. With Dynamic DNS we can tell it to look at an address that automatically gets translated into an IP address. Example:
Without Dynamic DNS
My server is on 192.168.0.1 (Yes, this is a private IP address, but it's easy for arguement sake to use this address).
My client.ovpn file is set to point to 192.168.0.1
I reboot my server. Its IP is now 192.168.0.55
I try to connect to my VPN but 192.168.0.1 is not there anymore! damn!
With Dynamic DNS:
My server is on 192.168.0.1
My client.ovpn file is set to point to myvpnserver.com
myvpnserver.com currently resolves to 192.168.0.1
I reboot my server
The server address is now 192.168.0.55
A small program from No-IP running on my server updates the Dynamic DNS that the new server IP is 192.168.0.55 and that myvpnserver.com should resolve to this new IP.
I try and connect to my vpn with myvpnserver.com and BAM! It still works!
So, let's set this up!
I really like No-IP
, but there are other providers out there. DynDNS is another company, but they charge now I think. The only draw back with No-IP is they require you to confirm you still want to use your Dynamic DNS every 30 days. Don't worry, they will email you when your time is close to up!
So, go sign up for a No-IP account
Once signed up, create a host name. To do so:
- Click on Dynamic DNS on the left side menu
- Click Create Hostname
- Enter the hostname you want. I am going to use openvpntutorial, but you can call it anything you want.
- Choose the domain name. I use ddns.net, but again you can use anything you want.
- Set the record type to DNS Host (A)
- Enter the public ip address of your server under the IPv4 Address
- Click Create Hostname
So we are still missing the Dynamic
part of Dynamic DNS
. To make it auto update with the new IP, we need to install the No-IP client. Go back to the terminal that is connected to your ubnutu server and enter the commands:
cd /uslocal/src/ sudo wget http://www.no-ip.com/client/linux/noip-duc-linux.tar.gz sudo tar xf noip-duc-linux.tar.gz cd noip-2.1.9-1/ sudo make install
What does this do
cd change directory
wget web get the no-ip client
tar means invoke the tar program which is used to compress and decompress tar files (similar to zip files).
x flags tar to extract the contents
f flag signals to tar that what is following is the filename of the tar file.
cd noip-2.1.9-1/ means change directory to the directory that was decompressed by *tar
make install run make and build No-IP with the instructions in the install file.
Damn! It failed! Why? make
is not installed. We will need to install this through apt
to get this working. We are also missing a dependancy gcc
. Let's get these installed. Enter the command:
sudo apt install make gcc -y
Now rerun our make
command...do it the lazy way.
You will be prompted to choose the interface that talks to the internet with. In our case it is eth0
so enter 0
and hit ENTER
You will then be asked to enter your username/email address and password used for your No-IP account.
After entering your credentials, you will likely be defaulted to using the dynamic hostname you just created in No-IP. If you have more than one hostname created, you will be prompted to choose.
You will be prompted for an update interval. The default is 30 minutes. I recommend setting it to 5 minutes.
Next you will be prompted to run something at startup. Just hit ENTER
If all was successful you should see:
New configuration file '/tmp/no-ip2.conf' created. mv /tmp/no-ip2.conf /uslocal/etc/no-ip2.conf
Congratulations! We now have Dynamic DNS setup and working. Configuring the DNS Client - Linux
I am only going to go through the configuraton for Linux since this is /linux4noobs
are quite a bit more straight forward than the Linux.
First up, we should edit our client ovpn file because at the moment, it is not using our No-IP Dynamic DNS
So, open the file in vim:
Find the line remote [IPADDRESS] [PORT NUMBER]
e.g. remote 220.127.116.11 1194
Put your cursor over the line and remove it then add a new blank line with:
Now enter INSERT
Type in the following:
remote [YOUR DYNAMIC DNS HOSTNAME] [PORT NUMBER]
As an example, mine was:
remote openvpntutorial.ddns.net 1194
Save the file with the following commands: ESC
Check it saved right:
Now we call apt
to install the OpenVPN client:
sudo apt install openvpn
It should have the changes we made to the remote server with our Dynamic DNS
name and the OpenVPN
Next we need to open our VPN connection with the client ovpn file that we used scp
to copy down to our computer earlier. Make sure to always sudo
this command, otherwise it won't connect. Enter the command:
sudo openvpn --config ~/.openvpn/[YOURCLIENTNAME].ovpn
In my case it was:
sudo openvpn --config ~/.openvpn/client.ovpn
If all went well, after a bunch of output lines of text the last one you should get is:
Initialization Sequence Completed
And thats it. We are on our VPN.
To confirm check your external IP on your server and on your local machine. If they match, you are golden!! Optional for the Lazy
The last thing I would add to this, to make life a little easier again is to set an alias in your .bashrc
file to more easily connect to the vpn. You can find the steps above and don't forget to reload your bash config once you set the alias!.
Also you can make your ssh connection a lot easier. Open up the ssh config file in vim:
Enter the following settings at the bottom of the file.
Host openvpn Hostname [YOUR DYNAMIC DNS HOSTNAME] User ubuntu IdentityFile ~/.ssh/keyfile.pem
Save the file and now you can connect with:
ssh openvpn Troubleshooting
One thing I have come across is sometimes (and aparently only on Ubuntu) the VPN config fails to work and you need to add the following lines at the bottom of the ovpn file:
up /etc/openvpn/update-resolv-conf down /etc/openvpn/update-resolv-conf Quick Edit:
I'm back from the cabin in the woods and will be answering questions/discussion points as well as fixing up the tutorial shortly! But wanted to point out what NickUnrelatedToPost
mentioned in a comment. Thank you for that Nick!
Now, noobs, take note!
What this VPN does for you:
It lets you get around geoblocking.
It prevents your employer or ISP from spying on you.
It may get you around internet filters in your country (eg. twitter bans).
What VPN does not do:
Protect your identity from the sites you go to. (As AWS has your identity connected to the IP address of the VPN-server. And there is no one else using this vpn)
Protect you from law enforcement.
Protect you from copyright enforcement (it does not allow you to torrent without fear of prosecution, if torrenting is prohibited in you country)
It does not stop government agencies (especially 5-Eyes states) from spying on you.
This is a convenience and learn-to-do-it VPN. This is not a I-can-do-evil-things VPN.