Hosting static content on a linux VPS server

Posted on Tue Feb 19 2019

An in-depth step by step tutorial on setting up an nginx server using Ubuntu on a Digital Ocean VPS and serve static content securely.

Hosting static content on a linux VPS server

What is a VPS?

VPS stands for Virtual Private Server. As the name says, its a virtual machine that is running its own copy of an operating system and gives you superuser privileges so you can install any software you need.

There are many hosting services that sell these servers but for this article, we’re going to use Digital Ocean to create our VPS, install and configure Nginx and secure our server with a firewall and an SSL certificate.

If you don’t have an account on Digital Ocean click this link to get free 100$ credits to get you started.

Creating your first droplet

In Digital Ocean a droplet is an SSD based virtual machine that can be scaled up and down, monitored, secured and has many more features. We’re going to use this droplet as our VPS.

To create your first droplet head over to your Digital Ocean dashboard and create a new project, give it a name and select it. After selecting your project click the green create button in the top right corner and select droplets in the dropdown menu.

Now you need to specify the configurations for your new droplet.

First, you need to select an image, I’m going to select Ubuntu since I’m more comfortable using it over other Linux distros, but feel free to choose whatever distro you feel comfortable using (CentOS is another great option).

Second, you have to choose a droplet size. For the sake of this tutorial, I’m going to choose the smallest size, which is 5$ a month and have 1CPU and 1GB of RAM. In a production application, this might not be enough to handle a large number of users but you can scale it up whenever you want and that’s the beauty of using droplets.

Now you need to add your SSH key to be able to access this droplet from your computer. This step is important to make sure your droplet is only accessible by your machine.

Generating SSH keys

If you’re on windows you need to Follow (this tutorial to generate SSH keys)

If you’re on Mac or Linux open your terminal and do the following:

First, check if you already have an SSH key by going into ~/.ssh directory

cd ~/.ssh

If the directory does not exist this means you don’t have any SSH key and you should generate a new one but if it does exist check if there is a key by listing the files in this directory.

ls

If the directory exists but empty this also means you don’t have any SSH key on your machine.

To generate an SSH key you need to run the following command

ssh-keygen

Once you run this command you will get a couple of questions

Enter file in which to save the key (~/.ssh/id_rsa):

You can press enter to save in the default location which is ~/.ssh or user-home-directory/.ssh

You will also be asked to enter a passphrase

Enter passphrase (empty for no passphrase):

You can leave this empty, but it’s recommended to set up one for better security (But you have to type this passphrase every time you want to use this key).

The output should be something similar to this

Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ~/.ssh/id_rsa.
Your public key has been saved in ~/.ssh/id_rsa.pub.
The key fingerprint is:
4a:dd:0a:c6:35:4e:3f:ed:27:38:8c:74:44:4d:93:67 demo@a
The key's randomart image is:
+--[ RSA 2048]----+
|          .oo.   |
|         .  o.E  |
|        + .  o   |
|     . = = .     |
|      = S = .    |
|     o + = +     |
|      . o + o .  |
|           . o   |
|                 |
+-----------------+

So now you have an SSH key installed on your machine that you can use to connect to your droplet. But you still need to get this key, so in your terminal run the following.

cd ~/.ssh
cat id_rsa.pub

This will print your public ssh key to your terminal. It will look something similar to this:

ssh-rsa some random text username@example.com

Copy the whole key and go back to Digital Ocean where you are setting up the droplet and click on New SSH Key.

Paste the key in SSH key content, give it a name to identify it later and click Add SSH Key.

For the rest of the settings, you can leave the default, but you might consider changing the region to somewhere near to you or your users.

Finally, click on the create button at the bottom of the page and wait till your droplet finish initializing.

Testing and Updating your droplet.

Now that your droplet is up and running we need to ssh into it and update everything.

To do so we first need the IP address of the droplet to be able to ssh into it. In your Digital Ocean dashboard select your project and under droplets section you will find your droplet and next to its name you will also find it’s IP address. Copy this IP address, head back to your terminal and type the following command:

ssh root@your-droplet-ip-address

Replace your-droplet-ip-address with the IP address you copied.

If you followed the steps correctly you should now be logged in to your server and you should see something like this in your terminal:

root@droplet-name:~#

Now let’s make sure everything is up to date by running the following commands.

apt update
apt upgrade

The first command will check for updates and the second one will update all these packages to the latest version.

