Web hostingWritten by GLWS25 min readUbuntu 24.04 LTS / AlmaLinux 9
Commands run on your server unless a section says otherwise. Replace example usernames, addresses and paths with your own values. Keep a working session open when changing remote access.

Before you start

This guide builds a classic LEMP stack (Linux, Nginx, MariaDB, PHP) and installs WordPress on it. You need a domain pointing at the server, a sudo account and a firewall that allows ports 80 and 443. If you would rather not run the server yourself, shared hosting on this site handles all of this for you.

Complete the database guide for MariaDB and the reverse proxy guide for Nginx and certificates. This guide only covers what is specific to PHP and WordPress. Replace example.com with your domain.

Install the packages on Ubuntu

Ubuntu 24.04 ships PHP 8.3. Install Nginx, PHP-FPM and the extensions WordPress commonly uses. The PHP-FPM socket is /run/php/php8.3-fpm.sock.

Ubuntu only
sudo apt update
sudo apt install nginx mariadb-server php-fpm php-mysql php-curl php-gd php-intl php-mbstring php-xml php-zip php-imagick certbot python3-certbot-nginx
sudo systemctl enable --now php8.3-fpm nginx mariadb
php --version
ls /run/php/

Install the packages on AlmaLinux

AlmaLinux 9 provides PHP in its default repositories, and a newer version is available through module streams. PHP-FPM runs as the apache user by default. Change it to nginx so that Nginx and PHP agree on file ownership, and the socket path is /run/php-fpm/www.sock.

Use the maintained PHP 8.3 stream on a fresh AlmaLinux 9 installation. If the server already hosts PHP applications, review their compatibility before switching streams.

AlmaLinux only
sudo dnf install epel-release policycoreutils-python-utils
sudo dnf module reset php
sudo dnf module enable php:8.3
sudo dnf install nginx mariadb-server php-fpm php-cli php-curl php-mysqlnd php-gd php-intl php-mbstring php-xml php-zip php-json certbot python3-certbot-nginx
sudo sed -i 's/^user = apache/user = nginx/;s/^group = apache/group = nginx/' /etc/php-fpm.d/www.conf
sudo sed -i 's/^;listen.owner = nobody/listen.owner = nginx/;s/^;listen.group = nobody/listen.group = nginx/' /etc/php-fpm.d/www.conf
sudo systemctl enable --now php-fpm nginx mariadb
sudo php-fpm -tt 2>&1 | tail -n 3

Create the database

Use the MariaDB steps from the database guide to create a database and a user for WordPress, with a random password. Write the password down for the WordPress setup screen.

Both systems
openssl rand -base64 24
sudo mysql <<'EOF'
CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'PASTE_THE_GENERATED_PASSWORD';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EOF

Download and verify WordPress

Download the latest release from wordpress.org and compare it with the checksum published beside it before extracting. Put the files in /var/www/example.com and give them to the web server user. The user is www-data on Ubuntu and nginx on AlmaLinux.

Both systems
cd /tmp
curl -fsSLO https://wordpress.org/latest.tar.gz
curl -fsSL https://wordpress.org/latest.tar.gz.sha1
sha1sum latest.tar.gz
Ubuntu only: if the two checksums match
sudo mkdir -p /var/www/example.com
sudo tar -xzf /tmp/latest.tar.gz -C /var/www/example.com --strip-components=1
sudo chown -R www-data:www-data /var/www/example.com
AlmaLinux only: if the two checksums match
sudo mkdir -p /var/www/example.com
sudo tar -xzf /tmp/latest.tar.gz -C /var/www/example.com --strip-components=1
sudo chown -R nginx:nginx /var/www/example.com
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/example.com(/.*)?"
sudo restorecon -Rv /var/www/example.com
sudo setsebool -P httpd_can_network_connect_db 1
On AlmaLinux semanage comes from the policycoreutils-python-utils package. Install it first if the command is missing.

Configure Nginx

This server block serves static files directly, sends PHP files to PHP-FPM and enables WordPress pretty permalinks. Ubuntu uses the socket /run/php/php8.3-fpm.sock and AlmaLinux uses /run/php-fpm/www.sock, so pick the right fastcgi_pass line.

Select the socket before testing Nginx: Ubuntu uses /run/php/php8.3-fpm.sock and AlmaLinux uses /run/php-fpm/www.sock.

Both systems: create /etc/nginx/conf.d/example.com.conf
sudo tee /etc/nginx/conf.d/example.com.conf >/dev/null <<'EOF'
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.php;
    client_max_body_size 64m;

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

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;   # AlmaLinux: unix:/run/php-fpm/www.sock
    }

    location ~ /\.ht { deny all; }
    location = /xmlrpc.php { deny all; }
}
EOF
# AlmaLinux only, before the test:
# sudo sed -i 's|unix:/run/php/php8.3-fpm.sock|unix:/run/php-fpm/www.sock|' /etc/nginx/conf.d/example.com.conf
sudo nginx -t && sudo systemctl reload nginx

Finish setup and enable HTTPS

Visit http://example.com in your browser and follow the WordPress installer, entering the database name, user and password you created. Then obtain a certificate with Certbot as shown in the reverse proxy guide, and set both WordPress addresses to https in Settings, General.

Both systems
sudo certbot --nginx -d example.com -d www.example.com
curl -I https://example.com/

Secure and maintain it

Use a strong administrator password, keep WordPress, themes and plugins updated, and remove anything you do not use. The most common compromises come from outdated plugins. Back up the database and the wp-content folder on a schedule, and test a restore. Restrict file permissions so that PHP cannot overwrite core files if you are not using automatic updates.

Both systems: tighten permissions, then adjust the owner to your web user
sudo find /var/www/example.com -type d -exec chmod 755 {} +
sudo find /var/www/example.com -type f -exec chmod 644 {} +
sudo chmod 640 /var/www/example.com/wp-config.php
WordPress needs write access to wp-content for uploads and, if you use the dashboard to update, to the whole site. Choose one update method and set permissions to match.

Official documentation

These upstream references provide more detail on the commands and workflows in this guide.