How to Create a VPS Web Server

Shared Hosting vs. VPS

Choosing a place to host a website is one of the most confusing decisions for beginner web developers. Even for experienced web devs, choosing between different forms of web hosting can be a daunting choice.

First, let's take a look at shared web hosting. Shared web hosting is a product where you are purchasing a small piece of a web server that is being shared between many websites. As a result, the cost of shared hosting is extremely low. You won't have access to the server itself, which means you can't install your own software on the server, such as Docker. Usually, you are simply allowed to connect your domains to the server, set up domain security, and other small utilities.

In contrast, a virtual private server (VPS) is a virtual machine that replicates the environment of having a dedicated server to yourself. You are able to control the virtual server's host names, base file system, package manager, etc. Another great upside of a VPS is that since it's virtual, the company providing the VPS can dynamically increase the disk size, RAM size, or number of CPUs at any time. However, the virtual server is still physically located on a server that is shared between multiple virtual servers.

The choice between shared hosting and VPS mostly depends on your skill level with system administration. If you're comforting working on a server that is mostly left up to you (or you're willing to learn), then a VPS is usually a better option. However, shared hosting is a fantastic option for people who don't want to have to learn how to manage their server.

My Situation

I had used shared hosting for approximately 5 years before trying my first VPS. I manage a homelab and have had success running a server and performing typical sysadmin duties, but I was still hesitant to get a VPS. One fear was that I always struggled to properly set up the networking part of a server - DNS and hostname configurations were not my friend.

As a little bit of background, I originally used Siteground for my initial shared hosting and stayed on that platform for at least a year. However, the UI was clunky, and I didn't like how they handled certain technical aspects, so I switched to Namecheap. Namecheap was great because it is the service I primarily use for purchasing domain names, which made it incredibly easy to link them to my hosting service. However, it was still mediocre shared hosting and Namecheap is notorious for not letting you use Let's Encrypt to obtain free SSL/TLS certificates - Namecheap wants to make you purchase certificates through their store.

Finally, I settled down with iWebFusion for about the last year of my shared hosting. This service was pretty great, came with free SSL/TLS, and I never had any complaints.

However, I finally grew tired of not being able to install software on my own web server. I wanted to be able to try out things like Postmill or Matrix. This is possible with a VPS, so I decided to grab a new domain name to try it out.

Getting Started: Buying a VPS

The first step to moving over to a VPS is (you guessed it): finding a VPS provider. Personally, I went with DigitalOcean. I don't have any real logic behind this choice except the fact that I enjoyed their website UI and the prices were marginally cheaper than others like Vultr.

You'll have to decide what specifications you want on your VPS. For me, I only build and deploy low-resource HTML, PHP, and Python websites. This means I can survive on the smallest VPS - 1 CPU, 2GB of RAM, and 20GB SSD for $5.00 per month. I added on the $1.00/month backup fee so that DigitalOcean will take weekly backups of my VPS, just in case I experiment too much and destroy everything on my server.

As noted above, the great thing about a VPS is you can request your provider to increase the resources at any time.

Configuring DNS Settings

Okay, so now let's get into some actual work that has to be done to get content moved from a shared host to a VPS. At this point, I'm assuming you have a shared host with website content that you can still access, and you've purchased a new VPS and can SSH into that server.

The first change is a minor one, but it should be done immediately in order to get things moving: DNS settings. Go to wherever your DNS settings are handled. If your shared host also managed your DNS settings, you'll need to first move that DNS over to your new VPS provider. For me, I route my DNS through Cloudflare (DNS only - no proxies).

Once you know where your DNS settings are, go ahead and update the A records to match the public IP address of your VPS. For example:

A         example.com     xxx.xxx.xx.xxx
A         subdomain       xxx.xxx.xx.xxx
CNAME     www             example.com.

If you have any other records that require updates, such as MX or TXT records for a mail server, be sure to update those accordingly. Personally, I don't host my own mail server - I route all mail on my custom domains to ProtonMail.

DNS changes can take up to 48 hours to propagate, so be sure to give it some time before assuming you've made an error.

Server Updates and Packages

Now that the DNS settings have been changed, let's set up our server while we wait for the DNS to propagate. First up is to ssh into your server - if you've signed up with a service like DigitalOcean, you can add your SSH key to your account and to your VPS droplet so that you don't need a password in order to SSH.

ssh root@xxx.xxx.xx.xxx

