in , , ,

Installing WordPress On Debian 11 VPS.. Quick Start Guide

Install WordPress On Debian 11

We will try to install WordPress CMS on Debian 11 VPS, we will install and configure Nginx as a reverse proxy, Apache as a web server, PHP Packages, and MariaDB database server.

Web Technology To Use

As described in the next figure, we will use:

wordpress on debian, mariadb nginx apache

  1. Nginx as a reverse proxy (listen Ports 443, 80)
  2. Apache as a web-server (listen Port 81)
  3. WordPress CMS Our PHP Web Application
  4. MariaDB Database Server

We will consider an example domain name:, with server IP-Address:

But while you apply this tutorial for your project, do not forget to replace your domain name and IP-Address with yours.

Configure The Debian 11 VPS/Server

We will:

  1. Update our server.
  2. Install required packages ( i.e. MariaDB, Nginx, Apache, and PHP ).
  3. Add The Domain User To The System.
  4. Install WP-CLI
  5. Install WordPress
  6. Set WordPress Files Permission
  7. Firewalls for all ports except HTTP(S) and SSH.
  8. Install fail2ban to harden SSH access.

Step1: Update Our Debian 11 VPS/Server

# apt update
# apt upgrade

Step2: Installing And Configure Nginx As A Reverse Proxy

Installing Nginx

# apt install nginx
# systemctl enable nginx
# systemctl start nginx

Configure Nginx As A Reverse Proxy

Create the domain config file in the path: /etc/nginx/sites-available/

# Define Your Server To Listen To Your Plubic IP ADDRESS && HTTP Port 80
# Do not forget to replace Server Public IP-Address and domain name with yours.
# If you want to redirect www to non-www domain, uncomment the next server block.
#server {
#  listen;
#  server_name;
#  access_log off;
#  return 301$request_uri;
server {
  listen default;

  # capture the logs
  access_log /var/log/nginx/;

  # Adjustment Headers
  add_header X-Frame-Options SAMEORIGIN;
  add_header X-Content-Type-Options nosniff;
  add_header Access-Control-Allow-Origin *;
  add_header Access-Control-Allow-Credentials true;

  #Enable and configure GZIP
  gzip on;
  gzip_static on;
  gzip_comp_level    9;
  gzip_min_length    256;
  gzip_proxied       any;
  gzip_vary          on;
  gzip_buffers           16 8k;
  gzip_http_version  1.1;
  proxy_http_version 1.1;
    # text/html is always compressed by gzip module

  # To allow POST on static pages
  error_page 405 =200 $uri$is_args$args;
  location / {
    # Pass Every request to Apache at the Port 81
    proxy_pass               ;
    # Adjustement reverse proxy headers.
    proxy_read_timeout                 640;
    proxy_connect_timeout              640;
    proxy_redirect                     off;
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto http;
    proxy_set_header X-Forwarded-Port  80;
    proxy_buffers                      16 32k;
    proxy_buffer_size                  64k;
    proxy_request_buffering off;
    proxy_buffering off;
# Enable Caching Static files...
  location ~*  \.(jpg|jpeg|png|gif|ico|css|js|pdf|ttf|woff|eot|bz2|gz|woff2|svg|bmp)$ {

                proxy_pass               ;
                proxy_read_timeout                 640;
                proxy_connect_timeout              640;
                proxy_redirect                     off;

                proxy_set_header Host              $host;
                proxy_set_header X-Real-IP         $remote_addr;
                proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto http;
                proxy_set_header X-Forwarded-Port  80;
                proxy_buffers                      32 64k;
                proxy_buffer_size                  128k;
                proxy_request_buffering off;
                proxy_buffering off;
                access_log off;
                log_not_found on;
                # Extend Browsers Caching Time for static file
                expires 60d;


Go to the directory /etc/nginx/sites-enabled/, then create a symbolic link for our domain config file as the following, and restart the Nginx Daemon.

# cd /etc/nginx/sites-enabled/
# ln -s /etc/nginx/sites-available/ ./
# systemctl restart nginx
# systemctl status nginx

Step3: Install And Configure Apache Web Server

Install Apache Web Server

# apt install apache2

Configure Apache

Configure The Apache to listen to port 81 at the localhost, Edit the file /etc/apache2/ports.conf, and set host and port to Listen as the following

# vim /etc/apache2/ports.conf
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf


# Listen 443
# Listen 443

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Configure Our Domain Virtual Host

Go to the directory /etc/apache2/conf-available, and Create our domain virtual host file with the following configs

# cd /etc/apache2/sites-available/
# vim
<VirtualHost *:81>
      DocumentRoot /home/wordpresslab/public_html
      ServerAlias *
      ErrorLog ${APACHE_LOG_DIR}/wordpress-lab.error.log
      CustomLog ${APACHE_LOG_DIR}/wordpress-lab.access.log combined
<Directory "/home/wordpresslab/public_html">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Require all granted

Go to the directory /etc/apache2/conf-enabled/, and create a symbolic link to our domain virtual  host file, as the following

# cd /etc/apache2/conf-enabled/
# ln -s /etc/apache2/conf-available/ ./

Now we can create our domain user, and make the public web directory public_html same as the DocumentRoot Value, then we can start the Apache webserver

Step4: Add The Domain New User To The System

We need to add a new user to the system, which will present our domain.

# adduser wordpresslab

Create the public web directory, public_html into the new user home directory /home/wordpresslab/

# mkdir -p /home/wordpresslab/public_html

Start, and check the status of the Apache Webserver

# systemctl start apache2
# systemctl status apache2

Step5: Install and Configure MariaDB The Database Server

Install MariaDB Server And Client

# apt install mariadb-server mariadb-client
# systemctl enable mariadb

Apply Database Basic Security

After installing the Database Server, we need to apply the basic security configuration step.

We need to run the command mysql_secure_installation and Interact with outputs as the following:

  1. Enter current password for root (enter for none): [Press Enter With Empty Value]
  2. Switch to unix_socket authentication [Y/n] [Answer n]
  3. Change the root password? [Y/n] [Answer Y & Enter your database root password]
  4. Remove anonymous users? [Y/n] [Answer Y]
  5. Disallow root login remotely? [Y/n] [Answer Y]
  6. Remove test database and access to it? [Y/n] [Answer Y]
  7. Reload privilege tables now? [Y/n] [Answer Y]
# mysql_secure_installation


In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.

You already have your root account protected, so you can safely answer 'n'.

Switch to unix_socket authentication [Y/n] n
... skipping.

You already have your root account protected, so you can safely answer 'n'.

Change the root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y
... Success!

Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y
... Success!

Cleaning up...

All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

Create Database And User

Log in to the database server as database root (we set a database root password in the previous step), as below, and replace PassWord with yours.

We will create a new database named wordpress_db, and a new database user named wordpress_db_user with wordpress_db_password.

You can replace the values with yours, and then flush MariaDB privileges as the following.

# mysql -uroot -pPassWord
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 52
Server version: 10.5.12-MariaDB-0+deb11u1 Debian 11

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)]> create database wordpress_db;
Query OK, 1 row affected (0.000 sec)

MariaDB [(none)]> GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wordpress_db_user'@'localhost' IDENTIFIED BY 'wordpress_db_password';
Query OK, 0 rows affected (0.001 sec)

Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]>

