If you want to run single WordPress site, best to use a WordPress hosting offer. If you want to run 5 WordPress sites, it is often more economical to get a VPS and configure multi-site. But you will face much more install and admin work, especially if you avoid using tools like Plesk etc.

On a fresh Debian 10 server install, I started with:

apt update; apt upgrade
—> set timezone
timedatectl set-timezone Europe/Berlin
—> verify status of timers
systemctl list-timers
—> install zip & unzip for Duplicator (WordPress plugin)
apt install zip unzip

Make sure to run:

apt update
apt list --upgradable

regularly and then decide what to do. On a Debian server install, unattended updates are disabled.

Next install webserver and php. I opted for nginx and php-fpm.

apt install nginx
—> test install
nginx -t
—> install PHP with FPM and modules for WordPress
apt install php-fpm php-mysql php-curl php-xml php-gd php-mbstring php-zip
—> fix nginx gateway timeout 504 error for Duplicator
vi /etc/nginx/snippets/fastcgi-php.conf
fastcgi_read_timeout 900;

Next install and configure the database engine. Here I opted for MariaDB.

—> install and secure MariaDB
apt install mariadb-server
—> create databases and database accounts for WordPress
for each site do (check the quotes !!)

GRANT ALL ON site1_db.* TO ‘site1_user’@‘’ IDENTIFIED BY ‘site1_pw’;

—> check database login
mariadb -u site1_user -h -p (and enter site1_pw)
—> verify all database accounts
mariadb (as root)
SELECT user,authentication_string,plugin,host FROM mysql.user;
—> My MariaDB updated settings for WordPress
vi /etc/mysql/mariadb.conf.d/50-server.cnf
bind-address =
innodb_buffer_pool_size = 512M 
query_cache_size = 64M

MariaDB defaults to unix permissions for root logins (using the unix_socket plugin). So no need to set a root password on MariaDB, just run mariadb as root. I also use instead of localhost for the accounts, to avoid any issues with ipv6, dual stack etc. Make sure to set bind-address to as well.

This is my nginx config for site1. You need one for site2 as well. nginx configs go into /etc/nginx/sites-available with softlinks from /etc/nginx/sites-enabled. Https is not yet enabled, certbot takes care of that later.

server {
    listen [::]:80;
    listen 80;
    #include snippets/ssl-params.conf;
    root /var/www/site1;
    index index.php;
    server_name site1.com www.site1.com;

    location / {
    # First attempt to serve request as file, then as directory
        try_files $uri $uri/ /index.php?$args;

    # pass PHP scripts to FastCGI server
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # with php-fpm socket
        fastcgi_pass unix:/run/php/php7.3-fpm.sock;

    location ~ /\.ht {
        deny all;

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;

Now you can create the root directories for each site and do some tests.

mkdir /var/www/site1
mkdir /var/www/site2
—> test PHP
vi /var/www/site1/info.php
—> set ownership 
chown -R www-data:www-data /var/www/site1 /var/www/site2

For now, I set website file and directory ownership to www-data, basically the default security model where both nginx and php-fpm run as user www-data. I’ve described a more secure solution for multi-site here.

Next step is getting a free Letsencrypt certificate and setup https with Certbot as snap. I decided to use the snap version of certbot instead of the certbot package from debian. That way, certbot is not impacted by debian updates, since the snap provides a containerised environment for certbot.

apt install snap
snap install core; snap refresh core
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot
—> show all snaps
snap list
—> get and install certificates for each site
certbot --nginx
—> test renewal without changing anything
certbot renew --dry-run
—> show certificates
certbox certificates
—> renewal timer check
systemctl list-timers

The certbot command will change and configure each nginx config file to https and add a redirect from http to https. Time to test again and verify the certificate in your browser.

Next up, download and copy WordPress to site1 and site2.

wget https://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
cd wordpress
cp -R * /var/www/site1
cp -R * /var/www/site2
chown -R www-data:www-data /var/www/site1 /var/www/site2

You can start the WordPress install by accessing it at https://site1.com/wp-admin/install.php for site1 and at https://site2.com/wp-admin/install.php for site2.

Since you’re running a https site already, WordPress will configure your site with https. Your site should now score A+ on the SSL Labs test with the default certbot settings…

Leave a Reply

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

46 − 44 =