Installing Nginx

Now we need a server installed on our droplet to handle incoming HTTP requests and serve our static files.

Why Nginx

You might be asking why I chose to use Nginx as my server, I might have used apache or nodejs and many others. But I chose Nginx for the following reasons:

  1. Speed: Nginx is super fast and efficient.
  2. Security: Nginx can be secured easily with an SSL certificate (We’ll do this later on in the tutorial).
  3. Reverse proxy: Nginx can be used as a reverse proxy to proxy incoming requests to other servers running locally (I’ll use this is a future article to send requests to a nodejs server running on this droplet).
  4. Load Balancing: nginx can be used as a load balancer (I’ll also use this in a future article where I will be running multiple instances of a nodejs API on this droplet).
  5. And many more features we can make use of later.

Installation and Configuration

I’m going to show you how to install Nginx on Ubuntu, if you’re not using Ubuntu you can follow (the official docs here).

To install Nginx on a droplet running Ubuntu run the following commands:

apt update
apt install nginx

Wait for the install to finish, and when it does we need to check if Nginx is running or not. To manage Nginx and check it’s status we need to use Systemctl which is a "systemd" utility responsible for Controlling the "systemd" system and service manager. With Systemctl we can enable, disable, stop, start, restart and check Nginx status.

Run the following command to check if nginx is active:

systemctl status nginx

Multiple lines will be printed to the terminal and one of them looks like this:

Active: active (running) since Sun 2019-02-17 16:09:13UTC; 21h ago

This means that Nginx is running properly.

If you don’t see active (running) then you should start it manually.

Here’s a list of useful systemctl commands.

# start nginx
systemctl start nginx
# stop nginx
systemctl stop nginx
# restart nginx
systemctl restart nginx
# reload nginx (If supported)
systemctl reload nginx
# get nginx status
systemctl status nginx
# Start nginx on boot
systemctl enable nginx
# Stop nginx on boot
systemctl disable nginx

For a full list of systemctl commands checkout SysVinit to Systemd Cheatsheet - Fedora Project Wiki

Now we need to enable Nginx in order for it to start whenever the server is rebooted.

systemctl enable nginx

Now open your browser and navigate to the IP address of your droplet. If you followed all the steps correctly, you should see a welcome page by Nginx, this indicated that Nginx is running and serving a stock webpage that comes with Nginx’s installation.

If the webpage didn't load check your firewall status as stated below.

Firewall setup

The default firewall configuration tool for Ubuntu is ufw. Developed to ease iptables firewall configuration, ufw provides a user-friendly way to create an IPv4 or IPv6 host-based firewall. By default UFW is disabled.

List the application configurations that ufw knows how to work with by typing:

ufw app list

You should get a listing of the application profiles:

Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

Nginx has 3 profiles:

  • Full: opens both ports 80 (for HTTP traffic) and 443 (for https traffic)
  • HTTP: opens port 80 only
  • HTTP: opens port 443 only

Since we are going to configure SSL and enable HTTPS we need both port 80 and 443 enabled. Also since we're connecting to our droplet using ssh we need to also allow OpenSSH.

You can enable those by typing:

ufw allow 'Nginx HTTP'
ufw allow 'OpenSSH'

Now you need to enable ufw by typing:

ufw enable

To check the status of ufw run:

ufw status

For more info on ufw commands check the official Ubuntu community help wiki page

Adding a domain

Now you have a web server running but you can only access it with an IP address. You don’t want that in a production server, you want people to type your domain name and get to your page. And that’s what we’re going to do right now.

If you don’t own a domain name, you can get one from Name Cheap

If you don’t want to set up a domain you can skip this section, but you have to know that you need a domain to set up an SSL certificate and secure your website.

Configuring domain name servers

Since your server is on Digital Ocean You want your DNS to be managed by Digital Ocean. To do so head up to your domain name registrar, find your domain and click on manage DNS (This might be different on each domain name registrar, I use Name Cheap ).

In your manage DNS window look for name servers, change them from default to custom name servers and add the following 3 name servers:

  • ns1.digitalocean.com
  • ns2.digitalocean.com
  • ns3.digitalocean.com

Add the required DNS records

Now that your name server is pointing to Digital Ocean head over to your Digital Ocean dashboard, navigate to Networking tab enter your domain name, select your project and click add a domain.

After adding your domain select it and add two new records:

