basement blog

everything i personally do when hosting a website on a new server

There's an overwhelming amount of options today for deploying something to the Internet. You've got services like Fly.io and Heroku that allow you to deploy worldwide with simple commands. There's Neocities and Nekoweb that expose a simple drag-and-drop interface for your static site. And of course there's Bearblog and Pika for blogging.

But what if you want to learn the basics of renting a virtual private server (VPS), spinning it up, and configuring it to run your website? Is learning the nitty-gritty of server setup obsolete these days? Maybe, but it's fun! So this is why I'm going to spend the rest of this blog post highlighting my personal checklist for provisioning and hardening a VPS!

Table of Contents

Prerequisites

First things first: we need to rent a server to put our Website on. My preference is to use Linode (referral link). Any VPS provider will do the trick, but I previously worked for Linode, so I'm familiar with the interface and the pricing is really good for the reliability and support. Their whole claim-to-fame is that you get connected to a human right away when calling in for support:

linode creation flow

you can get a nice starter server for $5/month

Connecting to the Server

During the purchasing step, you're most likely going to be asked to provide a "root password" for your server. This password you will need when getting access to the server, so make sure you remember it.

After you purchased your server and have your root password, look around on the interface for the IPv4 address. You're going to need this to access the server and start issuing commands to it from your home computer.

Once you have both, open up the terminal program of your liking. Macs come installed with an application called "Terminal" that you can use. Windows and Linux probably have a similarly named application. With this, you're ready to connect to your server and you can enter this command into the terminal, replacing IP_ADDRESS_GOES_HERE with your actual IPv4:

ssh root@IP_ADDRESS_GOES_HERE

The server will then ask for your root password, which you will then type in and hit "Enter." Be aware that when being asked for any password, your keypresses won't actually be logged to the screen, so don't be alarmed if you're typing and not seeing anything. Just know your input is working, and you can hit "Enter" once you typed it in.

At this point, you should be connected to the server - congratulations!

Basic Setup

At this point, there's some maintenance tasks to complete before we start securing it and getting a website working.

First, we'll create a new user account because logging in as root user is considered bad practice - root has God access to the server and we want to turn that user off.

Think of a new username and create it with this command:

adduser USERNAME_GOES_HERE

Set a password when asked, then skip through all the other questions by hitting "Enter." Setting the rest of the information isn't important.

Then, add this user to the "superuser" group called sudo. This will give your user elevated privileges:

usermod -aG sudo USERNAME_GOES_HERE

Log in as this new user:

su - USERNAME_GOES_HERE

Now, we're going to prevent password login and instead prefer logging in with a public/private SSH key pair. So type "exit" into the terminal a couple of times: once to log out of your new user, and a second time to log out as root and you should be disconnected from the server.

Now that we're back on our local machine, we need to generate an SSH Key. On most operating systems, you can do this with a simple command:

ssh-keygen

This command will ask you a few questions. You don't need to fill any of these out and can continue to hit "Enter" to use the default values.

After you do that, you should have a few files inside of the ~/.ssh directory: id_ed25519.pub (the public key) and id_ed25519 (the private key). You're going to want to transfer the public key over to your server, so that you can login with the other half, the private key.

Copy the public key over with this command, replacing with your own username and IP Address:

cat ~/.ssh/id_ed25519.pub | ssh USERNAME_GOES_HERE@IP_ADDRESS_GOES_HERE "mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod -R go= ~/.ssh && cat >> ~/.ssh/authorized_keys"

Your SSH Key is now copied over to the server and what this means is you can use the SSH Key, instead of a password, to log in to to server. In fact, it's the preferred approach.

Log in to the server using your private key to authenticate:

ssh -i ~/ssh_keys/id_ed25519 USERNAME_GOES_HERE@IP_ADDRESS_GOES_HERE

Note that this key is local to your computer, so if you want to log in on another device, you'll need to securely transfer your private key over to that device. Don't email it around, but instead use a flash drive or something more secure.

