Wordpress

How to install and configure Wordpress on Debian with Nginx and Certbot.

This will assume the following:

  • We'll start with a base install of Debian on Linode
  • We'll point a valid domain name (newsite.domainname used as example) to it
  • We'll use a valid TLS certificate
1. Make sure host is updated
apt update && apt upgrade
2. Install, start and enable Nginx

Install it:

apt install nginx

Start and enable it (i.e. make sure it starts on boot):

systemctl start nginx
systemctl enable nginx
3. Install PHP

Note, this only installs the PHP FastCGI Process Manager (FPM) and the CLI, and does not install Apache.

apt install php-fpm php-cli php-mysql

Install other PHP extensions:

apt install php-curl php-fpm php-bcmath php-gd php-soap php-zip php-curl php-mbstring php-mysqlnd php-gd php-xml php-intl php-zip
4. Install MariaDB Database Server
apt install mariadb-server mariadb-client

And start and enable it:

systemctl start mariadb
systemctl enable mariadb
5. Secure MariaDB

Run the secure script

mysql_secure_installation

The following questions should be answered "Y":

Remove anonymous users? [Y/n]: Y
Disallow root login remotely? [Y/n]: Y
Remove test database and access to it? [Y/n]:  Y
Reload privilege tables now? [Y/n]:  Y

Restart the DB server:

systemctl restart mariadb

Log in to the DB server:

mysql -u root -p
6. Create Wordpress database

Run the following commands to create and secure the Wordpress database. Replace new_username and new_password as appropriate. If multiple websites on a host, use something like wpuser_sitename for the user:

CREATE DATABASE wordpress_db;
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'new_username'@'localhost' IDENTIFIED BY 'new_password';
FLUSH PRIVILEGES;
EXIT
7. Download and configure Wordpress

Download Wordpress and place it in the web root.

wget https://wordpress.org/latest.zip
unzip latest.zip
mv wordpress /var/www/html/newsite.domainname

Modify the Wordpress config:

cd /var/www/html/newsite.domainname/
cp wp-config-sample.php wp-config.php
nano wp-config.php

Set the following parameters:

/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress_db' );

/** MySQL database username */
define( 'DB_USER', 'new_username' );

/** MySQL database password */
define( 'DB_PASSWORD', 'new_password' );

/** MySQL hostname */
define( 'DB_HOST', 'localhost' );

Press CTRL-O, CTRL-X to save and exit nano.

Change permissions for the Wordpress directory:

chown -R www-data:www-data /var/www/html/newsite.domainname/
8. Configure Nginx

Create and edit a new config file:

nano /etc/nginx/sites-available/newsite.domainname

The file should have the following contents:

server {
  listen 80;

    # server_name can have multiple values.
    server_name newsite.domainname www.newsite.domainname;
    root   /var/www/html/newsite.domainname;
    index  index.php;

    access_log /var/log/nginx/newsite.domainname.access.log;
    error_log /var/log/nginx/newsite.domainname.error.log;

    client_max_body_size 100M;

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

    location ~ \.php$ {
         include snippets/fastcgi-php.conf;
         fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
         include fastcgi_params;
         fastcgi_intercept_errors on;
    }
}

Add a symlink to sites-enabled and remove the default site:

cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/newsite.domainname
rm /etc/nginx/sites-enabled/default

Restart Nginx

systemctl restart nginx
9. Configure TLS

Make sure that any domain names listed in the Nginx configuration point to the Wordpress server (both A records and AAAA records if IPv6 is enabled). Then install certbot:

apt install python3-certbot-nginx

Run certbot

certbot --nginx 

Answer the questions, which are self-explanatory. The renew command command seems to be added into the systemd times. Verify with:

systemctl list-timers

This should show this:

NEXT                        LEFT     LAST                        PASSED        UNIT            ACTIVATES
--------------------------------------------------------------------------------------------------------------
[...]
Wed 2025-07-23 05:54:20 UTC 9h left  Tue 2025-07-22 15:10:12 UTC 5h 29min ago  certbot.timer   certbot.service
[...]

That should be all. The site should be accessible from https://newsite.domainname