First, add an A record with the hostname @ that redirects to your droplets IP address.

Second Add another A record with the hostname www that also redirects to your droplets IP address.

After adding these two records you should be able to access your server from your domain name instead of IP address.

If you are unable to access your server from your domain name immediately you have to wait for a couple of minutes and try again.

Deploying static content to Nginx

So until now, we have a server and domain name configured properly and running, but it’s still only serving a stock web page that came with Nginx installation. So we need to replace that page with our website code.

Nginx store the default HTML files in ~/var/www/html/ so we need to somehow send our website files to our server and place the code in this directory.

There are multiple ways to do this:

  1. We can compress the files on our local machine and copy them to our server using ssh.
  2. We can create a git repository, commit our code to it, clone it on our server and we can pull any changes that we push to our repository later (We need to change Nginx root folder to the new folder we cloned).
  3. We can write a shell script that does any of the above methods on our local machine and automate deployments (for advanced users).

For the sake of this tutorial, we're going to compress the files and send them using our ssh connection.

To do so let's create a new file on our local machine called index.html, open it in a text editor and add the following code to it:

<!DOCTYPE html>
<html>
    <head>
        <title>My Website</title>
    </head>
    <body>
        <h1>Hello World!</h1>
        <p>From nginx</p>
    </body>
</html>

Save the file and compress it. Now copy it to your server using the following command:

# This command should be run on your local machine, not on the ssh terminal
scp /local/directory/to/compressed/file root@droplet_ip:/var/www/html/

This command will copy the file to /var/www/html/ directory on your server.

Now ssh back into your server and run the following commands:

# navigate to the directory where we copied our file
cd /var/www/html/
# list files in directory
ls

The output should be 2 files (The default Nginx HTML file and the file you just copied).

Delete the default Nginx HTML file (In my case it was named index.nginx-debian.html)

rm index.nginx-debian.html

Now you need to extract the contents of the compressed files.

# For zip files you need to install unzip
apt install unzip
unzip file_name.zip
# For tar files
tar xvf file_name.tar

Go to your browser and navigate to your domain name (Or droplet IP if you haven't set up a domain) and you should see your page.

Adding an SSL to secure your website

This step requires that you have followed the steps above to add a domain name to your server. So, if you haven't, you can't secure your website and serve it over https.

We're going to use let's encrypt to obtain a free SSL certificate and tell Nginx to use this certificate.

First, you need to install certbot on your droplet and to do so you should run the following commands (These commands are specific to Ubuntu, for installation on other distros follow the instructions on certbot's official website).

apt update
apt install software-properties-common
add-apt-repository universe
add-apt-repository ppa:certbot/certbot
apt update
apt install certbot python-certbot-nginx 

Now to create the certificate run the following commands

sudo certbot --nginx -w /var/www/html -d your_domain.com -d www.your_domain.com

You will be asked a couple of questions after running this script agree to everything.

You will also be asked if you want to redirect HTTP traffic to HTTPS, it will look something like this:

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/default

Enter 2 and hit enter to redirect all traffic to HTTPS

Lastly, you will get a message like this:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2019-05-20. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Now go to your browser and navigate to https://your_domain.com and you should see a green lock on the URL bar.

Congrats you now have a secure website running on a Linux VPS on Digital Ocean.

It's a good practice to back up what you did so far. To do so we need a copy of these 2 directories /etc/letsencrypt/ and /etc/nginx/sites-available/

Run the following command on your ssh terminal

# compress both directories
tar czf letsencrypt.tar.gz /etc/letsencrypt/
tar czf nginx.tar.gz /etc/nginx/

Run the following commands on your local terminal

# copy the compressed files to local machine
scp root@droplet_ip:letsencrypt.tar.gz ~/Desktop/letsencrypt.tar.gz
scp root@droplet_ip:nginx.tar.gz ~/Desktop/nginx.tar.gz

This will copy the backed up files to your desktop. You can now move them somewhere safe. (If you're on windows change ~/Desktop/ to where you want to save the files).

What's next

Now that we have a server static files we need an API and a web-app to display dynamic content.

In future articles we're going to deploy a nodejs server and a small web-app using docker to serve as our API, we're going to run multiple instances of it and we're going to use Nginx load balancer.

Thank you for reading and if you have any questions or you have found any issues in this article don't hesitate to contact me.

If you feel that you have learned anything from this article, don't forget to share it and help other people learn.