Installing a Secured WordPress Website Using Debian 11 Linux, NGINX & Let’s Encrypt SSL

WordPress is one of the most used, open-source blogging platforms in the entire world. It powers nearly 34% of the world-wide web and it is easily customizable to fit your specific needs, whether those needs are simply blogging or running a large catalog e-commerce platform.

The requirements for a WordPress install are simple. You need a server environment, an operating system to run on, a framework for organizing HTML/CSS, a database for managing queries and finally a web engine that powers it all. This is what is known as a ‘stack’ or collection of programs made for a specific purpose.

The Overview

Before we begin, for those of you who are new to the server world that want to understand how and why things work together, I will discuss the details of the install. If you just want to get straight away to the install, jump to the installation sections below.

Our instance of WordPress is going to be running on Digital Ocean’s lowest tier droplet, which has 25GB SSD storage, 1GB of system memory and 1TB of monthly bandwidth, more than enough for our usage. It is going to be utilizing a LEMP stack (Debian 11 – NGINX – MariaDB – PHP 8.0) and is also going to have UFW (uncomplicated firewall), Fail2Ban, Postfix and a free SSL Certificate from Let’s Encrypt. We will create a swap partition of 2GB to handle memory spikes and also enable a strict set of rules to prevent multiple unauthorized login attempts

The Server Environment:

A server environment is a physical (bare-metal) or virtual private system (VPS) that provides the user with a computer capable of running software. There are a range of providers on the internet that can set you up with a solid VPS but our favorite has been Digital Ocean. They are the host of this very website and are also offering $100 of credit to new users. Of all the VPS providers I have tried (Linode, Vultr, AWS, Google Cloud, Etc.) Digital Ocean has been the fastest, most reliable and best value per dollar.

The Linux:

For our Operating System (OS) we are using Linux, specifically in the Debian flavor. Debian is known for being extremely stable and providing a real simple package manager that allows quick & easy installations. We will be using the latest Debian 11 Bullseye.

The Server Engine:

Traditionally, the web-server of choice for WordPress has been Apache. Apache is the number 1 HTTP server on the internet. It has been the king in main production servers for over 20 years. However, we have found NGINX, pronounced Engine-X, to be more powerful and more robust, as it was initially designed as a reverse proxy server. It utilizes a simple block structure for easy syntax and is highly extensible, providing a more solid solution for individual blogs and websites. Both Apache & NGINX are created under the Open-Source License, and can be used freely.

The Framework:

PHP, or Hypertext Pre-processor, is a scripting language used to help run websites and blogs all over the world. It is fast, flexible and has a number of uses beyond just web-servers. For this install, we will be using PHP version 8.0.

The Database:

WordPress requires you to be connected to a server database that catalogs and stores important information about your website. There are two great solutions for a database and those are MySQL and MariaDB. Do note, that MySQL is also used as a term to describe the database itself. Both MySQL and MariaDB act identically in terms of operation and install, however, we have found MariaDB to have a smaller footprint. This is the primary reason we are going with MariaDB.

Part 01 – Core Installations

The core installations process is simple. In this part we are going to install most of the core programs required for our needs. If you are experienced with running scripts, you can download our simple WordPress.sh script that sets up everything except for the last final configurations. If you would like to instead do things manually, please follow along and take your time. Please note, we are going to be presenting this information assuming that you are running commands on the terminal as the root user, otherwise you need to preface your command prompts with sudo . It is recommended to only use the root user for installation and to create a secondary user for maintenance.

Point Your Domain Name to Your Server Address

Before installing the core programs, you should configure your domain name to forward to your VPS. Your VPS has a numbered IPv4 address that looks something like this: 192.168.1.1 From your hosting provider’s dashboard, go to your DNS settings and change your A name record to the physical IP address of your server. This is often times accomplished by simply entering the ‘@’ symbol for the name and the IPv4 Address as your route. If you can, you can also reduce the TTL time to 300 seconds. This will cause your DNS changes to go into effect in 300 seconds (5 minutes). Next you need to configure name servers for your domain name. In our case, Digital Ocean is our hosting provider and they look something like: ns1.digitalocean.com From your domain name provider, go to your DNS settings for the domain name you have and set your name servers to your hosting provider. There are usually 3 slots and should all be filled with sequential prepended abbreviations like: ns1, ns2, ns3 Now that things are set-up it could take a few minutes to propagate across the web.

