In the previous chapter, I showed you how to install Nginx, PHP 7.4, WP-CLI, and MariaDB, which formed the foundations of a working web server. In this chapter I will guide you through the process of deploying your first HTTPS enabled site with HTTP/2 support.


HTTPS is a protocol for secure communication between a server and a client. It ensures that all data sent between the devices is encrypted, and that only the intended recipient can decrypt it. Without HTTPS any data transmitted will be sent in plain text, allowing anyone who is eavesdropping to read the information.

HTTPS is especially important on sites which process credit card information, but has gained widespread adoption over the last couple of years. This is partly due to Google announcing it as a ranking signal, but also due to the introduction of Let’s Encrypt, which provides free SSL certificates.


HTTP/2 is the latest version of the HTTP protocol and can provide a significant improvement to the load time of your sites. I wrote a complete article on the subject, which explains the benefits in more detail. In short, there really is no reason not to enable HTTP/2, the only requirement is that the site must also be served over HTTPS.

Obtaining an SSL Certificate

Before obtaining an SSL certificate you will need to ensure that you’ve added an A record to your DNS provider that points to your server. Now let’s install Certbot:

sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update
sudo apt install certbot python3-certbot-nginx

To obtain a certificate, you may use the Nginx Certbot plugin, by issuing the following command. The certificate can cover multiple domains (100 maximum) by appending additional d flags.

sudo certbot --nginx certonly -d -d

After entering your email address and agreeing to the terms and conditions, the Certbot client will generate the requested certificate.

Certbot will handle renewing all your certificates automatically, but you can test automatic renewals with the following command:

sudo certbot renew --dry-run

Nginx Server Block

Now we need to set up a server block so that Nginx knows how to deal with requests. By default, Nginx will drop any connections it receives, as in the previous chapter you created a catch-all server block. This ensures that the server only handles traffic to domain names that you explicitly define.

If you’re not already there, navigate to your home directory.

cd ~/

For simplicity’s sake, all of the sites that you host are going to be located in your home directory and have the following structure:

Directory Structure

The logs directory is where the Nginx access and error logs are stored, and the public directory is the site’s root directory which will be publicly accessible.

Begin by creating the required directories and setting the correct permissions:

mkdir -p
chmod -R 755

With the directory structure in place it’s time to create the server block in Nginx. Navigate to the sites-available directory:

cd /etc/nginx/sites-available

Create a new file to hold the configuration. Naming this the same as the site’s root directory will make server management easier when hosting a number of sites:

sudo nano

Copy and paste the following configuration, ensuring that you change the server_name, access_log, error_log and root directives to match your domain and file paths. You will also need to replace the file paths to the certificates obtained in the previous step. The ssl_certificate directive should point to the fullchain.pem file, and the ssl_certificate_key directive should point to the privkey.pem file. Hit CTRL X followed by Y to save the changes.

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;


    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    access_log /home/ashley/;
    error_log /home/ashley/;

    root /home/ashley/;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;


    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    return 301$request_uri;

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


    return 301$request_uri;

Download the complete set of Nginx config files

This is a bare-bones server block that informs Nginx to serve the domain over HTTPS. The WWW subdomain will be redirected to and HTTP requests will be redirected to HTTPS.

The two location blocks essentially tell Nginx to pass any PHP files to PHP-FPM for interpreting. Other files types will be returned directly to the client if they exist, or passed to PHP if they don’t.

By default Nginx won’t load this configuration file. If you take a look at the nginx.conf file you created in the previous chapter, you will see the following lines:

# Virtual Host Configs

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

Only files within the sites-enabled directory are automatically loaded. This allows you to easily enable or disable sites by simply adding or removing the symlink.

To enable the newly created site, symlink the file that you just created into the enabled-sites directory:

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

In order for the changes to take effect, you must reload Nginx. However, before doing so you should check the configuration for any errors:

sudo nginx -t

If the test failed, recheck the syntax of the new configuration file. If the test passes, reload Nginx:

sudo service nginx reload

Restart Nginx

With Nginx configured to serve the new site, it’s time to create the database so that WordPress can be installed.

