One well-tuned server can host many WordPress sites. Each site gets its own folder, Nginx server block, database and database user, so a problem on one doesn’t spill into the others. Replace example.com with your domain throughout, and repeat steps 1–6 for each site.
Before you start
- A LEMP stack:
sudo apt install nginx mysql-server php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-intl php8.3-imagick unzip - The domain’s A record pointing at the server
- A sudo user
Step 1 – Create the server block
sudo nano /etc/nginx/sites-available/example.com.confserver {n listen 80;n listen [::]:80;n server_name example.com www.example.com;n root /var/www/example.com;n index index.php index.html;nn client_max_body_size 64m;nn location / {n try_files $uri $uri/ /index.php?$args;n }nn location ~ u005c.php$ {n include snippets/fastcgi-php.conf;n fastcgi_pass unix:/run/php/php8.3-fpm.sock;n }nn # Never run PHP from uploads, never serve hidden filesn location ~* ^/wp-content/uploads/.*u005c.php$ { deny all; }n location ~ /u005c.(?!well-known) { deny all; }n location = /xmlrpc.php { deny all; }nn location = /favicon.ico { log_not_found off; access_log off; }n location = /robots.txt { log_not_found off; access_log off; }n}Using another PHP version? Change php8.3-fpm.sock to match (ls /run/php/). The Nginx Server Block Generator writes this file for you, HTTPS included.
Step 2 – Create the database and user
sudo mysqlCREATE DATABASE example_wp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;nCREATE USER 'example_user'@'localhost' IDENTIFIED BY 'a-long-random-password';nGRANT ALL PRIVILEGES ON example_wp.* TO 'example_user'@'localhost';nFLUSH PRIVILEGES;nEXIT;Use a different database and user for every site, and a long random password – the Password Generator can make one.
Step 3 – Download WordPress into the site folder
cd /tmpnwget https://wordpress.org/latest.tar.gzntar -xzf latest.tar.gznsudo mkdir -p /var/www/example.comnsudo cp -a /tmp/wordpress/. /var/www/example.com/nrm -rf /tmp/wordpress /tmp/latest.tar.gzStep 4 – Configure wp-config.php
cd /var/www/example.comnsudo cp wp-config-sample.php wp-config.phpnsudo nano wp-config.phpSet DB_NAME, DB_USER and DB_PASSWORD, replace the salt lines with fresh ones from api.wordpress.org/secret-key, and change $table_prefix from wp_ to something unique such as ex7_.
Step 5 – Set ownership and enable the site
sudo chown -R www-data:www-data /var/www/example.comnsudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/nsudo nginx -t u0026u0026 sudo systemctl reload nginxStep 6 – Add HTTPS with Let’s Encrypt
sudo apt install certbot python3-certbot-nginxnsudo certbot u002du002dnginx u002du002dredirect -d example.com -d www.example.comCertbot edits the server block for HTTPS and renews the certificate automatically.
Step 7 – Run the WordPress installer
Open https://example.com, choose a language, then create the administrator account – use a unique username, not “admin”.
Isolate sites further
For stronger separation give each site its own PHP-FPM pool running as its own Linux user (a file in /etc/php/8.3/fpm/pool.d/ with user = example and its own socket). A compromised plugin on one site then can’t read the others’ files.

