How to Install WordPress Using Nginx on Ubuntu 22.04

How to Install WordPress on Ubuntu 22.04 Using LEMP Stack (NGINX)

In this tutorial we will learn how to install WordPress on your Ubuntu 22.04 server with LEMP (Linux, Nginx, MariaDB, and PHP) stack. From first launch to ready-to-browse.

In a Linux server there are various applications we can use as a web server. The two most popular web servers in the market are the Apache HTTP Server and NGINX .

While there are others, these two dominate almost all of the market. In this tutorial we will focus on learning how to serve WordPress using NGINX, using the combination of applications commonly known in acronyms as the LEMP stack.

What is LEMP stack?

LEMP is a combination of applications used together to serve web pages.

This combination has everything necessary for you to be able to host a website publicly on the internet.

LEMP is a variation of another popular combination called LAMP stack. LEMP is an acronym and the letters:

  • L stands for Linux, in this case we are going to be using Ubuntu 22.04
  • E stands for NGINX (NGINX is pronounced Engine X in English thus making sense of the E acronym)
  • M stands for MySQL, a database application
  • P is for PHP, a programming language.

Our specific application versions we will be using in this example is Ubuntu 22.04 as our Linux operating system. NGINX version 1.2 as our web serving application. MySQL 8.3 as our database management system. And PHP-FPM 8.1 as our PHP process manager.

Why are we using these applications specifically?

For MySQL and PHP it’s always best practice to use the latest version of the applications, because of security reasons and to take advantage of the latest features.

The open source free version of NGINX has two versions available, the stable and mainline versions, version 1.2 and 1.21 respectively. For NGINX we choose the stable version for stability reasons, the stable version receives new features later than the mainline version but there are less chances of finding bugs. The mainline version is more similar to a beta version although more reliable than a regular beta application.

99% of the time when using applications in a live production environment, always choose the stable version unless you desperately want a feature not available in the stable version.

It’s not necessary to always have the latest version, I know that it can be very appealing to always choose the latest but in live production, stability is king.

So we should always resist the temptation to install the latest version or upgrade as soon as a new version comes out. In a general sense in a Linux server, upgrading major versions of software shouldn’t be performed. Minor updates, what in Linux are called point release updates, are okay to do.

But major version upgrades are extremely discouraged, as every single major change has the possibility to break the live environment, and in a web serving scenario like in this tutorial that means it could break your website.

Finally the main component of our LEMP stack, the L of our Linux operating system, is going to be Ubuntu 22.04 LTS.

The version 22.04 of Ubuntu is an LTS release which stands for Long Term Support.

Canonical, the company behind Ubuntu, releases yearly updates to its operating system. Every two years that release is an LTS release. LTS versions are designed to be used in live production environments as they are destined to be supported for 5 years, which is a good enough long time to run a production web serving server.

It’s important and recommended to run WordPress on a LEMP stack on an LTS Ubuntu operating system because once you have a working, secured server you don’t want to be changing and upgrading components as they fall out of the support period.

So choosing the latest LTS release is the recommended practice even if it came out a year prior. The version we will be installing came out on April 21, 2022.

Why serve WordPress with NGINX

NGINX was written by Igor Sysoev in 2004 out of frustration with the web servers of the time.

Those servers weren’t very well prepared to handle thousands of concurrent connections.

Thousands of concurrent connections means that thousands of people are trying to access the same website at the same time.

To have a website with millions of visitors per month was out of the reach of most people financially. Only the big enterprises had the budget to actually run huge websites.

What was available to regular people was good to serve only a small amount of concurrent visitors.

Then Igor innovated the market by releasing the first version of NGINX designed to have an event-driven asynchronous architecture well capable to serve thousands of visitors at the same time.

Asynchronous architecture means that NGINX can handle a lot of those requests at the same time without waiting for each request to finish before starting the next one.

NGINX quickly got adopted by professional system administrators to run most enterprise websites.

