Install WordPress on Ubuntu 20.04 with Nginx, MariaDB, PHP7.4 (LEMP)
This tutorial is going to show you how to install WordPress on Ubuntu 20.04 with Nginx, MariaDB and PHP7.4 (LEMP Stack). WordPress is the most popular CMS (Content Management System) in the world. It is estimated that more than a third of websites today are powered by WordPress. PHP7.4 made into the Ubuntu 20.04 repository and WordPress runs perfectly with it.
Prerequisite
To follow this tutorial, you need to have an Ubuntu 20.04 server with at least 1GB RAM. If you are looking for a VPS (Virtual Private Server), then you can click this special link to get $50 free credit on DigitalOcean. (For new users only). If you are already a DigitalOcean user, then you can click this special link to get $50 free credit on Vultr (for new users only).
You also need a domain name, so visitors can type a domain name in the web browser address bar to access your site. I registered my domain name at NameCheap because the price is low and they give whois privacy protection free for life.
This tutorial assumes that you have already set up a LEMP stack on Ubuntu 20.04. If not, please check out the following tutorial.
After finishing LEMP installation, come back here and read on.
Step 1: Download WordPress
SSH into your Ubuntu 20.04 server and update existing software.
sudo apt update && sudo apt upgrade
Next, go to wordpress.org download page and download the zip archive. You can acquire the direct download link by right-clicking the download button and select copy link location
.
Then at the command line prompt, type in wget followed by the direct download link to download WordPress to your Ubuntu 20.04 server.
wget https://wordpress.org/latest.zip
Next, extract the zip archive using the command below.
sudo apt install unzip sudo mkdir -p /usr/share/nginx sudo unzip latest.zip -d /usr/share/nginx/
The archive will be extracted to /usr/share/nginx/
directory. A new directory named wordpress
will be created (/usr/share/nginx/wordpress). Now we can rename it like below, so it’s easy for us to identify each directory. Replace example.com
with your real domain name.
sudo mv /usr/share/nginx/wordpress /usr/share/nginx/example.com
Step 2: Create a Database and User for WordPress Site
Log into MariaDB shell as root with the following command.
sudo mariadb -u root
or
sudo mysql -u root
Once you are logged in, create a database for WordPress using the following command. I named it wordpress
, but you can use whatever name you like such as your site name. (Don’t leave out the semicolon.)
create database wordpress;
Then enter the command below to create a database user for WordPress. This command also grants all privileges of WordPress database to the user. Replace wpuser
and your-password
with your preferred username and password.
grant all privileges on wordpress.* to wpuser@localhost identified by 'your-password';
Flush the privileges table for the changes to take effect and then get out of MariaDB shell.
flush privileges; exit;
Step 3: Configure WordPress
Go to your WordPress directory.
cd /usr/share/nginx/example.com/
Copy the sample configuration file and rename it to wp-config.php
.
sudo cp wp-config-sample.php wp-config.php
Now edit the new config file with a command-line text editor like Nano.
sudo nano wp-config.php
Find the following lines and replace the red texts with the database name, username and password you created in the previous step.
/** The name of the database for WordPress */ define('DB_NAME', 'database_name_here'); /** MySQL database username */ define('DB_USER', 'username_here'); /** MySQL database password */ define('DB_PASSWORD', 'password_here');
Then scroll down to find the following line.
$table_prefix = 'wp_';
By default, every WordPress database table name begins with wp_
as the prefix. It’s highly recommended to change it to something else to improve security. Use random characters like below.
$table_prefix = '9OzB3g_';
Save and close the file. To save the file in Nano text editor, press Ctrl+O
, then press Enter
to confirm. Next, press Ctrl+X
to exit.
We also need to set the Nginx user (www-data
) as the owner of the WordPress site directory by using the following command.
sudo chown www-data:www-data /usr/share/nginx/example.com/ -R
Step 4: Create an Nginx Server Block for WordPress
We will create the server block file in /etc/nginx/conf.d/
directory. The file name must end with .conf
.
sudo nano /etc/nginx/conf.d/example.com.conf
Put the following texts into the file. Replace the red texts with your own domain name. Don’t forget to create A records for your domain name in your DNS manager.
server { listen 80; listen [::]:80; server_name www.example.com example.com; root /usr/share/nginx/example.com/; index index.php index.html index.htm index.nginx-debian.html; location / { try_files $uri $uri/ /index.php; } location ~ ^/wp-json/ { rewrite ^/wp-json/(.*?)$ /?rest_route=/$1 last; } location ~* /wp-sitemap.*\.xml { try_files $uri $uri/ /index.php$is_args$args; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; client_max_body_size 20M; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { fastcgi_pass unix:/run/php/php7.4-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; include snippets/fastcgi-php.conf; fastcgi_buffers 1024 4k; fastcgi_buffer_size 128k; # Add headers to serve security related headers add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header X-Permitted-Cross-Domain-Policies none; add_header X-Frame-Options "SAMEORIGIN"; } #enable gzip compression gzip on; gzip_vary on; gzip_min_length 1000; gzip_comp_level 5; gzip_types application/json text/css application/x-javascript application/javascript image/svg+xml; gzip_proxied any; # A long browser cache lifetime can speed up repeat visits to your page location ~* \.(jpg|jpeg|gif|png|webp|svg|woff|woff2|ttf|css|js|ico|xml)$ { access_log off; log_not_found off; expires 360d; } # disable access to hidden files location ~ /\.ht { access_log off; log_not_found off; deny all; } }
Save and close the file. Then test Nginx configurations.
sudo nginx -t
If the test is successful, reload Nginx.
sudo systemctl reload nginx
Enter your domain name in the browser address bar.
example.com
or
example.com/wp-admin/install.php
You shall see the WordPress installation wizard. Select a language.
If the installation wizard isn’t displayed, you probably need to install some PHP7 extensions.
sudo apt install php-imagick php7.4-fpm php7.4-mbstring php7.4-bcmath php7.4-xml php7.4-mysql php7.4-common php7.4-gd php7.4-json php7.4-cli php7.4-curl php7.4-zip
Then reload PHP-FPM and Nginx. The wizard should now be displayed.
sudo systemctl reload php7.4-fpm nginx
Before entering your sensitive information in the setup wizard, it’s recommended to enable HTTPS to prevent traffic hijacking.
Step 5: Enabling HTTPS
To encrypt the HTTP traffic, we can enable HTTPS by installing a free TLS certificate issued from Let’s Encrypt. Run the following command to install Let’s Encrypt client (certbot) on Ubuntu 20.04 server.
sudo apt install certbot python3-certbot-nginx
And run this command to obtain and install TLS certificate.
sudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp --email [email protected] -d yourdomain.com,www.yourdomain.com
Wher
--nginx
: Use the Nginx plugin.--agree-tos
: Agree to terms of service.--redirect
: Force HTTPS by 301 redirect.--hsts
: Add the Strict-Transport-Security header to every HTTP response. Forcing the browser to always use TLS for the domain. Defends against SSL/TLS Stripping.--staple-ocsp
: Enables OCSP Stapling. A valid OCSP response is stapled to the certificate that the server offers during TLS.--email
: Email used for registration and recovery contact.-d
flag is followed by a list of domain names, separated by comma. You can add up to 100 domain names.
The certificate should now be obtained and automatically installed.
Now if you reload the WordPress setup wizard, you can see that HTTP is automatically redirected to HTTPS connection.
Step 6: Finish the Installation with the Setup Wizard
Create an admin account and click the Install WordPress button.
And now your new WordPress site is installed.
How to Redirect www to non-www (Or Vice Versa)
We have already enabled redirecting HTTP to HTTPS, what’s left to do is redirect www to non-www, or vice versa. It’s very easy. Simply go to WordPress Dashboard > Settings > General and set your preferred version (www or non-www) in WordPress Address and Site Address. Be sure to include the https://
prefix.
How to Send Emails in WordPress
Your WordPress site needs to send emails like account registration emails, password-resetting emails, comment notification emails, etc. Instead of using expensive third-party solutions like Gsuite to create professional email addresses for your website, you can follow this iRedMail tutorial to set up your own mail server with your own domain name, so you can have unlimited mailboxes and send unlimited emails without breaking the bank.
Note that it’s a good practice to install mail server and WordPress on two different virtual private servers because you don’t want the mail server to slow down your WordPress site speed, and the mail server will leak the IP address of your WordPress site if they are on the same virtual private server, which means hackers can bypass any CDN (Content Delivery Network) you are using and launch DDoS attack directly at your origin server.
Once your mail server is up and running, you can install an SMTP plugin in WordPress, so it can connect to your mail server and send emails. Go to your WordPress dashboard -> Plugins, click Add New to install a new plugin.
Then type in WP Mail SMTP in the search box. Install and activate the WP Mail SMTP by WPForms plugin.
Reload the WordPress dashboard web page, you will see WP Mail SMTP on the left menu bar. Click on it and select Settings.
Then scroll down to the Mailer section. By default, the PHP mailer is selected. We need to change it to Other SMTP.
Scroll down and you will need to enter the SMTP settings.
- Enter the hostname of your mail server.
- Select TLS as Encryption.
- Use port 587.
- Enable Authentication.
- Enter an email address of your domain and the password.
After saving the settings, you can test email sending by logging out the WordPress dashboard, and click lost your password link to send a password-resetting email.
Increase Upload File Size Limit
By default, files such as images, PDF files uploaded to the WordPress media library can not be larger than 2MB. To increase the upload size limit, edit the PHP configuration file.
sudo nano /etc/php/7.4/fpm/php.ini
Find the following line (line 846).
upload_max_filesize = 2M
Change the value like below:
upload_max_filesize = 20M
Then find the following line (line 694).
post_max_size = 8M
Change the maximum size of POST data that PHP will accept.
post_max_size = 20M
Save and close the file. Alternatively, you can run the following two commands to change the value without manually opening the file.
sudo sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 20M/g' /etc/php/7.4/fpm/php.ini sudo sed -i 's/post_max_size = 8M/post_max_size = 20M/g' /etc/php/7.4/fpm/php.ini
Then restart PHP-FPM.
sudo systemctl restart php7.4-fpm
Nginx also sets a limit of upload file size. The default maximum upload file size limit set by Nginx is 1MB. To allow uploading large files to your WordPress site, edit the Nginx configuration file.
sudo nano /etc/nginx/conf.d/example.com.conf
We have already set the maximum file size in this file, as indicated by
client_max_body_size 2M;
You can change it if you prefer, like 20M.
client_max_body_size 20M;
Save and close the file. Then reload Nginx for the changes to take effect.
sudo systemctl reload nginx
Next Steps
I hope this tutorial helped you install WordPress on Ubuntu 20.04 with Nginx, MariaDB and PHP7.4 (LEMP stack). As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks.
Backup is important in case of hacking, data center disasters, etc. You should have a backup strategy for your WordPress site.
- Back Up and Restore MariaDB Databases From the Command line
- Use Duplicati to Back Up Files on Debian, Ubuntu, Linux Mint
Linux Server Performance Tuning and Monitoring
- Easily Boost Ubuntu Network Performance by Enabling TCP BBR
- What is HTTP/2 and How to Enable it on Nginx
- Linux Server Performance Monitoring with Netdata (2022)
WordPress Command Line Utility
- You may also want to use the WP-CLI command-line tool to manage your WordPress site.
- You can use WPScan to scan the vulnerabilities of your WordPress site.
Take care 🙂
Great Instructions LinuxBabe!!!
Thank you!!!
Easy installations following your instructions. I have Nextcloud installed (root dir: /var/www/nextcloud/) as in https://www.linuxbabe.com/ubuntu/install-nextcloud-ubuntu-20-04-nginx-lemp-stack and wanted to add WordPress (root dir :/var/www/wordpress/). https is working for both. I get to the wp-config.php, but I can’t login – always the index page is shown. What should be changed in the nginx config?
Make sure you use the correct web root directory in the Nginx virtual host file.
Thanks for the tutorial. I am just wondering the reasoning behind installing WordPress at /usr/share/nginx location? While I keep installing my WordPress sites in this location, I am just curious.
Thanks
Fred
It doesn’t matter where the web files are stored on the server, as long as the web server can read them.
/var/www/
is an Apache tradition. Nginx officially recommends/usr/share/nginx/
Thanks, Xiao. It’s nice to hear from the experts
Great Ho-Tos, thank you for your time and dedication. Can you show us how to configure/run multiple WP sites/domains in the same server?
I tried using these steps twice to install 2 copies of WordPress on the same AWS EC2 instance. Now the new WordPress site goes to the first website when I type in the web address. Any thoughts on how to fix this? Thanks!
If you install 2 WordPress sites on the same server, you need to do the following:
1. Use different web root directories:
/usr/share/nginx/example.com
and/usr/share/nginx/example.org
2. Use different database name:
wordpress 1
andwordpress2
3. Create separate Nginx virtual host files:
/etc/nginx/conf.d/example.com.conf
and/etc/nginx/conf.d/example.org.conf
. Make sure you use the correct web root directory in each virtual host file.I followed your script everything was working until when i installed SSL certificate for the site it stopped working attached is the screenshot
Thanks for the great tutorial! However while starting the installation it cannot connect to the database :/
The following error appears:
Cannot select database
The database server could be connected to (which means your username and password is okay) but the test database could not be selected.
First of all, thank linuxbabe for making this website, it is very helpful to me!
I ran into a serious problem when I followed this article to install and use wordpress.
When I use the REST API of woocommerce, if I execute DELETE, all files in the working directory of wordpress will be deleted.
When I deleted the below section of NGINX configuration, it returned to normal.
——————————————————————-
location ~ ^/wp-json/ {
rewrite ^/wp-json/(.*?)$ /?rest_route=/$1 last;
}
——————————————————————-
However, this broke things (the buttons wouldn’t actually logout/empty-cart) on my WordPress Woo Commerce “Account Logout” button, as well as my Woo Commerce “Empty Cart” button.
In your virtual host config you have:
However, this broke things (the buttons wouldn’t actually logout/empty-cart) with my Woo Commerce “Account Logout” button, as well as my Woo Commerce “Empty Cart” button. What worked for me was…
However in other tutorials I’ve also seen…
which also fixed my logout/empty cart problems. So my question is, what is the difference between…
and
and
Could you please elaborate and let me know why 1 of these broke wordpress and 2 of them fixed it? Which one should I actually be using?
This is what I meant to post in the above ^^^^^ Post. Please read this one:
In your virtual host config you have:
However, this broke things (the buttons wouldn’t actually logout/empty-cart) with my Woo Commerce “Account Logout” button, as well as my Woo Commerce “Empty Cart” button. What worked for me was…
However in other tutorials I’ve also seen…
which also fixed my logout/empty cart problems. So my question is, what is the difference between…
and
and
Could you please elaborate and let me know why 1 of these broke wordpress and 2 of them fixed it? Which one should I actually be using?
In the
file, it lists something like this:
or this
But I’m not sure exactly which one it uses because I’m using Nginx Mainline, which doesn’t come with the snippets folder upon installation. So my question is, what is the
line inside
file, supposed to look like? Would it be any different for Nginx Mainline?