The other day, I decided to set up a simple VPS server. I've never done this before. When I was working at Google, things sort of work out of the box.

So for the first time, I was shopping around, looking for a simple first server to start hacking on. I'm pretty familiar with Linux, so that's already one less hurdle.

Choosing a provider #

Hosting. It seems like there are a million companies who offer it. From basic .php servers, to full-blown, Xeon boxes. The providers are also household names from Amazon with their Amazon Web Services (AWS), or Google with Google Cloud Platform (GCP), to GoDaddy or Namecheap. As a first timer though, I didn't want to roll with a managed service, with layers of abstraction. Some of these providers offered pretty nice introduction rates, with AWS and GCP having generous Free Tier offerings.

AWS #

The AWS Free Tier covers a ton of Amazon products, but as a newcomer, it's quite overwhelming. All their products have cryptic names, and all I really want is a Linux box! I might come back to AWS later if my needs evolve, but right now, it's too complicated.

GCP #

I feel like GCP is the same problem here. They offer GCP Always Free, which lists a bunch of products with various free quotas, but right now I don't even know what my usage is going to look like, so committing to this seems risky, especially because most of their products require Billing information. I'm actually pretty familiar with AppEngine, but this time, I wanted to be my own sysadmin.

OVH #

Having done some coding in the past in Belgium, My provider in the past was OVH, a French hosting provider with global operations. My previous plan with them is the cheapest 1 euro a month, with a simple PhpMyAdmin, an FTP-able server where I dumped .php files and it just worked. I had no versioning, I was usually editing files directly on the FTP server. Pretty bad, but that's how I did it over 10 years ago. Their VPS offerings seem pretty bare-bones, unlimited bandwidth; some some of Ryanair of hosting.

DigitalOcean #

It seems that the easy go-to host provider is DIgitalOcean nowadays, and it definitely seems appealing. I think I'll probably check it out later, OVH is a couple of bucks cheaper, but come at the cost of bandwidth, but because the point of this expercice is really just to practice, I thought I'd go with the cheap option.

Verdict #

In the end, I picked the VPS SSD 1 option from OVH, the cheapest, most barebone offering. It does one thing decently well, 100mbps isn't crazy but it'll get the job done.

Initial Setup #

Root login #

Once the payment was processed, something like 24 hours after the purchase, I finally got an email from OVH with my root password. Ubuntu 16.04 LTS.

Let's connect to the machine, using either the IP address of a URL if your provider gives you one. OVH gave me a vpsxxxx.ovh.net URL.

ssh root@vpsxxxx.ovh.net

First things to do is to make sure the system is up-to-date. Sure enough, a couple of packages needed to be updated, but with Ubuntu distro, it seems there's always something that needs updating.

# Fetch the list of packages and install the updates.

sudo apt update

# (Optional): To see the packages.

apt list --upgradable

sudo apt upgrade

# Get the system booted with all its fresh new greatness.

sudo reboot

Working on a server with the root user, is never a good idea, you can break stuff, you can be compromised. The better option is to create a new user, and give that user sudo access.

adduser \$username # Your new user's name here.

Fill in the information about the user, then grant them sudo access. You can give a unique user sudo access, by hard-coding their username in your /etc/sudoers file. This can seem convenient initially, but if you ever decide to delete the user, and further down the line you create a new user with the same username, the new user will inherit the sudo privileges from the previous user.
Ubuntu maintains a sudo group, and it's safer to add your new user to that group. That way, when the user is deleted, their membership to the sudo group is also revoked.

usermod -aG sudo \$username # -aG appends the given user to the given group.

Once this is done, the best is to log out of your ssh session and switch to using the new user.

exit

ssh username@vpsxxxx.ovh.net

Setting up a basic firewall #

Now that we have a safer user set up, it's time to define some basic firewall rules to prevent unauthorized access to our machine through some random ports. Ubuntu 16.04 has the UFW firewall, which allows super simple setup of certain services that integrate with it. Services register their firewall profile with UFW and you can easily enable/disable services.

The first step, before enabling UFW, is to allow SSH connections, otherwise you'll be locked out of you machine.


# Allow SSH connections

sudo ufw allow OpenSSH

# Enforce the Firewall

sudo ufw enable

From now on, your Firewall is enforced, and SSH is the only connection method. As we add more services, we'll have to enable them with UFW to allow traffic in.

Securing the box #

Installing NGINX #

As always with a new session, update your package index, then install the NGINX package.

sudo apt update
sudo apt install nginx

Once installed, we need to update our UFW settings to allow NGINX connections. NGINX registers itself with UFW, so activating it is straightforward.

For firewall settings it's important to try and enforce the most restrictive settings possible, to limit your exposure to vulnerabilities.

NGINX registers three profiles with UFW:

  • Nginx Full: This profile opens both port 80 (normal, unencrypted web traffic) and port 443 (TLS/SSL encrypted traffic)
  • Nginx HTTP: This profile opens only port 80 (normal, unencrypted web traffic)
  • Nginx HTTPS: This profile opens only port 443 (TLS/SSL encrypted traffic)

In our case, because we don't have SSL certificates installed yet, we only need to enable NGINX HTTP, although we'll be enabling HTTPS soon, so we can allow 'Full'.

sudo ufw allow 'Nginx Full'

Now that NGINX is installed and set up with the firewall, we can test that it all works in the web browser. The easiest is to access the web address your provider gave you, in my case vpsxxxx.ovh.net. If you do not have an address, you can also access with your IP address.

http://server_domain_or_IP
http://vpsxxxx.ovh.net

You should get a default NGINX landing page.

Setting up Let's Encrypt #

Obviously, we want to serve our traffic through https, and the easiest, and cheapest way to do so, is with Let's Encrypt. It's a free Certificate Authority, and it provides a super simple Certbot, which configures nearly everything automagically.
It's important to note here that you should have a registered domain name. You should also set up the records for your server, specifically an A record for the root example.com and an A record for www.example.com, both pointing to the public IP of your server.

First you need to add the repository. Then, refresh the package list and install Certbot for NGINX.

sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install python-certbot-nginx

Certbot can configure NGINX automatically, but it still needs to find the correct server block in your NGINX config.
For that, update the default config file for NGINX /etc/nginx/sites-available/default. Find the existing server_name line, and update it to include your domain.

[...]
server_name example.com www.example.com;
[...]

Once this is done, you need to restart the NGINX process.

sudo systemctl reload nginx

Now we can run the Certbot. It will install your Certificates, and configure NGINX.

sudo certbot --nginx -d example.com -d www.example.com

Certbot will also configure itself to autorenew your certificate when needed.
You can always trigger it manually.

sudo certbot renew

Conclusion #

After all this, you now have a basic server running Ubuntu, and serving traffic securely with https. Only basic security features have been implemented, so this should not be used for production yet.

Now what? You might want to run a NodeJS server, and serve traffic. In the next article we will look at NodeJS, PM2, and more NGINX configurations.