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.
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.
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
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.
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
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 .oo. | | . o.E | | + . o | | . = = . | | = S = . | | o + = + | | . o + o . | | . o | | | +-----------------+The key's randomart image is: +--[ RSA 2048]----+ |
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 email@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:
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:
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.
Now we need a server installed on our droplet to handle incoming HTTP requests and serve our static files.
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:
- Speed: Nginx is super fast and efficient.
- Security: Nginx can be secured easily with an SSL certificate (We’ll do this later on in the tutorial).
- 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).
- 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).
- 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.
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:
To check the status of ufw run:
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:
Add the required DNS records
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:
- We can compress the files on our local machine and copy them to our server using ssh.
- 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).
- 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:
<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)
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).
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.