The VPS that is used in this post runs Ubuntu 20.04 with an Apache web server. If you're working on a different operating system (OS) or want a different web server, such as Nginx, you'll have to use different commands to set it up.

First, let's update and upgrade our server.

NOTE: Since we have SSH'd into the server as root, we don't need to use the sudo modifier before our commands.

apt update && apt upgrade -y

Our goal here is to host a web server, so the next step is to install the Apache web server and any other packages we need.

apt install apache2

If you need other language support, such as PHP, you'll need to install that too.

apt install libapache2-mod-php php-dom
a2enmod php
systemctl restart apache2

Website Files & Folders

Next up is to create the directories for the domain(s) we want to be hosted on this web server.

cd /var/www
mkdir example.com

We have a folder for example.com now, so let's add an index.html file and put it within a specific public_html folder. You don't need this public_html if you don't want it, but it helps with organizing items related to example.com that you don't want published to the internet.

cd example.com
mkdir public_html && cd public_html
nano index.html

You can put anything you want in this index.html file. If you can't think of anything, paste this in there:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>
  </body>
</html>

If you want something to be served at example.com/page01/file.txt, you'll have to create the page01 directory under the example.com directory. For example:

cd /var/www/example.com/public_html
mkdir page01
nano file.txt

Apache Configuration

Now, let's set up the files that will tell the server where to find the files for example.com. We will copy the default configuration file and create our own.

cd /etc/apache2/sites-available
cp 000-default.conf example.com.conf
nano example.com.conf

This configuration file will have a few default lines, but you'll need to edit it to look similar to this (settings may change based on your personal needs):

<VirtualHost *:80>
      ServerAdmin your-email@email-provider.com
      ServerName example.com
      ServerAlias www.example.com
      DocumentRoot /var/www/example.com/public_html
      ErrorLog ${APACHE_LOG_DIR}/error.log
      CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Now, enable the configuration for your new site, disable the default configuration, and reload the web server.

a2ensite example.com.conf
a2dissite 000-default.conf
systemctl reload apache2

You can always run a test to make sure no errors or warnings are found in your configuration files.

apache2ctl configtest

Now, restart the web server entirely. After this, you should be able to browse to http://example.com and see the HTML content you provided earlier. Note that SSL/TLS has not been enabled yet, so you won't be able to use the secure version yet (https://example.com).

systemctl restart apache2

You can repeat this for as many websites as you need. Just create the domain folders in /var/www/, add the configuration file, enable the configuration, and restart apache2.

SSL/TLS Certificates - Serve Websites Over HTTPS

In order to serve secure content, you'll need to obtain SSL/TLS certificates. Luckily there's a free tool called Certbot that helps us with the process.

The first step is to install snapd and snap's core for Ubuntu.

apt install snapd
snap install core
snap refresh core

Next, install the certbot snap package.

snap install --classic certbot

Execute the following command to ensure that the certbot command can be run.

ln -s /snap/bin/certbot /usr/bin/certbot

Finally, you can run certbot one of two ways:

  1. run it and let it alter your Apache configuration files automatically to enable HTTPS redirects/
  2. run it and only allow it to create certificates - you'll need to manually alter the config files to enable HTTPS redirects.

Run certbot and allow automatic config changes:

certbot --apache

Run certbot for certificates only - don't allow it to alter config files:

certbot certonly --apache

The Certbot packages on your system come with a cron job or systemd timer that will renew your certificates automatically before they expire. You will not need to run Certbot again, unless you change your configuration. You can test automatic renewal for your certificates by running this command:

certbot renew --dry-run

Now, test your domains by going to https://example.com.

Firewall Security

To enable better security on your server, you'll need to enable a basic firewall. For Ubuntu, we'll use the uncomplicated firewall.

Now, add the following rules to the firewall allow SSH, Apache, and HTTP(S) connections. If you need to, you can enable different ports for specifics applications, SFTP, etc.

ufw allow OpenSSH
ufw allow Apache
ufw allow proto tcp from any to any port 80,443

Once you've added all the rules you need, enable the firewall.

ufw enable

Troubleshooting

If you run into any issues during your VPS set-up, be sure to walk back through your actions and make sure you didn't miss any steps.

Many websites have fantastic guides to setting up various web servers - this is one of the areas where DigitalOcean shines.

If you're getting certain errors (e.g. 500 Internal Server Error) need to debug locally, you can view the access.log and error.log files in the /var/log/apache/ directory.