{"id":186,"date":"2026-10-28T21:19:37","date_gmt":"2026-10-28T20:19:37","guid":{"rendered":"https:\/\/nodeguard.io\/blog\/?p=186"},"modified":"2026-10-29T21:34:17","modified_gmt":"2026-10-29T20:34:17","slug":"how-to-install-wordpress-on-an-ubuntu-vps-with-nginx","status":"publish","type":"post","link":"https:\/\/nodeguard.io\/blog\/how-to-install-wordpress-on-an-ubuntu-vps-with-nginx\/","title":{"rendered":"How to Install WordPress on an Ubuntu VPS with Nginx: 12 Simple Steps to a Faster Site"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">WordPress powers a huge share of the web, and most of those sites sit on shared hosting where you control almost nothing. Running it on your own server changes that. This guide shows you how to install WordPress on an Ubuntu VPS with Nginx, step by step, so you end up with a site that is fast, secure and fully under your control.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nginx is an excellent match for WordPress. It serves images, stylesheets and scripts straight from disk with very little memory, and it hands only the dynamic requests to PHP. On a small virtual server, that efficiency means more visitors per euro and faster pages for every one of them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will go from a fresh server to a working WordPress dashboard in twelve clear steps. Every command works on Ubuntu 26.04 LTS and Ubuntu 24.04 LTS, and we point out the few places where the two releases differ. Along the way you will create the WordPress database, write a clean Nginx server block, enable free HTTPS and lock down the settings that attackers target first.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Set aside about 30 minutes. You only need basic comfort with the command line.<\/p>\n\n\n\n<h2 id=\"what-you-need-before-you-install-word-press\" class=\"wp-block-heading\">What You Need Before You Install WordPress<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before you install WordPress, make sure you have these four things ready:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>An Ubuntu VPS<\/strong> running Ubuntu 26.04 LTS or 24.04 LTS, with at least 1 GB of RAM. A brand-new blog runs fine on 1 GB; a busy site or an online shop is happier with 2 to 4 GB.<\/li>\n\n\n\n<li><strong>A sudo user and SSH access.<\/strong> Do not work as root. If your server is brand new, follow our guide on <a href=\"https:\/\/nodeguard.io\/blog\/how-to-set-up-an-ubuntu-vps\">how to set up an Ubuntu VPS<\/a> first. It covers updates, a sudo user, SSH keys and basic hardening.<\/li>\n\n\n\n<li><strong>A domain name<\/strong> with an A record pointing to your server&#8217;s IP address. You need this for HTTPS in Step 11. DNS changes can take a few minutes to spread, so create the record now.<\/li>\n\n\n\n<li><strong>About 2 GB of free disk space<\/strong> for WordPress, its database and your first uploads.<\/li>\n<\/ul>\n\n\n\n<h3 id=\"word-press-server-requirements-in-2026\" class=\"wp-block-heading\">WordPress Server Requirements in 2026<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At the time of writing, the current release is WordPress 7.1. The official <a href=\"https:\/\/wordpress.org\/about\/requirements\/\" target=\"_blank\" rel=\"noopener\">WordPress requirements page<\/a> recommends PHP 8.3 or newer, MariaDB 10.11 or newer (or MySQL 8.0 or newer) and HTTPS. The good news is that Ubuntu&#8217;s default packages already meet those targets, so you do not need any third-party repositories:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Component<\/th><th>Ubuntu 26.04 LTS<\/th><th>Ubuntu 24.04 LTS<\/th><\/tr><\/thead><tbody><tr><td>Nginx<\/td><td>1.28<\/td><td>1.24<\/td><\/tr><tr><td>PHP<\/td><td>8.5<\/td><td>8.3<\/td><\/tr><tr><td>MariaDB<\/td><td>11.8<\/td><td>10.11<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Both releases receive security updates for years, which is exactly what you want under a production website.<\/p>\n\n\n\n<h2 id=\"how-word-press-runs-on-nginx\" class=\"wp-block-heading\">How WordPress Runs on Nginx<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">It helps to understand how the pieces fit together before you install WordPress, because almost every error you will ever see comes from one of the links in this chain.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When a visitor opens your site, the browser connects to <strong>Nginx<\/strong> on port 443. If the request is for a static file, such as an image or a CSS file, Nginx sends it straight back from disk. That is the fast path, and on a typical WordPress page it covers most of the requests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the request is for a page or a post, there is no matching file on disk, because WordPress builds its pages on the fly. Nginx then passes the request to <code>index.php<\/code>, and hands it to <strong>PHP-FPM<\/strong> over a local Unix socket. PHP-FPM runs WordPress, which reads your posts, settings and users from the <strong>WordPress database<\/strong> in <strong>MariaDB<\/strong>. WordPress assembles the HTML, returns it to Nginx, and Nginx delivers it to the browser.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike Apache, Nginx does not read <code>.htaccess<\/code> files. Every rule a WordPress plugin would normally write to <code>.htaccess<\/code>, such as pretty permalinks, lives in your Nginx server block instead. That is why the server block in Step 10 matters so much, and why we explain it line by line later.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-how-it-works-1024x576.webp\" alt=\"How to install WordPress on an Ubuntu VPS with Nginx \u2013 request flow from browser to Nginx, PHP-FPM and the MariaDB WordPress database\" class=\"wp-image-189\" srcset=\"https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-how-it-works-1024x576.webp 1024w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-how-it-works-300x169.webp 300w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-how-it-works-768x432.webp 768w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-how-it-works-900x506.webp 900w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-how-it-works.webp 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 id=\"how-to-install-word-press-on-an-ubuntu-vps-with-nginx-12-simple-steps\" class=\"wp-block-heading\">How to Install WordPress on an Ubuntu VPS with Nginx: 12 Simple Steps<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-12-steps-1024x576.webp\" alt=\"Install WordPress on Ubuntu with Nginx in 12 steps \u2013 update, Nginx, firewall, MariaDB, database, PHP-FPM, download, wp-config, permissions, server block, HTTPS and installer\" class=\"wp-image-188\" srcset=\"https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-12-steps-1024x576.webp 1024w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-12-steps-300x169.webp 300w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-12-steps-768x432.webp 768w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-12-steps-900x506.webp 900w, https:\/\/nodeguard.io\/blog\/wp-content\/uploads\/2026\/10\/wordpress-ubuntu-nginx-12-steps.webp 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">The 12 steps at a glance, from a fresh Ubuntu VPS to the WordPress dashboard.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Steps 1 to 6 build the web server underneath WordPress. If you already followed our guide on <a href=\"https:\/\/nodeguard.io\/blog\/how-to-install-a-lemp-stack-on-ubuntu\">how to install a LEMP stack on Ubuntu<\/a>, you can skim them and jump to Step 5 to create the WordPress database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Throughout this guide, replace <code>example.com<\/code> with your own domain.<\/p>\n\n\n\n<h3 id=\"step-1-update-your-ubuntu-vps\" class=\"wp-block-heading\">Step 1: Update Your Ubuntu VPS<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Log in over SSH as your sudo user and bring every package up to date:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update &amp;&amp; sudo apt upgrade -y\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the upgrade installed a new kernel, reboot with <code>sudo reboot<\/code> and log back in. Starting from a fully patched Ubuntu VPS avoids version mismatches later.<\/p>\n\n\n\n<h3 id=\"step-2-install-nginx\" class=\"wp-block-heading\">Step 2: Install Nginx<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Install the web server and make sure it starts at boot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y nginx\nsudo systemctl enable --now nginx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check that it is running with <code>systemctl status nginx --no-pager<\/code>. For a deeper look at the Nginx file layout and its commands, see our guide on <a href=\"https:\/\/nodeguard.io\/blog\/how-to-install-nginx-on-ubuntu\">how to install Nginx on Ubuntu<\/a>.<\/p>\n\n\n\n<h3 id=\"step-3-allow-web-traffic-through-the-firewall\" class=\"wp-block-heading\">Step 3: Allow Web Traffic Through the Firewall<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If UFW is active on your server, open ports 80 and 443 while keeping SSH allowed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ufw allow OpenSSH\nsudo ufw allow 'Nginx Full'\nsudo ufw enable\nsudo ufw status\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Port 80 is needed even if you only want HTTPS, because Let&#8217;s Encrypt uses it to verify your domain and Nginx uses it to redirect visitors to HTTPS. Our guide on <a href=\"https:\/\/nodeguard.io\/blog\/how-to-configure-ufw-firewall-on-ubuntu\">how to configure UFW firewall on Ubuntu<\/a> explains each rule in detail.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Open <code>http:\/\/YOUR_SERVER_IP<\/code> in a browser. The &#8220;Welcome to nginx!&#8221; page confirms that Nginx is reachable.<\/p>\n\n\n\n<h3 id=\"step-4-install-and-secure-maria-db\" class=\"wp-block-heading\">Step 4: Install and Secure MariaDB<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Install the database server:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y mariadb-server\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then run the security script, which removes the test database and anonymous accounts:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mariadb-secure-installation\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Press Enter for the current root password, answer <code>n<\/code> to switching to unix_socket authentication and <code>n<\/code> to changing the root password (on Ubuntu, the database root account already uses socket login, so only the system&#8217;s root user can use it), then answer <code>Y<\/code> to the remaining four questions.<\/p>\n\n\n\n<h3 id=\"step-5-create-the-word-press-database-and-user\" class=\"wp-block-heading\">Step 5: Create the WordPress Database and User<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress should never connect as the database root user. Give it a dedicated WordPress database and a user that can touch nothing else. Open the MariaDB shell:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mariadb\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run these statements, choosing your own names and a long, random password:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\nCREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'USE-A-LONG-RANDOM-PASSWORD';\nGRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';\nFLUSH PRIVILEGES;\nEXIT;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>utf8mb4<\/code> character set stores every character WordPress can display, including emoji and non-Latin scripts. Write the database name, user and password down somewhere safe; you need them in Step 8.<\/p>\n\n\n\n<h3 id=\"step-6-install-php-fpm-and-the-php-extensions-word-press-needs\" class=\"wp-block-heading\">Step 6: Install PHP-FPM and the PHP Extensions WordPress Needs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Install PHP-FPM together with the extensions WordPress and popular plugins rely on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y php-fpm php-mysql php-curl php-gd php-intl php-mbstring php-xml php-zip php-imagick php-bcmath\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>php-mysql<\/code> lets WordPress talk to the WordPress database, <code>php-gd<\/code> and <code>php-imagick<\/code> handle image resizing, and the rest cover international text, XML feeds, ZIP uploads and maths functions used by shop plugins. You do not need a separate OPcache package: on Ubuntu 26.04 it is built into PHP 8.5, and on 24.04 it is installed with PHP-FPM automatically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check your version with <code>php -v<\/code>. You should see PHP 8.5 on Ubuntu 26.04 or PHP 8.3 on Ubuntu 24.04.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress uploads, themes and plugin installs often exceed PHP&#8217;s small default limits. Create a small settings file for PHP-FPM instead of editing the main <code>php.ini<\/code> (replace <code>8.5<\/code> with <code>8.3<\/code> on Ubuntu 24.04):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/php\/8.5\/fpm\/conf.d\/99-wordpress.ini &gt; \/dev\/null &lt;&lt;'EOF'\nupload_max_filesize = 64M\npost_max_size = 64M\nmemory_limit = 256M\nmax_execution_time = 120\nEOF\nsudo systemctl restart php8.5-fpm\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A separate file survives package upgrades and makes your changes easy to find later.<\/p>\n\n\n\n<h3 id=\"step-7-download-word-press\" class=\"wp-block-heading\">Step 7: Download WordPress<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Always download WordPress from the official site, never from a third-party mirror. Fetch the latest release, unpack it and move it into your web root:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/tmp\nwget https:\/\/wordpress.org\/latest.tar.gz\ntar -xzf latest.tar.gz\nsudo mkdir -p \/var\/www\/example.com\nsudo cp -a \/tmp\/wordpress\/. \/var\/www\/example.com\/\nrm -rf \/tmp\/wordpress \/tmp\/latest.tar.gz\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>latest.tar.gz<\/code> link always points at the newest stable version, so you start fully patched.<\/p>\n\n\n\n<h3 id=\"step-8-configure-wp-config-php\" class=\"wp-block-heading\">Step 8: Configure wp-config.php<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress reads its database details and security keys from <code>wp-config.php<\/code>. Create it from the sample file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/var\/www\/example.com\nsudo cp wp-config-sample.php wp-config.php\nsudo nano wp-config.php\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Find the database section and fill in the values from Step 5:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>define( 'DB_NAME', 'wordpress' );\ndefine( 'DB_USER', 'wpuser' );\ndefine( 'DB_PASSWORD', 'USE-A-LONG-RANDOM-PASSWORD' );\ndefine( 'DB_HOST', 'localhost' );\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Next, replace the eight placeholder security keys. They protect login cookies, so they must be unique to your site. Generate a fresh set:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -s https:\/\/api.wordpress.org\/secret-key\/1.1\/salt\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Delete the eight <code>put your unique phrase here<\/code> lines in <code>wp-config.php<\/code> and paste the generated block in their place. While the file is open, add this line just above the &#8220;That&#8217;s all, stop editing!&#8221; comment:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>define( 'DISALLOW_FILE_EDIT', true );\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It turns off the built-in theme and plugin code editor in the dashboard. If an attacker ever steals an admin password, that editor is the first thing they use to plant malicious code.<\/p>\n\n\n\n<h3 id=\"step-9-set-the-correct-file-ownership-and-permissions\" class=\"wp-block-heading\">Step 9: Set the Correct File Ownership and Permissions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">PHP-FPM runs as the <code>www-data<\/code> user on Ubuntu, so WordPress files must belong to it. That lets WordPress install plugins, themes and updates directly, without ever asking you for FTP details:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo chown -R www-data:www-data \/var\/www\/example.com\nsudo find \/var\/www\/example.com -type d -exec chmod 755 {} \\;\nsudo find \/var\/www\/example.com -type f -exec chmod 644 {} \\;\nsudo chmod 640 \/var\/www\/example.com\/wp-config.php\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Folders get <code>755<\/code>, files get <code>644<\/code>, and <code>wp-config.php<\/code> gets <code>640<\/code> so other users on the server cannot read your database password. Never use <code>777<\/code>, whatever an old forum post tells you.<\/p>\n\n\n\n<h3 id=\"step-10-create-the-nginx-server-block-for-word-press\" class=\"wp-block-heading\">Step 10: Create the Nginx Server Block for WordPress<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Now connect Nginx to WordPress. Create a new Nginx server block for your domain:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/nginx\/sites-available\/example.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Paste in this configuration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server {\n    listen 80;\n    listen &#91;::]:80;\n    server_name example.com www.example.com;\n\n    root \/var\/www\/example.com;\n    index index.php index.html;\n\n    client_max_body_size 64M;\n\n    # Block PHP inside uploads and hidden files (must come before the PHP block)\n    location ~* \/wp-content\/uploads\/.*\\.php$ { deny all; }\n    location ~ \/\\.(?!well-known) { deny all; }\n    location = \/xmlrpc.php { deny all; }\n\n    location \/ {\n        try_files $uri $uri\/ \/index.php?$args;\n    }\n\n    location ~ \\.php$ {\n        include snippets\/fastcgi-php.conf;\n        fastcgi_pass unix:\/run\/php\/php-fpm.sock;\n    }\n\n    location ~* \\.(css|js|gif|ico|jpe?g|png|svg|webp|avif|woff2?)$ {\n        expires 30d;\n        access_log off;\n        log_not_found off;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check the PHP-FPM socket name with <code>ls \/run\/php\/<\/code>. If there is no <code>php-fpm.sock<\/code> shortcut, use the versioned name instead, for example <code>unix:\/run\/php\/php8.5-fpm.sock<\/code> (or <code>php8.3-fpm.sock<\/code> on Ubuntu 24.04).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enable the site, remove the default welcome page, then test and reload:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ln -s \/etc\/nginx\/sites-available\/example.com \/etc\/nginx\/sites-enabled\/\nsudo rm -f \/etc\/nginx\/sites-enabled\/default\nsudo nginx -t\nsudo systemctl reload nginx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Never skip <code>nginx -t<\/code>. It catches typos before they can take your site offline.<\/p>\n\n\n\n<h3 id=\"step-11-enable-free-https-with-lets-encrypt\" class=\"wp-block-heading\">Step 11: Enable Free HTTPS with Let&#8217;s Encrypt<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Install Certbot and its Nginx plugin, then request a certificate for both versions of your domain:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y certbot python3-certbot-nginx\nsudo certbot --nginx -d example.com -d www.example.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Certbot verifies your domain, installs the certificate, adds the <code>listen 443 ssl<\/code> lines to your Nginx server block and sets up an automatic redirect from HTTP to HTTPS. Renewal runs on its own through a systemd timer; confirm it works with <code>sudo certbot renew --dry-run<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do this before you run the installer. WordPress stores your site address in the database, and starting on HTTPS saves you from mixed-content warnings later.<\/p>\n\n\n\n<h3 id=\"step-12-run-the-word-press-web-installer\" class=\"wp-block-heading\">Step 12: Run the WordPress Web Installer<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Open <code>https:\/\/example.com<\/code> in your browser. WordPress asks you to choose a language, then shows its famous five-minute install screen. Fill in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Site title:<\/strong> you can change it later.<\/li>\n\n\n\n<li><strong>Username:<\/strong> anything except <code>admin<\/code>, which is the first name bots try.<\/li>\n\n\n\n<li><strong>Password:<\/strong> keep the strong one WordPress suggests and store it in a password manager.<\/li>\n\n\n\n<li><strong>Email:<\/strong> an address you check, because password resets go there.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Click <strong>Install WordPress<\/strong>, log in at <code>https:\/\/example.com\/wp-admin<\/code>, and you are done. You now know how to install WordPress on an Ubuntu VPS with Nginx, from the first update to the first login.<\/p>\n\n\n\n<h2 id=\"understanding-your-nginx-server-block-line-by-line\" class=\"wp-block-heading\">Understanding Your Nginx Server Block Line by Line<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Copying a configuration is easy; knowing what it does is what lets you fix it at 2 a.m. Here is what each part of the Nginx server block does:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>root<\/code> and <code>index<\/code><\/strong> tell Nginx where WordPress lives and to look for <code>index.php<\/code> first.<\/li>\n\n\n\n<li><strong><code>client_max_body_size 64M<\/code><\/strong> matches the PHP limit from Step 6. Without it, Nginx rejects large uploads with a &#8220;413 Request Entity Too Large&#8221; error before PHP ever sees them.<\/li>\n\n\n\n<li><strong><code>try_files $uri $uri\/ \/index.php?$args<\/code><\/strong> is the heart of WordPress on Nginx. It serves a real file if one exists, then a real folder, and otherwise passes the request to WordPress with its query string. This single line replaces the rewrite rules WordPress writes to <code>.htaccess<\/code> on Apache, and it is what makes pretty permalinks work.<\/li>\n\n\n\n<li><strong>The uploads rule<\/strong> blocks PHP execution inside <code>\/wp-content\/uploads\/<\/code>. Uploads should only ever contain media, so a PHP file there is almost always malware. Nginx checks regular-expression locations in order, which is why these deny rules sit above the PHP block.<\/li>\n\n\n\n<li><strong>The hidden-files rule<\/strong> blocks <code>.git<\/code>, <code>.env<\/code> and similar files while still allowing <code>\/.well-known\/<\/code>, which Let&#8217;s Encrypt needs.<\/li>\n\n\n\n<li><strong>Blocking <code>xmlrpc.php<\/code><\/strong> shuts a door that bots use for brute-force login attempts. Remove that line only if you use the Jetpack plugin or a mobile app that depends on XML-RPC.<\/li>\n\n\n\n<li><strong>The static-files block<\/strong> tells browsers to cache images, fonts, CSS and JavaScript for 30 days and keeps those requests out of your logs.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">When you host a second site on the same Ubuntu VPS, copy this Nginx server block, change <code>server_name<\/code> and <code>root<\/code>, and give it its own WordPress database and user.<\/p>\n\n\n\n<h3 id=\"pretty-permalinks-with-your-nginx-server-block-including-subfolder-installs\" class=\"wp-block-heading\">Pretty Permalinks with Your Nginx Server Block (Including Subfolder Installs)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pretty permalinks turn addresses like <code>example.com\/?p=123<\/code> into clean, readable URLs such as <code>example.com\/my-first-post\/<\/code>. They are better for visitors and for search engines, because the address itself describes the page.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On Nginx, there is nothing to install and no <code>.htaccess<\/code> to edit. WordPress only needs every unknown address passed to <code>index.php<\/code>, and the <code>try_files<\/code> line in your Nginx server block already does that. Choose <strong>Post name<\/strong> under <strong>Settings \u2192 Permalinks<\/strong>, click <strong>Save Changes<\/strong>, and your URLs are clean straight away.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If WordPress lives in a subfolder, such as <code>example.com\/blog<\/code>, the root rule is not enough. Keep <code>root \/var\/www\/example.com;<\/code>, place WordPress in <code>\/var\/www\/example.com\/blog<\/code>, and add a block that sends unknown addresses to the subfolder&#8217;s own <code>index.php<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>location \/blog\/ {\n    try_files $uri $uri\/ \/blog\/index.php?$args;\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Without it, the blog&#8217;s home page loads but every post returns a 404. Test the result by opening a post, or run <code>curl -I https:\/\/example.com\/blog\/my-first-post\/<\/code> and look for <code>200 OK<\/code>.<\/p>\n\n\n\n<h2 id=\"backing-up-and-protecting-your-word-press-database\" class=\"wp-block-heading\">Backing Up and Protecting Your WordPress Database<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Your posts, pages, users and settings all live in the WordPress database, so it deserves the most protection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Keep MariaDB private.<\/strong> By default, MariaDB on Ubuntu listens only on <code>127.0.0.1<\/code>. Check with <code>sudo ss -tlnp | grep 3306<\/code> and never open port 3306 in your firewall when WordPress and MariaDB run on the same server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Back it up every day.<\/strong> A simple, reliable export looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mariadb-dump --single-transaction wordpress | gzip &gt; ~\/wordpress-$(date +%F).sql.gz\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Schedule it with cron, keep at least a week of copies, and store some of them off the server, because a backup on the same disk does not survive a disk failure. Back up <code>\/var\/www\/example.com\/wp-content<\/code> too, since your themes, plugins and uploads live there.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Change the table prefix on new sites.<\/strong> If you have not run the installer yet, changing <code>$table_prefix<\/code> in <code>wp-config.php<\/code> from <code>wp_<\/code> to something like <code>ng7x_<\/code> makes automated SQL injection attacks a little less likely to hit the right tables.<\/p>\n\n\n\n<h2 id=\"essential-settings-after-you-install-word-press\" class=\"wp-block-heading\">Essential Settings After You Install WordPress<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A fresh install works, but a few minutes of setup makes it faster, safer and friendlier to search engines:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Set permalinks.<\/strong> Go to <strong>Settings \u2192 Permalinks<\/strong> and choose <strong>Post name<\/strong>. Thanks to the <code>try_files<\/code> line, this works immediately on Nginx with no extra rules.<\/li>\n\n\n\n<li><strong>Check the site address.<\/strong> Under <strong>Settings \u2192 General<\/strong>, both addresses should start with <code>https:\/\/<\/code>.<\/li>\n\n\n\n<li><strong>Delete what you do not use.<\/strong> Remove the sample post, the sample page, the &#8220;Hello Dolly&#8221; plugin and every inactive theme except one default theme as a fallback.<\/li>\n\n\n\n<li><strong>Turn on automatic updates.<\/strong> Minor WordPress releases update themselves by default. Enable auto-updates for trusted plugins on the <strong>Plugins<\/strong> screen as well, because outdated plugins are the most common way WordPress sites get hacked.<\/li>\n\n\n\n<li><strong>Add login protection.<\/strong> Enable two-factor authentication with a reputable plugin, and consider Fail2Ban on the server to block repeated failed logins.<\/li>\n<\/ol>\n\n\n\n<h2 id=\"speed-up-word-press-on-your-ubuntu-vps\" class=\"wp-block-heading\">Speed Up WordPress on Your Ubuntu VPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Nginx and PHP-FPM are already fast, but caching makes the biggest difference.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Use a page cache.<\/strong> A caching plugin stores finished pages so PHP and the WordPress database are skipped for repeat visitors. For maximum speed, Nginx&#8217;s own FastCGI cache can serve cached pages without touching PHP at all.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Add an object cache.<\/strong> Install Redis with <code>sudo apt install -y redis-server php-redis<\/code>, restart PHP-FPM, and enable it with a Redis object cache plugin. Busy pages then hit the WordPress database far less often.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Tune PHP-FPM for your RAM.<\/strong> The default pool settings in <code>\/etc\/php\/8.5\/fpm\/pool.d\/www.conf<\/code> are conservative. On a 2 GB Ubuntu VPS, <code>pm.max_children = 10<\/code> is a sensible starting point for most WordPress sites; raise it gradually while watching memory with <code>free -h<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Serve modern images.<\/strong> Current WordPress versions accept WebP and AVIF uploads, which are often much smaller than JPEG at the same quality. Converting large photos before you upload them cuts page weight more than almost any plugin.<\/p>\n\n\n\n<h2 id=\"optional-install-word-press-faster-with-wp-cli\" class=\"wp-block-heading\">Optional: Install WordPress Faster with WP-CLI<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Once you have done this by hand, you may want to install WordPress faster next time. WP-CLI is the official command-line tool for WordPress, and it can download, configure and install a site in seconds. Install it once:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -O https:\/\/raw.githubusercontent.com\/wp-cli\/builds\/gh-pages\/phar\/wp-cli.phar\nchmod +x wp-cli.phar\nsudo mv wp-cli.phar \/usr\/local\/bin\/wp\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After you finish Steps 1 to 6 and Step 10, you can replace Steps 7, 8 and 12 with three commands, run as <code>www-data<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/var\/www\/example.com\nsudo -u www-data wp core download\nsudo -u www-data wp config create --dbname=wordpress --dbuser=wpuser --prompt=dbpass\nsudo -u www-data wp core install --url=https:\/\/example.com --title=\"My Site\" --admin_user=yourname --admin_email=you@example.com --prompt=admin_password\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>--prompt<\/code> options ask for the passwords interactively, so they never end up in your shell history. WP-CLI also makes daily tasks easy: <code>wp plugin update --all<\/code>, <code>wp core update<\/code> and <code>wp db export<\/code> all work the same way.<\/p>\n\n\n\n<h2 id=\"troubleshooting-common-word-press-and-nginx-errors\" class=\"wp-block-heading\">Troubleshooting Common WordPress and Nginx Errors<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most problems after you install WordPress come from a handful of causes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>502 Bad Gateway:<\/strong> Nginx cannot reach PHP-FPM. Check that the service runs with <code>systemctl status php8.5-fpm<\/code> and that the socket path in your Nginx server block matches what <code>ls \/run\/php\/<\/code> shows.<\/li>\n\n\n\n<li><strong>Error establishing a database connection:<\/strong> the details in <code>wp-config.php<\/code> do not match Step 5. Test them with <code>mariadb -u wpuser -p wordpress<\/code>. If that login fails, WordPress will fail too.<\/li>\n\n\n\n<li><strong>Pages other than the home page return 404:<\/strong> the <code>try_files<\/code> line is missing or wrong. Fix it, run <code>sudo nginx -t<\/code> and reload.<\/li>\n\n\n\n<li><strong>WordPress asks for FTP details when installing a plugin:<\/strong> the files are not owned by <code>www-data<\/code>. Re-run the <code>chown<\/code> command from Step 9.<\/li>\n\n\n\n<li><strong>413 Request Entity Too Large:<\/strong> raise <code>client_max_body_size<\/code> in Nginx and the upload limits in your PHP settings file, then reload both services.<\/li>\n\n\n\n<li><strong>A blank white screen:<\/strong> add <code>define( 'WP_DEBUG', true );<\/code> and <code>define( 'WP_DEBUG_LOG', true );<\/code> to <code>wp-config.php<\/code>, reload the page and read <code>wp-content\/debug.log<\/code>. Turn debugging off again when you are done.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The Nginx error log at <code>\/var\/log\/nginx\/error.log<\/code> is your best friend for all of these. Read it with <code>sudo tail -n 50 \/var\/log\/nginx\/error.log<\/code>.<\/p>\n\n\n\n<h2 id=\"frequently-asked-questions\" class=\"wp-block-heading\">Frequently Asked Questions<\/h2>\n\n\n\n<h3 id=\"is-nginx-better-than-apache-for-word-press\" class=\"wp-block-heading\">Is Nginx better than Apache for WordPress?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For most sites, yes. Nginx uses less memory under load and serves static files faster, which matters on a VPS with limited RAM. The main trade-off is that Nginx ignores <code>.htaccess<\/code>, so plugin rewrite rules must be added to the Nginx server block by hand. For standard WordPress sites, the configuration in this guide covers everything you need.<\/p>\n\n\n\n<h3 id=\"how-much-ram-does-word-press-need-on-a-vps\" class=\"wp-block-heading\">How much RAM does WordPress need on a VPS?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A new blog runs comfortably on 1 GB of RAM. Plan on 2 GB for a growing site with caching and a handful of plugins, and 4 GB or more for WooCommerce or a membership site, where many pages cannot be cached.<\/p>\n\n\n\n<h3 id=\"can-i-host-several-word-press-sites-on-one-ubuntu-vps\" class=\"wp-block-heading\">Can I host several WordPress sites on one Ubuntu VPS?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. Give each site its own folder under <code>\/var\/www<\/code>, its own Nginx server block, its own WordPress database and user, and its own certificate. For stronger isolation, run each site in a separate PHP-FPM pool under its own system user.<\/p>\n\n\n\n<h3 id=\"should-i-use-maria-db-or-my-sql-for-word-press\" class=\"wp-block-heading\">Should I use MariaDB or MySQL for WordPress?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Either works. MariaDB is Ubuntu&#8217;s default, is fully compatible with WordPress and is the database most hosting providers choose. If you prefer MySQL, install <code>mysql-server<\/code> in Step 4; Ubuntu 26.04 ships MySQL 8.4 LTS. The rest of the guide stays the same.<\/p>\n\n\n\n<h3 id=\"how-do-i-update-word-press-after-installing-it\" class=\"wp-block-heading\">How do I update WordPress after installing it?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Minor and security releases install themselves automatically. For major versions, take a backup of the WordPress database and <code>wp-content<\/code>, then click <strong>Update now<\/strong> under <strong>Dashboard \u2192 Updates<\/strong>, or run <code>wp core update<\/code> with WP-CLI. Keep Ubuntu itself patched with <code>sudo apt update &amp;&amp; sudo apt upgrade<\/code> too.<\/p>\n\n\n\n<h2 id=\"conclusion-your-word-press-site-is-live\" class=\"wp-block-heading\">Conclusion: Your WordPress Site Is Live<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You now know how to install WordPress on an Ubuntu VPS with Nginx from start to finish. You updated the server, installed Nginx, MariaDB and PHP-FPM, created a dedicated WordPress database, configured <code>wp-config.php<\/code>, set safe permissions, wrote an Nginx server block built for WordPress, enabled free HTTPS and ran the installer. You also know how to back it up, speed it up and fix the errors that catch most beginners.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is a professional setup that you understand from top to bottom, which is the real advantage of running WordPress on your own server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you need a fast home for it, a <a href=\"https:\/\/nodeguard.io\/cloud-vps\">NodeGuard Cloud VPS<\/a> gives you full root access, a clean Ubuntu image and the resources to grow with your traffic. Prefer to focus on content and leave the server work to us? <a href=\"https:\/\/nodeguard.io\/wordpress-hosting\">NodeGuard managed WordPress hosting<\/a> takes care of updates, security and backups for you.<\/p>\n\n\n\n<h3 id=\"further-reading\" class=\"wp-block-heading\">Further Reading<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/wordpress.org\/about\/requirements\/\" target=\"_blank\" rel=\"noopener\">WordPress server requirements<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/make.wordpress.org\/hosting\/handbook\/\" target=\"_blank\" rel=\"noopener\">WordPress Hosting Handbook<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/nginx.org\/en\/docs\/\" target=\"_blank\" rel=\"noopener\">Nginx official documentation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/certbot.eff.org\/\" target=\"_blank\" rel=\"noopener\">Certbot instructions from the EFF<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/wp-cli.org\/\" target=\"_blank\" rel=\"noopener\">WP-CLI official site<\/a><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n","protected":false},"excerpt":{"rendered":"<p>WordPress powers a huge share of the web, and most of those sites sit on shared hosting where you control almost nothing.\u2026<\/p>\n","protected":false},"author":2,"featured_media":187,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29],"tags":[95,94,96,90,97,99,7,38,69,100,101],"class_list":["post-186","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wordpress","tag-lemp-stack","tag-lets-encrypt","tag-mariadb","tag-nginx","tag-php-fpm","tag-server-tutorials","tag-ubuntu","tag-ubuntu-26-04","tag-ubuntu-vps","tag-wordpress","tag-wp-cli"],"_links":{"self":[{"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/posts\/186","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/comments?post=186"}],"version-history":[{"count":5,"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/posts\/186\/revisions"}],"predecessor-version":[{"id":208,"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/posts\/186\/revisions\/208"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/media\/187"}],"wp:attachment":[{"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/media?parent=186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/categories?post=186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nodeguard.io\/blog\/wp-json\/wp\/v2\/tags?post=186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}