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:
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.
Now, restart the SSH daemen service, so that the changes take effect:
sudo systemctl restart sshd
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 (SSH) 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 ssh
sudo ufw allow http
sudo ufw allow https
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:
- Creating a
sudo
user - Configure SSH Key login
- Securing your server
- Adding a firewall
- Configure Nginx
- Certbot homepage / configuring wizard
like this post? discuss it on the forums at basementcommunity.com. Or you can also send me an email!