In the previous step, I showed you how to install Nginx, PHP 8.0, WP-CLI, and MySQL, which formed the foundations of a working Linux web server. In this step, I will guide you through the process of deploying your first HTTPS enabled WordPress site with HTTP/2 support.
HTTP/2
HTTP/2 is the latest version of the HTTP protocol, which is the communication protocol used whenever you interact with a website. HTTP/2 can provide a significant improvement to the load time of your sites. I wrote a complete article on HTTP/2, 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.
HTTPS
HTTPS is an extension for HTTP/2 which secures the 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 might be 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 factor in ranking your website in search results and also due to the introduction of Let’s Encrypt, which provides free SSL certificates.
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 the IP address of your server.
Now let’s install Certbot, the free, open source tool for managing Let’s Encrypt certificates:
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 can now 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 huypham.work -d www.huypham.work
After entering your email address and agreeing to the terms and conditions, the Certbot client will generate the requested certificate. Make a note of where the certificate file fullchain.pem
and key file privkey.pem
are created, as you will need them later.
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/huypham.work/fullchain.pem
Key is saved at: /etc/letsencrypt/live/huypham.work/privkey.pem
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, our Nginx configuration 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.
When we installed Nginx you may remember we created a php.info
file in the /var/www/html
directory. This was because this is the default document root that Nginx configures. However, we want to make use of a more manageable directory structure for our WordPress configuration.
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:
huypham@pluto:/var/www# ls huypham.work
logs public
The logs
directory is where the Nginx access and error logs will be stored, and the public
directory will be the site’s root directory, which will be publicly accessible.
Begin by creating the required directories and setting the correct permissions:
mkdir -p huypham.work/logs huypham.work/public
chmod -R 755 huypham.work
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 site configuration. Naming this the same as the site’s root directory will make server management easier when hosting a number of sites:
sudo nano huypham.work
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 certificate and certificate key 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;
server_name huypham.work;
ssl_certificate /etc/letsencrypt/live/huypham.work/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/huypham.work/privkey.pem;
access_log /var/www/huypham.work/logs/access.log;
error_log /var/www/huypham.work/logs/error.log;
root /var/www/huypham.work/public/;
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/php8.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.huypham.work;
ssl_certificate /etc/letsencrypt/live/huypham.work/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/huypham.work/privkey.pem;
return 301 https://huypham.work$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name huypham.work www.huypham.work;
return 301 https://huypham.work$request_uri;
}
This is a bare-bones server block that informs Nginx to serve the huypham.work
domain over HTTPS. The www
subdomain will be redirected to huypham.work
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 file 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 a symbolic link (or symlink, think of it as a shortcut) in the sites-enabled
directory, linked to the configuration file in sites-available
.
To enable the newly created site, symlink the file that you just created into the sites-enabled
directory, using the same filename:
sudo ln -s /etc/nginx/sites-available/huypham.work /etc/nginx/sites-enabled/huypham.work
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 fails, recheck the syntax of the new configuration file. If the test passes, reload Nginx:
sudo service nginx reload
ashley@pluto:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
ashley@pluto:~$ sudo service nginx restart
* Restarting nginx [ OK ]
ashley@pluto:~$
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 database and database user 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.
Log into MySQL with the root user.
sudo mariadb
You’ll be prompted to enter the password which you created when setting up MySQL.
huypham@pluto:~# sudo mariadb
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 10091
Server version: 10.6.16-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.04
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
Once logged in, create the new database, replacing ashleyrich_com
with your chosen database name:
CREATE DATABASE huypham_work CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;
Next, create the new user using the following command, remembering to substitute username
and password
with 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 your database only, like so:
GRANT ALL PRIVILEGES ON huypham_work.* 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:
FLUSH PRIVILEGES;
Finally, you can exit MySQL:
exit;
Now that you have a new database, it’s time to install WordPress.
Installing WordPress
You could install WordPress manually by using something like cURL
or wget
to download the latest.zip
or latest.tar.gz
archive, extract it, and then follow the WordPress installer in a web browser. As we already have WP-CLI installed, we’ll be using that instead.
Start by navigating to the site’s public directory:
cd ~/huypham.work/public
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. Make sure to use the database details you set up in the previous step:
wp core config --dbname=huypham_work --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=https://huypham.work --title='Huy Pham' --admin_user=huypham [email protected] --admin_password=password
You should see the 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 step 5.
You should now be able to visit the domain name in your browser and be presented with a default WordPress installation:
![huypham.work](https://huypham.work/wp-content/uploads/2024/05/huypham-work-1024x808.jpg)
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:
- Add the relevant DNS records to the domain.
- Obtain an SSL certificate.
- Navigate to your home directory and create the required directory structure for the new site (
logs
andpublic
). - 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. - Symlink the config file to the
sites-enabled
directory to enable the site and restart Nginx - Create a new database and MySQL user.
- 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.