As the web matured through the years to serve more dynamic, API driven, media heavy content, NGINX kept pace with the changes and it’s now considered the king of web servers. It is very well capable of handling advanced new web technologies like WebSockets, HTTP/2, compressions, and video streaming, stuff that makes up most of the modern web.

Thus when choosing to host WordPress we will want to host with the best web serving application we can install on our operating system.

Now we know the basis of what a LEMP stack is and why we choose to use it to run our WordPress website. Now let’s get to installing all the stack.

Installing Ubuntu 22.04

Installing Ubuntu 22.04 itself is not something we have to worry about on most web hosts. The process of installing Ubuntu is only needed when renting a bare metal server that has absolutely nothing installed on it prior.

Most of the VPS and web hosting cloud companies that the majority of people will contract already have an image of the Ubuntu OS and when ordering service they pre-install that image on it for you.

It’s an important thing to note because newer Linux and cloud computing users get confused trying to understand how to install Ubuntu on a server that it already is an Ubuntu installation, this distinction is not so well explained on most guides.

So in this tutorial we assume that you will get a regular pre-installed Ubuntu server from a popular cloud computing company, and thus the first leg of our LEMP stack is already done for us.

In this example we ssh login to our Ubuntu server we named “lempstacked”. lempstacked is a server that is not known to our local computer, so our local computer ask if we trust it, we input yes and then we are asked for our password, once we input that in we are officially connected through the ssh protocol and have full control of the Ubuntu 22.04 server.

To verify we check the release information and we see that it is indeed Ubuntu 22.04 LTS that we are running.

ssh lempstacked

And after you’ve logged into your server:

lsb_release -a
Note that lempstacked is a nickname we gave to the server in our local computer’s ssh config file.

We can do absolutely the same identical step as using the username and IP address of the server, in this case we are logging in as the root user of the server with the IP address

If you don’t have an alias (nickname) set up for your server, you can just login using the following syntax:

ssh root@your_server_ip

In my case I’ll run:

ssh [email protected]

word image 111

The L in our LEMP stack is here and ready so we can proceed.

Preparing the Ubuntu Environment for a LEMP stack

Creating a User in Ubuntu

Now we will create a user account that will manage our LEMP stack. Connected as root through SSH we will create the user with the following command.

adduser tupacshakur

Here we created a user tupacshakur and we gave it a strong random password. As a security feature of Ubuntu it is to not allow easy passwords like those based on dictionary words or simplistic ones like passw0rd. Then we skipped the other unnecessary questions and confirmed that everything was correct.

Granting User Privileges in Ubuntu

Right now we have the user tupacshakur which is just a regular user.

Regular users don’t have much of the admin rights that are necessary to run our stack. So we will grant it some privileges. These privileges work by using a special command before executing regular commands in the command line when connected as this user.

The special command is called sudo.

When our user tupacshakur tries to run a command that only a server admin can perform such as the reboot command to restart the server, Ubuntu 22.04 will not allow him. He will only be allowed to execute this if he first adds the magic word before it. If tupacshakur writes sudo reboot only then will the server restart.

As you can see, this sudo power is very strong, almost like being root. So we grant this power only to computer users that absolutely need it. This new breed of user in the computer is called a superuser.

Let’s make tupacshakur a sudoer by putting him in the user group called sudo group. The rights of the sudo users are set in the configuration to this group.

usermod -aG sudo tupacshakur

Using the usermod utility we told it to append the user tupacshakur to the user group sudo.

The -a option told it to append the user to the sudo group. Without the -a option the default group of the user would change. That would be bad. That is because user groups are set to have common rights. The rights of sudo users are to grant only limited, highly powerful rights.

This sudo group doesn’t have all the complete, extensive, functioning rights a user needs to be a user in this computer. Meaning if we change the user group of tupacshakur it would become a broken user. Again, there are a lot of guides out there that recommend changing a group instead of appending.