Update the System

The first thing anyone should do when dealing with a new VPS or bare metal instance is to ensure that your programs and OS are up to date. To do this, we can run:

apt-get update
apt-get upgrade
apt-get dist-upgrade

For most fresh Debian installs, you will find that Apache2 is already installed. Since we’re going to be using NGINX, we can go ahead and remove it and search for any remnants with:

apt-get remove apache2
whereis apache2

After doing the ‘whereis’ search you can further remove any queried locations with

rm -rf 'path/to/apache2/remains'

Make sure to change ‘path/to/apache2/remains’ with your actual path to any apache2 remains.

Install Essential Programs

Next, we can begin installing our essential programs. I’m also going to install a few programs that will help me when I maintain the system. These are items such as htop for monitoring usage and ranger for visualizing the file system when looking for certain files.

apt-get install net-tools sudo wget curl vim mariadb-server speedtest-cli fish ca-certificates apt-transport-https fail2ban certbot ufw git ranger caca-utils highlight atool poppler-utils mediainfo lsb-release nginx python-certbot-nginx mailutils postfix

This installs a majority of the core programs needed but PHP needs to be installed a little differently. We can install it by adding the SURY repository and then installing like any other program.

sh -c 'echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list' 
wget -qO - https://packages.sury.org/php/apt.gpg | sudo apt-key add -
apt-get update
apt install -y php8.0 php8.0-cli php8.0-soap php8.0-mbstring php8.0-geoip php8.0-xml php8.0-curl php8.0-mysql php8.0-common php8.0-json php8.0-fpm php8.0-cgi php8.0-memcached php8.0-gd php8.0-imagick

Now we will want to adjust some settings that will optimize our performance and eliminate some common WordPress issues with PHP limits. We are going to adjust a few parameters by entering the following:

sed -i "s/memory_limit = .*/memory_limit = 768M/" /etc/php/8.0/fpm/php.ini
sed -i "s/upload_max_filesize = .*/upload_max_filesize = 128M/" /etc/php/8.0/fpm/php.ini
sed -i "s/zlib.output_compression = .*/zlib.output_compression = on/" /etc/php/8.0/fpm/php.ini
sed -i "s/max_execution_time = .*/max_execution_time = 18000/" /etc/php/8.0/fpm/php.ini
sed -i "s/max_file_uploads = .*/max_file_uploads = 100/" /etc/php/8.0/fpm/php.ini

By doing this, we can easily manage our PHP infrastructure and ensure that we should not run into issues later. Feel free to adjust the variables as you see fit. The memory on our VPS is only 1GB or 1024M so be careful to not set the memory_limit to anything higher than that.

Configure Ranger File Viewer

I absolutely love utilizing the ranger file viewer system and highly recommend using it to navigate your server’s files. It makes visualizing the entire Linux filesystem much easier and provides a fun way to find critical files and directories. To enable the default configuration files we simply enter in:

ranger --copy-config=all

Viola, it’s configured. Now you can enter ranger in your terminal and visually navigate through your VPS. This is great for beginners and experienced users alike.

Enable Essential Services

Now that we have our core programs installed and ready, we need to enable the services that WordPress is going to be using. We need to start NGINX, PHP, MariaDB and UFW. We can do that by entering the following commands:

systemctl stop nginx
systemctl enable nginx
systemctl start nginx
systemctl stop php7.3-fpm
systemctl enable php7.3-fpm
systemctl start php7.3-fpm 
ufw allow ssh 
ufw allow http
ufw allow https 
ufw enable
systemctl stop mysql
systemctl enable mysql
systemctl start mysql

Notice that we also added some rules to our firewall. UFW or Uncomplicated FireWall, is a nice program for limiting access to your server. Traffic can only come from SSH, HTTPS and HTTP. This drastically reduces the entry points for possible attacks and keeps your VPS more secure. Make sure to always allow SSH as failing to do so can result in locking yourself out of your VPS.

Part 02 – MySQL Configuration

With the essentials out of the way we need a database to store information and run queries for data. Since we’ve already installed it and enabled the service, we can run the MySQL configuration process by entering:

mysql_secure_installation