We're back in the server - let's continue the setup. Perform system updates (you'll also want to get in the habit of doing this regularly):

sudo apt-get -y update && sudo apt-get -y upgrade

apt-get will work if you're on Ubuntu or Debian but other operating systems have different commands for upgrading. You can find your appropriate command here

This is probably the first time you are prefixing a command with sudo as well, so you'll be asked for your password just this one time.

Now, we set a hostname for the server. This is just a convenience, so that you can recognize your server with a human-readable name. It can be something fun or you can just make it the domain name you want to use. My main server's hostname is the-moon, but could have just as easily been called basementcommunity.com if I wanted:

sudo hostnamectl set-hostname HOSTNAME_GOES_HERE

Open up the /etc/hosts file in a terminal text editor called nano and link your IP Address with the hostname you just chose:

sudo nano /etc/hosts

Once the file is open, place this line in it, replacing with your IP and hostname:

IP_ADDRESS_HERE HOSTNAME_GOES_HERE

Exit the file with Ctrl + X then Y then Enter to confirm changes

Set the timezone to whatever timezone you're in:

sudo timedatectl set-timezone 'America/New_York'

Don't know how to format your timezone? You can view a full list with this command:

timedatectl list-timezones

You can hit the "Q" key to exit out of the timezone list.

Securing the Server

The basic setup is done! Let's secure the server.

First, we're going to disable the option to login as root because that user is too powerful and there's no reason to be logging in as it anymore. Open up the /etc/ssh/sshd_config file with the nano text editor:

sudo nano /etc/ssh/sshd_config

find the line that reads PermitRootLogin and set to no

PermitRootLogin no

Ctrl + X to quit, Y then Enter to save the changes.

Let's install a firewall. There's many options, but UFW is the one I choose just because it's very simple. First, install UFW:

sudo apt install -y ufw

Now enable which kind of traffic you want to allow to your server. First, we know we need port 22 open because that's the port via which you log in to the server. If you're hosting a website, you'll probably also want ports 80 (HTTP) and 443 (HTTPS) open as well. So let's allow those 3 to begin with:

sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443

Then, enable the firewall:

sudo ufw enable

Configure a Web Server

Finally, let's get a Website working. First, let's install Nginx, the software that will serve your Website:

sudo apt install -y nginx

Now, god forbid your server crashes, let's enable Nginx to restart itself when the server comes back online:

sudo systemctl enable nginx

Now if you open up a browser, and navigate to http://YOUR_IP_ADDRESS_HERE, you should see the default Nginx page there. But let's get something different on there. Create a new directory where we'll keep our Website files, replacing SITE_URL_HERE with the domain name of your site:

sudo mkdir -p /var/www/SITE_URL_HERE/html

Next, give the current user ownership to this directory and all the files within:

sudo chown -R $USER:$USER /var/www/SITE_URL_HERE/html

Create a simple HTML file in here:

sudo nano /var/www/SITE_URL_HERE/html/index.html

Write "hello world" or whatever you like in here. Ctrl + X to quit, Y then Enter to save the changes.

With the HTML file created, we need to tell Nginx where to find it. Create an "Nginx server block" with this command, again replacing SITE_URL_HERE with the actual domain name you're using:

sudo nano /etc/nginx/sites-available/SITE_URL_HERE

Paste this code inside of the file, again replacing SITE_URL_HERE with your domain name:

server {
        listen 80;
        listen [::]:80;

        root /var/www/SITE_URL_HERE/html;
        index index.html index.htm index.nginx-debian.html;

        server_name SITE_URL_HERE www.SITE_URL_HERE;

        location / {
                try_files $uri $uri/ =404;
        }
}

Ctrl + X to quit, Y then Enter to save the changes.

Now we need to sync this file to the one Nginx reads when it starts up. Run this command, again replacing SITE_URL_HERE with your domain:

sudo ln -s /etc/nginx/sites-available/SITE_URL_HERE /etc/nginx/sites-enabled/

Really quickly, we should update the Nginx configuration file to give Nginx more memory to handle more domains. Open the file in nano:

sudo nano /etc/nginx/nginx.conf

Remove the beginning # character from this line:

server_names_hash_bucket_size 64;

Ctrl + X to quit, Y then Enter to save the changes.

Now, test that there are no errors within Nginx with this command

sudo nginx -t

If you don't see this, you'll know you did something wrong and should go back through the steps and confirm you followed them all correctly:

Output
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Now, restart Nginx:

sudo systemctl restart nginx

Assuming you have proper A records configured as well for your domain, (which I won't explain in this blog), you should now be able to navigate to http://SITE_URL_HERE in the browser to see the HTML file as well.

At last, let's get HTTPS working as well. For this, we're going to use Certbot, a free solution to getting HTTPS working

First, install the dependencies and prepare Certbot:

sudo apt install -y snapd
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Now run Certbot and have it configure HTTPS (this command will automatically update the /etc/nginx/sites-available/SITE_URL_HERE we created earlier:

sudo certbot --nginx

This command will ask you a few questions. Be sure to answer them then hit "Enter." Once you're done, you should be able to go to https://SITE_URL_HERE and you're done!

Also note that any http:// connections are being redirected to https://


That's everything I'm going to outline in this blog. Obviously the next step would be to get the actual files you want to host inside the /var/www/SITE_URL_HERE/html directory and replace that index.html file you created. I'll list the links I used to create this guide below:

References:


like this post? discuss it on the forums at basementcommunity.com. Or you can also send me an email!