Creating a Database

When hosting multiple sites on a single server, it’s good practice to create a separate user and database for each individual site. You should also lock down the user privileges so that the user only has access to the databases that they require. Here’s how to do just that.

Log into MariaDB with the root user. Although we’re using MariaDB the commands are exactly the same as if you were using MySQL, because it’s a drop in replacement. MariaDB and MySQL will be used interchangeably throughout the remainder of this chapter.

mysql -u root -p

You’ll be prompted to enter the password which you created when setting up MariaDB.

MySQL Command Line

Once logged in, create the new database:

CREATE DATABASE ashleyrich_com CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;

Next, create the new user using the following command, remembering to substitute the username and password for your own values:

CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';

You then need to add the required privileges. To keep things simple, you can grant all privileges but restrict them to the ashleyrich_com database only, like so:

GRANT ALL PRIVILEGES ON ashleyrich_com.* TO 'username'@'localhost';

Alternatively, you can have more granular control and explicitly define the privileges the user should have:

GRANT SELECT, INSERT, UPDATE, DELETE ON ashleyrich_com.* TO 'username'@'localhost';

Be careful not to overly restrict permissions. Some plugins and major WordPress updates require heightened MySQL privileges (CREATE, DROP, ALTER, etc), therefore revoking them could have adverse effects. The WordPress Codex has more information on MySQL privileges.

For the changes to take effect you must flush the MySQL privileges table:


Finally, you can exit MySQL:


Now that you have a new database, it’s time to install WordPress.

Installing WordPress

Start by navigating to the site’s public directory:

cd ~/

Then using WP-CLI, download the latest stable version of WordPress into the working directory:

wp core download

You now need to create a wp-config.php file. Luckily, WP-CLI has you covered:

wp core config --dbname=ashleyrich_com --dbuser=username --dbpass=password

Finally, with the wp-config.php file in place, you can install WordPress and set up the admin user in one fell swoop:

wp core install --url= --title='Ashley Rich' --admin_user=ashley --admin_password=password

You should see following message:

sh: 1: /usr/sbin/sendmail: not found
Success: WordPress installed successfully.

You can safely ignore the sendmail not found error. This occurs because we haven’t set up email sending yet. We’ll set up email sending in chapter 5.

You should now be able to visit the domain name in your browser and be presented with a default WordPress installation:

Blank WordPress Installation

Adding Additional Sites

Additional sites can be added to your server using the same procedure as above and you should be able to fire up new sites within a couple of minutes. Here’s a quick breakdown of how to add additional sites:

  1. Add the relevant DNS records to the domain
  2. Obtain an SSL certificate
  3. Navigate to your home directory and create the required directory structure for the new site (logs and public)
  4. Navigate to the sites-available directory within Nginx and copy an existing config file for the new server block. Ensure you change the relevant directives
  5. Symlink the config file to the sites-enabled directory to enable the site and restart Nginx
  6. Create a new database and MariaDB user
  7. Navigate to the site’s public directory and download, configure and install WordPress using WP-CLI

You are free to add as many additional sites to your server as you like, the only limiting factors are available system resources (CPU, memory, and disk space) and bandwidth restrictions imposed by your VPS provider. Both of which can be overcome by upgrading your package. Caching will also greatly reduce system resource usage, which is something I will guide you through in the next chapter.

Subscribe to get the latest news, updates and optimizations in performance and security.

Thanks for subscribing 👍

To receive awesome stuff, you'll need to head to your inbox and click on the verification link we sent you.
Make sure to check your "spam" folder or your "promotions" tab (if you have Gmail).
If you're still having trouble, then message us at

You are already logged in

It looks like you are already logged in to SpinupWP.

Please log out of this account to continue.

Registration Successful

Thanks for registering for a new
SpinupWP account.

Before getting started, could you verify your email address by clicking on the link we just emailed to you?


Free Trial

Start Your 7-Day Free Trial

No credit card required. All features included.

By signing up to SpinupWP, you agree to our Terms and Conditions.
For privacy related information, view our Privacy Policy.