You should always append a user to the sudo group with the -a option. The -G option simply tells that the user settings will be altered.

Installing NGINX

Now we will install the NGINX web server, the application and configuration that actually publishes the website to the public web.

We’re going to grab NGINX from the apt repository.

Before proceeding, let’s exit our root user and let’s connect as tupacshakur. We’re going to install everything from our new user.

And now we are connected as the tupacshakur user.

By the way, did you notice how fast I was able to type ssh [email protected]?

That is because of the magical power of fzf, a utility to improve your workflow on the command line. Learn more about fzf at How to Use fzf Command-Line Fuzzy Finder.

Before we download NGINX we have to refresh the apt list of available apps for download to make sure we get the latest version available from the apt repository by running the following command.

sudo apt update

And then, if there are any updates available, follow by.

sudo apt upgrade

For us there weren’t updates available so we are good to go.

Notice that before using sudo it asked us for our password? That is because, when connecting as a sudo user, on the first sudo command it always needs to verify your identity with your user password.

On subsequent uses of sudo commands in the same session, it will not ask you for it. Once disconnected, in the next session it will ask you again.

Now let’s download and install NGINX on our server.

sudo apt install nginx

Immediately after running that command, apt tells us which additional packages need to be installed and which additional packages are optionally available to be installed.

Proceeding with the installation, it then asks us which running services on Ubuntu we want to restart to get them to recognize our new installed NGINX toy. It pre-seletcs which ones are necessary or recommended, we just leave it as is to not complicate the installation process and press enter on OK.

And voilà, NGINX is installed.

Ubuntu comes with a firewall to block unwanted connections.

Your server will receive hundreds or even thousands of connection attempts daily from bots that are searching for unsecure servers.

Never run a server exposed to the internet without a firewall, never disable a firewall for prolonged periods of time.

The firewall is an important tool for keeping your server secure, and its basic function from the outside is to block unwanted connections, but from the inside the basic function is to stop any application running on your machine from accidentally exposing itself to the internet.

The firewall will control what is accessible from the public internet.

There are various firewalls that you can install on your Ubuntu 22.04 machine but the one that comes by default is the ufw firewall. We need to tell ufw to allow NGINX to expose itself to the internet so that NGINX can perform its function to act as a web server.

sudo ufw allow 'Nginx HTTP'

ufw then updates its rules to allow NGINX to be exposed to the internet. We repeat the same command but with HTTPS to allow secure connections.

sudo ufw allow 'Nginx HTTPS'

Then we verify if the rules are applied by running the following command.

sudo ufw status verbose

word image 112

This tells us that port 80 and port 443 are open and assigned to NGINX to allow connections into our machine from any IP in the world. It tells us the same for the v6 (IPv6) version.

Port 80 is for unencrypted website visits made to http and port 443 are for secure connections made to https.

The v6 part is to accept IPv6 connections, IPv6 is a protocol that allows internet service providers a much greater amount of combinations of IP addresses. Each internet user is assigned an IP address by their provider and with billions of devices connected to the internet around the world lots of companies are using the IPv6 standard. NGINX serves those visitors using IPv6 natively.

Now that we modified our firewall rules to allow NGINX to be exposed to the internet, we check if it’s live by visiting the IP address of our server on a browser.

Success! The web page tells us that if we see that page, then it means the NGINX web server is successfully installed and working.

word image 113

Installing MySQL

Now that we have a working web server we will install MySQL, this application will serve us as the relational database that WordPress will utilize to save its structure and content in.

Here first we install MySQL with the command.

sudo apt install mysql-server

Again apt asks us for our sudo password as we invoked it to be able to install.

Then it proceeded to tell us how many additional packages it needed to install as dependencies of MySQL. It told us 28 new dependencies will be installed with a total size of 240 MB. We agreed to it and it installed them, now MySQL is installed. Lastly it asked us which services running on our Ubuntu machine currently needed to be restarted so changes could take effect, which we proceeded to skip.

