The minimal configuration of a VPS server to host a Web Application
Photo by Denny Müller on Unsplash
Contrary to shared hosting, which is already configured with many applications and ready to serve your application to the Internet, a VPS comes with only the operating system. It is your responsibility to configure it to serve your app.
Prerequisites
This tutorial assumes you have a VPS running on Ubuntu 18.04 or higher.
You can buy a VPS on Hetzner, which provides affordable server with good performance. The server running this blog and all my side projects are hosted here. Use my referral link to get €20 after you sign up.
Connect to the server
You bought a VPS at your favorite provider; the first thing to do is log into it. Usually, you receive an email with the credentials required to connect. It's constituted by an
- IP address
- a user (root by default)
- a port (22 by default).
The syntax for connecting to the server is as follows:
ssh -p <port> <user>@<server_ip_address>
Option -p is for the server's port; the default value is 22.
Let's assume our IP address is 43.206.85.179.
I chose it randomly, so I'm sorry if it turns out to be the IP address of your server. The username is usually the root, but it will be given in the email you will receive.
We will type the code below to connect to the server:
ssh root@43.206.85.179
Congratulations, we are inside the server. Let's continue with the next step.
Install a firewall
A firewall is a software placed between our system and the external network. It filters incoming and outgoing requests based on rules written by the system administrator.
You can deny incoming traffic from a specific port or IP address. Our server usually has no firewall installed, so it is our responsibility to install one. The most famous in the Ubuntu world is UFW, which stands for Uncomplicated Firewall.
We will use it to deny incoming requests from any port and then add rules based on our needs to allow on a specific port.
Run the command below to install and wait for the installation to complete.
apt-get install ufw
The firewall is all installed, and by default, all incoming connections to our server are denied, even the SSH connection on port 22. If we log out to the server, we can't connect anymore.
Let's allow SSH connection on port 22 with the command below:
# Allow ssh connection
ufw allow ssh
# Activate UFW
sudo ufw enable
# View all rules defined
ufw status verbose
Note: We don't add sudo because we are connected with the root user. If it is not your case, consider adding the "sudo" keyword before the command.
Log out, then log in again to ensure you can still connect to the server.
Change SSH Port
By default, the SSH port is 22. Changing this to make your server a little more secure is a good idea. Here is the process to change the port to 4927.
- Open the SSH config's file:
nano /etc/ssh/sshd_config
- Locate line #Port 22
- Remove the hashtag in front of and replace 22 by 4927
- Save the file and exit
- Restart the SSH service:
/etc/init.d/ssh restart
Now, we need to update the firewall rule to:
- Allow SSH connection on port 4927:
ufw allow 4927/tcp
- Delete rule for SSH connection on port 22:
This is achieved in two steps where the first is to list the rule with a number assigned to each rule: ufw status numbered
.
Locate the number of the rule you want to delete, then type: ufw delete <rule_number>
e.g.: ufw delete 3
Create a user with a sudo privilege
Since then, we have used the root user to perform restricted actions. It is not a good decision because a bad manipulation can cause significant damage. It is better to create a user with lower privileges on the system and keep the user performing actions requiring the root user.
The command below creates a user "admin" with sudo privilege:
# create user admin with his home directory
useradd -m -d /home/admin admin
# set the password
passwd admin
# add the user in the sudo users list
echo 'sadmin ALL=(ALL) ALL' >> /etc/sudoers
# list users to verify the user created
cat /etc/passwd
Now log out, then connect with the new user created and provide the password you have registered in the step above:
ssh -p 4927 admin@43.206.85.179
Disable connection with root user
Since we have another user we can connect to the server with, we will disable the SSH connection with the root user. It is a security measure to avoid preventing a malicious person from doing anything on our server.
The process to achieve that is as follows:
- Open the SSH config's file:
nano /etc/ssh/sshd_config
- Locate the line with:
PermitRootLogin yes
and replace yes with no. - Save the file and exit.
- Restart the SSH service:
/etc/init.d/ssh restart
- Log out and verify that you can't connect with the root user.
Note: When connected with the sudo user, if you want to perform an action requiring root user privilege, you can switch to the root user by typing the command sudo su
then provide your admin password.
Install a Web server
Our goal is to host our web application and make it accessible through the Internet, but a server is just a computer like ours but without a GUI and up every time.
By default, the server doesn't have this capability, and we need to install a Web server to make this possible. The most popular web servers are Apache, Nginx, and Microsoft IIS.
We are going to install Nginx:
sudo apt install nginx
sudo ufw allow 'Nginx Full'
sudo systemctl status nginx
The command sudo ufw allow 'Nginx Full'
Open ports 80 and 443 for HTTP and HTTPS, respectively, to allow incoming traffic from the web.
Install Node.js
We can run a web application built in any language. The only requirement is to install the necessary runtime. You can install PHP, Go, Ruby, Java, or Node.js, depending on your needs.
We will install Node.js through NVM (Node Version Manager). You can check the latest version on the GitHub repository. At the time I'm writing this article, the version is 0.39.5.
cd ~
# install necessary dependencies
sudo apt-get install build-essential libssl-dev
curl -sL https://raw.githubusercontent.com/creationix/nvm/v0.39.5/install.sh -o install_nvm.sh
bash install_nvm.sh
# reload your profile
source ~/.profile
# list all available versions
nvm ls-remote
nvm install v18.17.1
nvm use v18.17.1
nvm alias default v18.17.1
# verify that node installed succesfully
node -v
Install PM2
To launch a Node.js web application, we type node our_entry_file.js
. If we do that on the server and log out, the application will stop, and we don't want that. We need a way to have our application up even if we log out of the server.
PM2 solves this by creating a daemon process to keep your application online 24/7. You can launch as many applications as you want, and it will manage these for you. The installation is straightforward:
npm install -g pm2
pm2 list
If you want to deploy a Node.js app with PM2, check out this article, where I show how to do that.
Connect to the server with a private key
We connect to our server with a username and password, but connecting with an RSA private key is also possible. Let's see how to create that key and connect to the server using that:
Once connected to the server with the admin user created earlier, do these actions:
- Create a folder .ssh at the home directory:
cd ~ && mkdir .ssh
- Generate an RSA key pair:
ssh-keygen -t rsa
- Enter in the .ssh directory:
cd .ssh
- Add the public key to the authorized keys
cat id_rsa.pub >> authorized_keys
- Mark the authorized_keys file as hidden:
chmod 600 authorized_keys
- Delete the public key:
rm .ssh/id_rsa.pub
- Open the private key file
id_rsa
and copy the content to the clipboard - Log out of the server.
You are now on your computer, and the private key is in your clipboard:
- Create a file key.txt (you can give the name you want) and paste the clipboard's content inside.
- Make the file hidden:
chmod 600 key.txt
Connect to the server with the private key:
ssh -i key.txt admin@43.206.85.179
It's done 🎉
Wrap up
We saw how to prepare our server to host our Web application with the basic configuration. However, many other things to remember when managing a VPS, like software updates, health monitoring, and continuous protection against malicious attacks (DDoS, ransomware, etc.).
Follow me on Twitter or subscribe to my newsletter to avoid missing the upcoming posts and the tips and tricks I occasionally share.