VPS & Web Hosting series part 1: Installation¶
Fully configuring a VPS is not that hard nor that long, but when we start our IT journey it's an intimidating task.
Today, we'll configure one from scratch (and for fun ). Let's dream about a NodeJS application that must connect to a MongoDB instance hosted somewhere else. To spice-it up a little, our fictive project called IT Rocks is both an HTTP server and a WebSocket server. It must be able to send emails to our customers too.
And... since it's a very serious project, it needs to be accessible within restrictive networks as well. Why? Because... what would be an IT task without a tricky part?
Important
A few precisions before we start:
- This is inspired by several real-world scenarios I encountered in the past few years
- This tutorial is an advanced one.
- I tried my best to write it in a way that should allow a beginner not to be lost and reproduce every step without struggling too much
- This is not only once of those How to? article you may be used to read, it's also a Why? article. It means that I tried to justify why some decisions have been taken for you to understand that tools and choices are not default ones. They have been thought to fit the project's requirements.
As a consequence, despite my efforts to make it as short and digest as possible, it is quite long and detailed. But so are all real-case IT scenarios we encounter in our jobs.
If you're a beginner, you should find here some valuable information and resources that are not that easy to find and compile by yourself. But it comes at a cost: you'll have to invest some time and efforts to understand everything. If something is unclear or if you have a question... just leave a comment :)
This is the first part of a series:
- VPS & Web Hosting series part 1: Installation
- VPS & Web Hosting series part 2: Configuration
- VPS & Web Hosting series part 3: Maintenance & additional notes
Project precisions & Preparation¶
First of all, we need a VPS (Virtual Private Server) up and running to connect to.
To sum up the needs defined in the intro and for clarity sakes, there are the requirements:
- NodeJS application
- HTTP server with express
- WebSocket server with uWebSocket.js
- Sends mails
- Connects to distant MongoDB database service.
- Accessible in restrictive networks (enterprise, schools, etc.)
- The project sources are hosted in a Github private repository, with two branches:
main
release
(the one we want to use on the VPS)
About express and uWebSocket.js
This is not as uncommon as it seems to encounter a scenario like this. You can read more about express and uWebSocket.js configuration pitfalls there, but not to make this tutorial too long, I'll sum it up in one sentence:
Express and uWebSocket.js are incompatible. It means that ITRocks needs two open ports. It's important because of the "accessible in restrictive networks" requirement.
Now, it's time to roll up our sleeves and start typing on our beautiful keyboard
Installation¶
The first thing to do is obviously to connect to our VPS to install the tools we need.
We ordered our VPS few minutes ago, and since our provider is as fast and efficient as our beautiful application, we already received an email with the following information:
Dear customer,
Ubuntu 20.04
operating system has been installed on the VPS you ordered:
- IPv4 address:
156.225.137.143
(1)- VPS name:
ac78ef7.vps.provider.com
(2)The admin account configured on your VPS is:
- User:
ubuntu
(3)- Password:
Ohb78@hioude!ma09k
(4)
- This is a fictive IPv4
- This is a fictive domain
- This is a fictive username
- This is a fictive password
Please, DO NOT use the above credentials as is. CHANGE THEM!
The following tutorial should work for Ubuntu Server 22.04 as well. If you use another distribution, the following tutorial may not be accurate nor relevant anymore.
First connection and ubuntu upgrade¶
Let's connect to the server for the first time through SSH with the command ssh [user]@[ip]
or ssh [user]@[domain]
. For the current VPS,
the exact command using the IP address is:
The first time, it will print you a warning because of self-signed certificate, just accept it.
Then type the server password.
Securing SSH connection to the VPS¶
Once logged in, we must start by changing the admin password, since it has been provided in cleartext by mail, its security maybe compromised already, or maybe compromised later.
Now, the first thing we want to do is disabling SSH password login to prefer a private key secured by a passphrase. This reduces risks of a successful brute-force attack to 0. And your SSH login should remain secure as long as the machine you keep this private key on stays secure too.
For the whole tutorial, I'll assume that you're operating from an ubuntu local machine. If it is not the case, please adapt local commands to your operating system.
On local machine | |
---|---|
- At this step, you will be given the option to setup a passphrase or not. Keep the habit to always define a passphrase. It makes your private key much harder to steal.
Then, try to connect to your VPS with the command ssh ubuntu@156.225.137.143
. Your operating system will ask you the
passphrase you chose while generating the certificates, but if the operation was successful, the SSH client will not ask you the ubuntu
password.
Now, we want to prevent anyone from accessing the server with any password, to enforce keys usage, as well as forbid entirely root login. Let's create a new ssh config file:
With the following content:
Type Ctrl+S to save and Ctrl+X to exit.
Then, we need to reload the SSH server and the SSH daemon:
Test time. Trying to log with root user should be always rejected, so:
Must print Permission denied (publickey).
, and:
- This option allow us to disable automatic key based authentication to request a password authentication
Must print Permission denied (publickey).
too.
Upgrading ubuntu & setting up automatic upgrades¶
Now that we successfully secured SSH access to our VPS, let's login once more to upgrade ubuntu:
Rebooting may or may not be mandatory, so we just go with it anyway.
Since we don't want to connect every day just to update the server to get security fixes, we will use
the unattended-upgrades
package that will take care of that for us:
Then we must enable it:
Just choose yes
and press Enter.
We do not turn on automatic reboot, because we may want to reboot at a specific point in time. ITRocks may want to schedule a maintenance downtime, for example.
Installing needed packages¶
Let's install what we need to run IT Rocks behind an Apache proxy:
The package iptables-persistent may ask you if you want to save the current ipv4
or ìpv6
config. The answer doesn't matter, since we will redefine them later anyway.
Wait... what are all those packages?
It looks like we're installing a bunch of software, let's explain what is what:
package | description |
---|---|
apache2 |
An HTTP server and will be our proxy. It could have been NGinx or Caddy too, for example. |
npm |
The NodeJS Package Manager, needed to fetch our project's dependencies. |
certbot |
A utility that is useful to manage (generate/install/renew/revoke) SSL certificates signed by Let's Encrypt. |
python3-certbot-apache |
A Certbot plugin to work with Apache. It will automatically setup Apache configuration for us in a blink. |
fail2ban |
A log analyzer that works with the firewall to ban suspicious activities. |
iptables-persistent |
A utility that will persist our firewall configuration. |
Why do we need a proxy?
It seems that the time has come to discuss what we'll install on this server to fulfill our requirements list. The most important information in this requirements list now is the need for 2 open ports and the need for access in most restrictive networks. But what actually are restrictive networks? Why is that important?
If at home your gateway (the device that connects your home network to the Internet) do not restrict your online activities, in an enterprise or school network the gateway firewall will most likely block the inbound and outbound traffic on almost every port. Not so long ago, it left two ports open to the Internet:
- 80 (HTTP)
- 443 (HTTPS)
Since port 80 is insecure and SSL certificates free for years now thanks to our savior Let's Encrypt, port 80 almost disappeared from most of the firewalls' configurations. As such, it leaves us with... port 443. However, our wonderful application still needs two open ports.
It looks like we're screwed, isn't it?
Not even close. God bless proxies!
If you don't know what a proxy is: it's something that acts like an interface between two other things. When it receives a request, it will not answer it himself but rather will forward the request to another service to get the answer, and then send it back to the requester.
So we can set up a proxy that will expose only one public port (443 in our case), and route the traffic on two private ports on which our ITRocks server will be listening. Another welcome benefit is that you can reload the proxy when SSL certificates are renewed without closing ongoing connections. Pretty cool, huh?
NVM & node¶
Then we'll need nvm to manage NodeJS versions on the same machine, it will ease switching version later if needed:
This command downloads the last nvm
version at the moment this document has been written, to install the last version, please read the install section of their GitHub.
Then we install the version of NodeJS that will run our server. Hydrogen
is the last LTS (v18.14.2) version at the moment this document has been written:
While writing this doc, Hydrogen downloads the v18.14.2.
You can use nvm ls-remote
to print all available versions of node, and use nvm ls-remote | grep LTS
to filter LTS versions only.
It will be set to default
, you can check node version with node -v
. If it doesn't print the version you installed, run the commands:
Then, node -v
should print v18.14.2
Very important note
If a Github Action is configured for the current server, you must follow additional instructions
for this version change to take effect when the Github Action will run npm install
!
For now, it shouldn't. But if you come back later or if you didn't follow all steps and encounter strange error messages while trying to run a Github Action, carefully read the above link.
Installing ITRocks¶
We start by creating a folder in ubuntu's home folder /home/ubuntu
:
git config core.fileMode false
, is this git sorcery?
The command git config core.fileMode false
is mandatory to avoid git to track local file system permissions changes.
If you don't run this command, when the git hooks that we will set up below will change group ownership of all files, git will later prevent to checkout/pull before stashing or committing.
Now, we need to create a deploy token
to be able to pull, since the repository is private (do not change generated file path/name, you don't need a passphrase):
Then we will configure the key for git:
Type this into the file editor:
/home/ubuntu/.ssh/config | |
---|---|
Then type Ctrl+S to save and Ctrl+X to exit.
We want to adapt permissions to this file as well:
Now, you need to copy the content of id_rsa.pub
. You can use the Linux scp
command from another terminal to download it, or just print it to the console to be able to copy it into your clipboard:
The public key must be set as deploy key
on GitHub
. To do so, go to the project repository, click on the settings
in the top tabs, then choose Deploy Keys
in the left panel, and click the Add deploy key
button, top right.
Type a meaningful name as Public production key on [Provider] VPS
as title, and paste the previously copied ìd_rsa.pub
file content into the key
field. Do not check the Allow write access
checkbox for security sakes.
Once done, come back to your SSH terminal and type :
And... we've done for the installation process \o/
Now, it's configuration time, in the second part of this series