Step6: Install PHP

# apt install php libapache2-mod-php php-cgi php-common php-mbstring php-zip php-net-socket php-gd php-mysql php-bcmath php-json php-curl php-intl php-soap php-xml php-xmlrpc unzip wget git

Step7: Install WP-CLI

We will install WordPress using WP-CLI the command-line interface for WordPress, we can install WP-CLI as the following

# curl -O
# chmod +x wp-cli.phar
# mv wp-cli.phar /usr/local/bin/wp

Step8: Install WordPress CMS

Go to our web public directory /home/wordpresslab/public_html, and start the WordPress installation process as the following:

PS: as we are in the root terminal, we will append the suffex “–allow-root” flag at the end of each WP-CLI command.

We will:

  1. Download The latest WordPress core release.
  2. Adjustment The WordPress Config File w-config.php, With Database and WebSite Information
  3. Install The WordPress

As the following:

# wp core download --allow-root
Downloading WordPress 5.9.2 (en_US)...
md5 hash verified: b5e9c3b8dfd767d55c3797c2eae0f57d
Success: WordPress downloaded.

# wp core config --dbname=wordpress_db --dbuser=wordpress_db_user --dbpass=wordpress_db_password --dbhost=localhost --dbprefix=wp_ --allow-root
Success: Generated 'wp-config.php' file.

# wp core install --url="" --title="WordPress Lab" --admin_user="Admin" --admin_password="AdminPassWord" --admin_email="" --allow-root
Success: WordPress installed successfully.

Step9: Set The WordPress File Permissions

We will do the following:

Append our domain user wordpresslab to the Apache Group www-data

# usermod -a -G www-data wordpresslab

Change the public_heml directory and contents owner and permissions

Go to the domain user home directory /home/wordpresslab and run the following commands

# cd /home/wordpresslab
# chown -R wordpresslab.www-data public_html
# chmod -R 2750 public_html
# chmod -R 2640 public_html/wp-config.php
# chmod -R 2770 public_html/wp-content/

We Can Access our WordPress website using IP-Address or our domain name from the web browser

wordpress debian install

Step10: Allow Bypass FTP For WordPress Config

Allow install and download files directly without using FTP, we can do it by adding define(‘FS_METHOD', ‘direct'); line to the wp-config.php file.

# vim /home/wordpresslab/public_html/wp-config.php
define( 'WP_DEBUG', false );

/* Add any custom values between this line and the "stop editing" line. */
define('FS_METHOD', 'direct');

/* That's all, stop editing! Happy publishing. */

Step11: Install Fail2ban, Allow & Configure Firewall

Install And Configure UFW

We will Install UFW – Uncomplicated Firewall and configure it to bypass HTTP(s) and SSH Ports.

# apt install ufw

# ufw allow ssh

# ufw allow http

# ufw allow https

# ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

# ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443                        ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

Install And Enable Fail2Ban

Harden SSH access by installing and enabling Fail2ban

# apt install fail2ban

# systemctl enable fail2ban

Step12: Enable Nginx SSL 

To enable SSL access to your WordPress site, you will need to modify the Nginx config file we created above to the one located here: its enable SSL, and the file is the same lab and example we created in this article. and no need to change Apache.

And you can create your self signed SSL in simple steps as described here: How to generate your self-signed SSL certificate in 3 Steps for Linux

What do you think?

Leave a Reply

Your email address will not be published. Required fields are marked *

      connecting tor network the onion router

      Connecting Tor Network Using Privoxy On Ubuntu 20.04

      Arch Linux logo

      Install WordPress On Arch Linux VPS… Quick Start Guide