You can enter Y for all questions. Make sure to use a secure password and to store it safely. After you’ve set up MySQL’s installation, you can optionally secure it by running:

use mysql;
update user set plugin='' where User='root'; 
flush privileges; 
exit;

This allows only the root user to log into MySQL. Now that we’ve installed MySQL we can set up the database for our WordPress install.

CREATE DATABASE wpdb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'password'; 
GRANT ALL PRIVILEGES ON wpdb.* TO 'admin'@'localhost'; 
FLUSH PRIVILEGES; 
EXIT;

Note that there are 3 variables at play here. There is the database name, which we input as 'wpdb' . There is the user, which we chose as 'admin'@'localhost' . And lastly, there is the 'password' which is something that you need to choose and store. You can make these anything you would like, but I would suggest something that you can easily remember when you need to look back at it later in time.

Part 03 – Configure NGINX & Let’s Encrypt SSL

Now that WordPress is installed we need to configure NGINX to run it. We can do so by editing the NGINX files that use block structuring.

nano /etc/nginx/sites-available/website.com

This creates an empty file in which your configuration syntax can be entered. Below you will find the configuration we will use for our installation of NGINX. You can copy and paste it into nano, the text editor used in the previous command. After you have done so, you can replace website by using Nano’s replace command ctrl+\and inputting your domain name.

server {
listen 80;
listen [::]:80;
root /var/www/wordpress;
index  index.php index.html index.htm;
server_name  website.com www.website.com;
include snippets/well-known.conf;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /var/www/wordpress;
index  index.php index.html index.htm;
server_name www.website.com;
ssl_certificate /etc/letsencrypt/live/website.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/website.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/website.com/chain.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
add_header Strict-Transport-Security "max-age=31536000;  includeSubDomains";
include snippets/well-known.conf;
return 301 https://website.com$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /var/www/wordpress;
index  index.php index.html index.htm;
server_name website.com;
ssl_certificate /etc/letsencrypt/live/website.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/website.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/website.com/chain.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 30s;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
add_header Strict-Transport-Security "max-age=31536000;  includeSubDomains";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
include snippets/well-known.conf;
client_max_body_size 100M;
autoindex off;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

With this NGINX configuration we can now enable it via:

ln -s /etc/nginx/sites-available/website.com /etc/nginx/sites-enabled/
systemctl restart nginx

Let’s Encrypt SSL Certificate Creation

NGINX is now configured but it’s been set to only utilize HTTPS traffic. Nothing will work without first obtaining a SSL certificate. We do can so but utilizing certbot which is a program that grabs a certificate from Let’s Encrypt.

openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
certbot certonly --agree-tos --email admin@website.com --webroot -w /var/www/html -d website.com -d www.website.com

Certificates last 90 days and need to be renewed. We can automate this process with cron , an automated process handler. Running the certbot command in the previous prompt should have already created this file but you can check by running:

cat /etc/cron.d/certbot

Part 04 – Install WordPress

Finally we can install WordPress onto our VPS. To install the latest version of WordPress, we will run:

mkdir -p /var/www/html/website.com
wget -q -O - http://wordpress.org/latest.tar.gz | sudo tar -xzf - --strip 1 -C /var/www/html/site
chown www-data: -R /var/www/html/website.com
chmod -R /var/www/wordpress/

Make sure to replace 'website.com' with the name of your website. This is the primary location where your core WordPress files will reside. Once WordPress is installed, you can access it via your domain name. The configuration is now access via your web-browser and it simply asks for your MySQL database, user and password. Once it’s complete you can access and customize your WordPress website.

To Summarize

With all of the technical commands and configuration done, you should now have a functioning WordPress website. It’s important to understand how you installed everything and where your configuration files are. Keep a notepad or note app handy to keep track of your usernames, database names and passwords. If anything ever happens with your server the only person who will know how to fix it best it likely you. I like to keep this post updated to the latest versions of each program as sometimes they work different with new releases.

Professional Hobbyist. Fitness Enthusiast. Photography Nerd. Computer Tinkerer. Business Entrepreneur. Game Dork. D&D Noob.

Getting Started with SSH (Secure Shell) – A Beginner’s Guide

View Comments

There are currently no comments.

The Key to Creative Freedom
Next Post