Secure MySQL With the Secure Installation Script

MySQL can be a complex piece of software. A misconfiguration can allow our server to be hacked.

So right away we told it to run a script that comes bundled with MySQL to secure our server. It’s always best practice to perform this task, or the tasks this script does manually. The script is run by the following command.

sudo mysql_secure_installation

First of all this script connects us to MySQL. The script asks us a series of questions that will make our installation more secure. Unless you have a valid reason and are experienced enough, the answers to these questions should always be yes.

The first question is about VALIDATE PASSWORD COMPONENT, this is a component that prevents users from using simple passwords like dictionary words and simple combinations like passw0rd2.

When setting up a new database password this component will check for the password strength. This, 95% of times, will be great for the security of your MySQL installation but at times it can have conflict with some external web applications that access the database.

If down the road there’s a conflict that can’t be resolved because of this password checking component, then it can be disabled as needed.

The second question it asked is about the level of strength you want this check to be with three choices being LOW, MEDIUM or STRONG. I proceeded with low.

Then the script asked for a password to the root user of MySQL. Don’t confuse this with being the root user of your Ubuntu machine. This is a separate root user for MySQL only. This root user will have full admin rights to manage everything and it’s needed for the management of MySQL.

We proceeded by giving it a secure password that it accepted satisfyingly with a score of 100. A low scoring password might be insecure, so we have a chance to change it at this point if we wanted. We were satisfied with this score so we proceeded.

The third question is about disallowing root login from outside the server, remotely from another computer on the internet.

Having remote access to a database on a server is how more complex websites run their stacks, it’s common and needed when running huge websites that need multiple servers to handle hundreds of thousands of concurrent users.

But to allow the root user to be accessed remotely is considered a bad practice. It can be done but it’s not recommended for inexperienced database managers.

Just simply giving it access will make your server a big target for hack attempts and overall unwanted bot traffic. So we proceed by disallowing remote access to the root.

Next it asks if we want to reload the privileges table for changes to take effect and we do. Now that’s the end to the script and for providing some basic security to our database engine that is MySQL.

If we run the following command we can check which version it installed.

mysql -V

And we can get information about the running status with the command.

sudo service mysql status

word image 114

Now we have a running MySQL instance that can be used by our WordPress application.

Installing PHP

Now we are advancing deep into the LEMP stack, and we have only one of the puzzle pieces left to configure before loading WordPress onto our server.

NGINX does not contain a native PHP processing engine like Apache does and thus we need to install an additional piece of software in order for NGINX and PHP to function together. This software is called php-fpm, which fpm stands for fastCGI process manager, and this piece of software also needs itself a helper software of its own called php-mysql. So we will install this with the following command.

sudo apt install php-fpm php-mysql

Again apt tells us what it’s going to install and how many dependencies. 11 additional software totaling 22 MB. We agree to it and it proceeds to install, prompting us at the end if we want to restart any services in Ubuntu. We skip by pressing OK as we don’t want anything restarted.

Now we have to make a few configuration changes in order for NGINX to know how to use our PHP processor engine that we just installed.

Here we are adding a new configuration file for a new site at the location where NGINX stores them. We used as an example but you would use your own domain name in this case.

sudo nano /etc/nginx/sites-available/

We directed the nano text editor to create a new file, we pasted our configuration seen below, saved and exited.

