TürkiyeVPS

Installing WordPress on a VPS: With Nginx, PHP 8.3 and MariaDB

Install WordPress by hand on an Ubuntu 24.04 VPS: setting up Nginx, PHP 8.3-FPM and MariaDB, creating the database, wp-config settings, the Nginx server block, a free SSL certificate and basic security measures.

7 min read

Running WordPress on your own VPS gives you full control: you decide the PHP version, the cache settings and the server configuration. In return, updates, security and backups are your responsibility too. In this guide we'll install the LEMP stack (Linux, Nginx, MariaDB, PHP) on Ubuntu 24.04 and put WordPress online.

Before you start, point your domain's DNS A record to the VPS's IP address; we'll need it in the SSL step. The examples use ornek.com; replace it with your own domain.

1. Install Nginx, PHP 8.3 and MariaDB

Connect via SSH and update packages. The default PHP version in the Ubuntu 24.04 repositories is 8.3:

sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx mariadb-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

For image processing, you can optionally install the Imagick extension that WordPress recommends:

sudo apt install -y php8.3-imagick

Check that the services are running:

systemctl status nginx php8.3-fpm mariadb --no-pager

2. Secure MariaDB

sudo mariadb-secure-installation

On Ubuntu, MariaDB's root user authenticates via unix_socket by default, which means only the server's root user can log in, with sudo mariadb. So you can answer n to "Switch to unix_socket authentication" and "Change the root password". Answer Y to removing anonymous users, disallowing remote root login, removing the test database and reloading the privilege tables.

3. Create a database and user

Create a separate database for WordPress and a user with privileges on that database only:

sudo mariadb
CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'GucluBirSifre123!';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Be sure to replace the password with a long, random value of your own. You can generate a random password with openssl rand -base64 24.

4. Download WordPress and set permissions

Download the latest version directly from wordpress.org:

cd /tmp
curl -LO https://wordpress.org/latest.tar.gz
tar xzf latest.tar.gz
sudo mv wordpress /var/www/ornek.com
sudo chown -R www-data:www-data /var/www/ornek.com
sudo find /var/www/ornek.com -type d -exec chmod 755 {} \;
sudo find /var/www/ornek.com -type f -exec chmod 644 {} \;

Making www-data the owner of the files lets WordPress install plugins and themes from the dashboard and apply updates itself. 755 for folders and 644 for files are the values WordPress recommends; never give files 777 permissions.

5. Prepare the wp-config.php file

cd /var/www/ornek.com
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php

Fill in the database lines with the details you created in step 3:

define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', 'GucluBirSifre123!' );
define( 'DB_HOST', 'localhost' );

In the same file, replace the eight-line security keys section (AUTH_KEY, SECURE_AUTH_KEY and so on) with unique values. You can get new values from WordPress's official service:

curl -s https://api.wordpress.org/secret-key/1.1/salt/

Copy the output and paste it in place of the lines containing put your unique phrase here. Then add the following above the /* That's all, stop editing! */ line; it disables the theme and plugin file editor in the dashboard:

define( 'DISALLOW_FILE_EDIT', true );

Fix the file's owner and permissions:

sudo chown www-data:www-data wp-config.php
sudo chmod 640 wp-config.php

6. Raise PHP upload limits

PHP's default upload limit is 2 MB, which causes trouble as soon as you upload a theme or a large image. Creating a separate settings file instead of editing the main php.ini makes it easier to keep your changes across updates:

sudo nano /etc/php/8.3/fpm/conf.d/99-wordpress.ini
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 120
sudo systemctl restart php8.3-fpm

7. Write the Nginx server block

sudo nano /etc/nginx/sites-available/ornek.com
server {
    listen 80;
    server_name ornek.com www.ornek.com;
    root /var/www/ornek.com;
    index index.php index.html;

    client_max_body_size 64M;

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

    location = /xmlrpc.php {
        deny all;
    }

    location ~* /wp-content/uploads/.*\.php$ {
        deny all;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }

    location ~* \.(css|js|jpg|jpeg|png|gif|webp|svg|ico|woff2?)$ {
        expires 30d;
        access_log off;
    }
}

Key points:

  • try_files $uri $uri/ /index.php?$args: if there's no real file, the request is passed to WordPress. Pretty permalinks (like /blog/yazi-adi) depend on this line.
  • fastcgi_pass: passes PHP requests to the PHP 8.3-FPM socket. The socket name must match the PHP version.
  • Blocking PHP in the uploads folder: even if a PHP file is dropped into the uploads folder through a vulnerability, it can't be executed. Because Nginx tries regex blocks from top to bottom, this block must come before the general \.php$ block.
  • xmlrpc.php: frequently used in brute-force attacks. If you use a tool that relies on XML-RPC, such as Jetpack or the WordPress mobile app, remove this block.

Enable the site:

sudo ln -s /etc/nginx/sites-available/ornek.com /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

8. Firewall and SSL

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Get a free Let's Encrypt SSL certificate:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d ornek.com -d www.ornek.com

It's best to set up SSL before the WordPress installation wizard; that way WordPress saves the site address as https:// from the start, and you don't have to change the address later.

9. Complete the installation wizard

Go to https://ornek.com in your browser. Complete the steps for language, site title, admin username, password and email. Don't choose a guessable admin username like admin, and use a strong password.

Basic security and maintenance

  • Updates: keep WordPress core, themes and plugins up to date. Don't just deactivate plugins and themes you don't use; delete them.
  • Server updates: update Ubuntu packages regularly. For steps such as SSH keys, disabling root login and Fail2ban, see our Linux server security guide.
  • Login attempts: consider using a plugin that limits brute-force attempts on the login page, along with two-factor authentication.
  • Backups: back up the database and the wp-content folder regularly, and keep the backups off the server:
sudo mariadb-dump wordpress | gzip > ~/wordpress-db-$(date +%F).sql.gz
sudo tar czf ~/wordpress-dosyalar-$(date +%F).tar.gz -C /var/www/ornek.com wp-content wp-config.php

If you don't want to manage a server

Managing your own VPS is a great way to learn, but not every business has time for it. If your only goal is to publish a WordPress site, there are two alternatives:

  • WordPress hosting: runs on NVMe storage; after payment, our team installs WordPress and hands the site over to you ready to use.
  • Web hosting: comes with your own control panel, phpMyAdmin and a file manager, and supports PHP 8.3 and MariaDB. Current prices (in US dollars) are listed on the plan page. If you're curious about the differences, read our what is web hosting article.

If you want to run multiple sites, custom PHP settings or other applications besides WordPress, a VPS with root access gives you more flexibility.

Frequently Asked Questions

Permalinks return a 404 error. Why?

Nginx doesn't read Apache's .htaccess file. Make sure the try_files $uri $uri/ /index.php?$args; line is inside location / in the server block, then run sudo nginx -t and sudo systemctl reload nginx.

I get "Error establishing a database connection". What should I do?

Check that the DB_NAME, DB_USER and DB_PASSWORD values in wp-config.php exactly match what you created in step 3, and that MariaDB is running (systemctl status mariadb).

WordPress asks for FTP details when I install a plugin. Why?

WordPress asks for FTP details when it can't write to the files. Check that the site folder is owned by www-data: sudo chown -R www-data:www-data /var/www/ornek.com.

I get "413 Request Entity Too Large" when uploading files.

This error comes from Nginx. Raise the client_max_body_size value in the server block together with upload_max_filesize and post_max_size in PHP, then reload Nginx and PHP-FPM.

Can I run more than one WordPress site on the same VPS?

Yes. Just create a separate database and user, a separate folder (such as /var/www/site2.com) and a separate Nginx server block for each site.