server {
        listen 80;
        root /var/www/html;
        index index.php index.html index.htm index.nginx-debian.html;

        location / {
                try_files $uri $uri/ =404;

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

        location ~ /\.ht {
                deny all;

Again, besides the server_name directive where we placed our IP it’s where you would write your domain name. Just the name and extension and nothing else besides the semicolon at the end. The semicolon (;) must be kept.

For example, my server block, for will look something like this:

server {
        listen 80;
        root /var/www/html;
        index index.php index.html index.htm index.nginx-debian.html;

After creating the server block configuration and saving it, we must now enable it. We do that by creating a symbolic link from the file we just created, which is in the sites-available directory, to the sites-enabled directory that NGINX uses.

sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

And we unlink the default configuration so that our site takes over.

sudo unlink /etc/nginx/sites-enabled/default

Then we test if our configuration file is correct.

sudo nginx -t

word image 115

It tells us that the syntax is correct and the test successful. If we misconfigured the configuration here it would output us which line of the config file is wrong. As everything is correct, we move along.

Finally we reload NGINX for all the changes to take effect.

sudo systemctl reload nginx

Now that everything is set up we will validate that NGINX can send .php files off to our php-fpm processor.

We will do that by creating a PHP file in the public files directory.

We again sudo nano to create the file.

sudo nano /var/www/html/info.php

We pasted a little PHP script to pull the PHP setup info.


We open this .php file in a browser and we get success.

word image 116

Let’s remove that now, as that contains a lot of server information that shouldn’t be made public.

sudo rm info.php

And with this we have concluded the setup of our LEMP stack.

This suite of very powerful utilities known as LEMP can enable us to create any website we want and publish it to the world wide web for the world to visit.

Install WordPress with LEMP on Ubuntu 22.04

Now that we have all the components of the server ready we will install WordPress. First we will make a few preparations before downloading and setting up the application itself.

First we will log into MySQL as the root user to create a database for WordPress.

sudo mysql

This logs us in.

We know we are in MySQL because our prompt starts with mysql>.

Then we will create a new database called wordpressworld.

CREATE DATABASE wordpressworld DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

After we have a database we will create a database username continuing inside MySQL.

CREATE USER 'supermario'@'localhost' IDENTIFIED BY 'bowser_9Es';

This creates us a database user with the name supermario and the password bowser_9Es. Now we will grant our supermario user access to all the rights of the wordpressworld database.

GRANT ALL ON wordpressworld.* TO 'supermario'@'localhost';

Now we have a database and a user to use for WordPress. Finally we type the command inside MySQL to exit.


With WordPress being a monster of an application there are lots of PHP extensions that it can utilize. Let’s install the popular ones with the following command.

sudo apt install php-curl php-gd php-intl php-mbstring php-soap php-xml php-xmlrpc php-zip

After apt finishes doing its thing we have to restart our PHP-FPM procesor.

sudo systemctl restart php8.1-fpm

Now we have all the extensions we can possibly use with WordPress.

We need to go back to the NGINX server block configuration so we can add a few WordPress specific configs.

sudo nano /etc/nginx/sites-available/

And we will add a few location directives.

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;

We will also adjust the try_files location. Let’s comment out the current one and add the following line underneath it.

try_files $uri $uri/ /index.php$is_args$args;

Everything should end up looking like the below example.

word image 117

Let’s again check the configuration syntax

sudo nginx -t

If everything is okay it will tell us that the syntax is ok and the test succesful. If there are errors we go back and edit the configuration. If everything is good we reload NGINX to load the new updated config.

sudo systemctl reload nginx

The prep is done and now we will proceed to install WordPress.

We will change directory to the /tmp directory. In Linux the /tmp directory is for placing stuff that you want to delete after the next boot up or in a pre-determind time, thus being called temporary.

cd /tmp

With the curl utility we will download the files of WordPress from the official WordPress website into our current /tmp direcotry.

curl -LO

When using curl, the -L option tells it to follow redirects if there are any and the -O tells it to make a copy of the file locally in our compuer.

Now we will use the tar utility to untar the content of WordPress that we just downloaded. These are the actual files that WordPress uses.

tar xzvf latest.tar.gz

We will make a copy of the sample config file that WordPress comes with.

cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php

We will copy the entirity of the WordPress directory we just extracted to our public html directory.

sudo cp -a /tmp/wordpress/. /var/www/html

We can change the directory to verify that all the WordPress files are there.

cd /var/www/html && ls

It looks all okay.

We need to give ownership to a user and user group that NGINX creates, this user and group are called www-data. We will give it access to the directory where our WordPress files reside.

sudo chown -R www-data:www-data /var/www/html

Now WordPress can be managed by NGINX because it has the appropriate permissions.

We will move on to the WordPress application configuration. In the wp-config.php file we need to add certain salt keys to make things secure.

These keys are totally random and should never be copied from any tutorial or guide that you find online. It needs to be unique only to your installation. Luckily for us WordPress makes it easy to get these salt keys on the command line with the following command.

curl -s

We copy these keys and then proceed to open our WP config file.

word image 118

sudo nano /var/www/html/wp-config.php

Inside the config in the section of the salt keys you paste the keys that we just copy like this example.

word image 119

Then we provide the database name, database user and database password. In our example case that is wordpressworld, supermario, and bowser_9Es respectively.

word image 120

Below the database connection information, anywhere paste the following code.

define( 'FS_METHOD', 'direct' );

With that setting WordPress is allowed to write directly to the file system. For example when uploading a new picture or plugin.

That is all for the wp-config.php.

We proceed to open our site in a browser. If done everything according to example you should get the WordPress setup wizard. At this point you can be confident that the installtion of WordPress was a success.

word image 121

After finishing the admin setup, you can then proceed to enter the admin dashboard, at or visit the front page of your website.

word image 122


Congratulations, you successfully installed LEMP stack and the WordPress application totally from start to end. Well done!

The LEMP suite of utilities are an amazing piece of free software. It can empower us to create anything we want.

It’s powerful enough to run websites like YouTube and small enough for any hobbies to pick it up and start using in an hours’ time of dedication.

Thanks for reading, now is time for creating.

If you have any feedback or questions feel free to leave us a comment and we’ll get back to you as soon as we can.

Notify of
Receive notifications when your comment receives a reply. (Optional)
Your username will link to your website. (Optional)

Newest Most Voted
Inline Feedbacks
View all comments
1 year ago

Thanks but I get permission denied (publickey) after adduser and the sudo grant. Get also problems seting up pwd for mysql, it requests ALTER USER. I am root, I have keys no pwd to log in, have been since yesterday trying all possible solutions…

1 year ago
Reply to  EdXD

Sorry, only saw it now…

My instance is OCI, I installed ubuntu 22.04 on ARM64.
Downloaded keys and logged with Putty. The last time, I registered a pwd on Putty Gen before saving the private key.

What I can’t remember is if it worked well and then stopped after configuring wp, or if I never got the domain set up.

I opened requests for help in these communities:

I don’t know why the CA came up automatically. The errors are as follow:

– Err_connection_refused (when Cloudflare was paused)
– 521 server is down (when Cloudflare was enabled on complete and full TLS)
– A no html page displaing the wp text and links content. (when Cloudflare is enabled on flex)

  • after pausing cloudflare again, I got ERR_QUIC_PROTOCOL_ERROR

It would help me to get help if I could access the Ngix logs.
I am not a dev, new to linux… but I am thinking Nginx needs to know there is a CA in order for it to allow cloudflare HTTPS…?

1 year ago

thank you so much, It works just fine.

1 year ago

Thanks for the post.
Are you sure the domain will allow unsecured https connection? Shouldn’t it have a config for nginx to call a certificate? I only got to set up on IP, the domain has many problems. 521, ERR_connection, ERR_QUICK_PROTOCOL…
As a sugestion, I would ask you to help up config the logs so we can diagnose what is happening, but please test it before.

You May Also Like
Bash Compare Strings
Read More

Bash Compare Strings

Similar to other programming languages, strings in bash is the datatype that holds a sequence of characters. In…
bash if statement
Read More

Bash if..else Statement

The if..else statements are categorized under conditional statements in bash. They work similarly to the if..else statements in…