Configuring Nginx to Serve WordPress Over HTTPS
In the previous chapter, we discussed how to install PHP 8.3, Nginx, WP-CLI, and MySQL, laying the foundation of a Linux web server with a LEMP stack. This guide will walk you through deploying your first WordPress site with HTTPS and HTTP/2 support.
HTTPS Overview
HTTPS is an extension of HTTP/2 that secures communication between a server and a client, encrypting data to ensure only the intended recipient can read it. HTTPS is especially important for sites handling sensitive information, but it has now become standard for all websites. Google also uses HTTPS as a ranking factor.
Domain and DNS Configuration
In the first lab, you set up your server’s domain and configured DNS to point to its IP address. Now, we'll set up the WordPress site’s domain.
For this example, use www.example.com
as your domain, and create a CNAME record pointing to www.example.com
and www.www.example.com
.
Pro Tip: Use CNAME records instead of A records for easier IP address updates.
Obtain an SSL Certificate
To secure your site with HTTPS, you'll need an SSL certificate. We will use Certbot, a free tool provided by Let’s Encrypt, to manage the SSL certificates. First, install Certbot:
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update
sudo apt install certbot python3-certbot-nginx
Now, use the Nginx Certbot plugin to obtain a certificate. The certificate can cover multiple domains (up to 100) by appending additional -d
flags:
sudo certbot --nginx certonly -d www.example.com -d www.www.example.com
During the process, Certbot will ask for your email address and terms agreement. After this, the certificate will be generated. Make sure to note the location of the fullchain.pem
(certificate) and privkey.pem
(private key) files:
Certificate is saved at: /etc/letsencrypt/live/www.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/www.example.com/privkey.pem
Certbot automatically renews your certificates, but you can test the renewal process with:
sudo certbot renew --dry-run
Nginx Configuration
For better security and scalability, the preferred approach is to use /var/www/
as the root directory for your web content. This ensures proper permission management, isolation of web applications, and follows best practices for server administration.
Here’s how you can configure Nginx using /var/www/
for your WordPress site.
Step 1: Create a Directory for Your Site
set up your site under /var/www/
. This is where web servers typically store website files.
sudo mkdir -p /var/www/www.example.comhost/public
sudo mkdir -p /var/www/www.example.comhost/logs
Next, adjust the permissions so that Nginx can read and serve the files:
sudo chown -R www-data:www-data /var/www/www.example.comhost
sudo chmod -R 755 /var/www/www.example.comhost
Step 2: Update the Nginx Server Block
Now, create the Nginx server block configuration for your domain. Navigate to the sites-available
directory:
cd /etc/nginx/sites-available
Create a configuration file for your domain:
sudo nano www.example.comhost
In this file, use the following configuration, updating the server_name
, access_log
, error_log
, and root
directives to match the new structure in /var/www/
. Replace the SSL certificate paths accordingly:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name www.example.comhost;
ssl_certificate /etc/letsencrypt/live/www.example.comhost/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.example.comhost/privkey.pem;
access_log /var/www/www.example.comhost/logs/access.log;
error_log /var/www/www.example.comhost/logs/error.log;
root /var/www/www.example.comhost/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name www.www.example.comhost;
ssl_certificate /etc/letsencrypt/live/www.example.comhost/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.example.comhost/privkey.pem;
return 301 https://www.example.comhost$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name www.example.comhost www.www.example.comhost;
return 301 https://www.example.comhost$request_uri;
}
Step 3: Enable the Site
Just like before, enable the site by creating a symlink from sites-available
to sites-enabled
:
sudo ln -s /etc/nginx/sites-available/www.example.comhost /etc/nginx/sites-enabled/
Test the Nginx configuration for syntax errors:
sudo nginx -t
If the test passes, reload Nginx to apply the changes:
sudo service nginx reload
### Step 4: Finalize WordPress Installation
Proceed with the WordPress installation as described previously, using WP-CLI to configure the database and complete the installation. Make sure your web root is updated to reflect the new directory structure in `/var/www/`.
---
By following these steps, you adhere to best practices for file storage and security. Using `/var/www/` ensures that your websites are organized in a standard directory structure and accessible only by the Nginx process running under the `www-data` user. This setup is more secure and scalable for hosting multiple websites.
---
## Enable the Site
Nginx loads configuration files from the `sites-enabled` directory. Create a symlink from your newly created configuration file to enable the site:
```bash copy
sudo ln -s /etc/nginx/sites-available/www.example.com /etc/nginx/sites-enabled/www.example.com
Test the configuration to ensure there are no syntax errors:
sudo nginx -t
If the test passes, reload Nginx to apply the changes:
sudo service nginx reload
Create a WordPress Database
Log in to MySQL as the root user:
mysql -u root -p
Create a new database and a dedicated MySQL user for the WordPress site:
Your MySQL commands for setting up the database and user look good. Here’s a brief explanation of each command to ensure everything is clear:
MySQL Commands to Setup Database and User
-
Create the Database:
CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;
This creates a new database named
wordpress
with the specified character set and collation. -
Create the User:
CREATE USER 'wordpress_user'@'localhost' IDENTIFIED BY 'password';
This creates a new MySQL user
wordpress_user
with the specified password. Make sure that the password satisfies the policy you set earlier. -
Grant Privileges:
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress_user'@'localhost';
This grants all privileges on the
wordpress
database to thewordpress_user
. -
Apply the Changes:
FLUSH PRIVILEGES;
This reloads the privilege tables to ensure that all changes take effect immediately.
-
Exit MySQL:
exit;
Install WordPress
Navigate to your site’s public
directory:
cd /var/www/domain/public
Download WordPress using WP-CLI:
sudo -u www-data wp core download
Configure WordPress using your database credentials:
sudo -u www-data wp core config --dbname=wordpress --dbuser=wordpress_user --dbpass='password'
This should now work without permission errors, assuming the credentials match what you used in the GRANT
command.
Finally, install WordPress:
sudo -u www-data wp core install --skip-email --url=https://www.example.com --title="My WordPress Site" --admin_user=user --admin_email=user@www.example.com --admin_password='password'
Finally, install WordPress:
wp core install --skip-email --url=https://www.example.com --title="My WordPress Site" --admin_user=user --admin_email=user@www.example.com --admin_password='password'
Adding Additional Sites
You can host multiple sites by following the steps below for each new site:
- Update DNS records for the domain.
- Obtain a new SSL certificate using Certbot.
- Set up directories (
logs
,public
) for the new site. - Create a new Nginx server block and enable it by symlinking to
sites-enabled
. - Create a new MySQL database and user.
- Install WordPress using WP-CLI.
Troubleshooting
If you encounter permissions issues when downloading WordPress or using WP-CLI, follow these steps:
Issue: Directory Not Writable by Current User
If you see an error like Error: '/var/www/www.example.com/public/' is not writable by current user
, follow these steps:
-
Set Ownership for WordPress Directory:
sudo chown -R www-data:www-data /var/www/www.example.com/public
-
Set Correct Permissions:
sudo find /var/www/www.example.com/public -type d -exec chmod 755 {} \; sudo find /var/www/www.example.com/public -type f -exec chmod 644 {} \;
Issue: WP-CLI Cache Directory Permission Denied
If you encounter a warning such as Failed to create directory '/var/www/.wp-cli/cache/': mkdir(): Permission denied
, follow these steps:
-
Create and Set Ownership for Cache Directory:
sudo mkdir -p /var/www/.wp-cli/cache/ sudo chown -R www-data:www-data /var/www/.wp-cli
-
Set Correct Permissions:
sudo chmod -R 755 /var/www/.wp-cli/cache/
Retry WordPress Download
After fixing the permissions, retry the WordPress download command:
sudo -u www-data wp core download
Issue: multiple Nginx server blocks with conflicting server_name
directives.
Steps to Resolve Conflicting Server Names
-
Locate the Conflicting Configurations
Check for multiple server blocks with the same
server_name
. You can search through your Nginx configuration files:grep -r 'server_name wpdev.yourbestbuystore.com' /etc/nginx/
This command will show you all the locations where
wpdev.yourbestbuystore.com
is used. -
Review and Edit Configuration Files
Review the files identified by the
grep
command and ensure that each domain is defined only once. Make sure there are no duplicate server blocks with the sameserver_name
directive.Common directories to check include:
/etc/nginx/sites-available/
/etc/nginx/sites-enabled/
/etc/nginx/conf.d/
/etc/nginx/nginx.conf
(if you have included other configuration files)
-
Remove or Merge Duplicate Configurations
If you find duplicates:
- Remove Duplicate Files: If the duplication is across different files, you might remove one of the conflicting files.
- Merge Configurations: If the duplicates are within the same file, consolidate the server blocks.
-
Test Nginx Configuration
After making changes, test the Nginx configuration to ensure there are no syntax errors:
sudo nginx -t
If there are no errors, proceed to reload Nginx.
-
Reload Nginx
Apply the changes by reloading Nginx:
sudo service nginx reload
Summary
- Search for conflicting
server_name
directives. - Review and edit or remove duplicate configurations.
- Test the configuration.
- Reload Nginx to apply changes.
These steps should help resolve the conflicting server name warnings.
Issue: Troubleshooting 502 Bad Gateway Error
A 502 Bad Gateway error usually indicates that Nginx is having trouble communicating with PHP-FPM. Here are some steps to try and resolve this issue:
1. Check PHP-FPM Status
Ensure PHP-FPM is running properly:
sudo systemctl status php8.3-fpm
If it's not running, start it:
sudo systemctl start php8.3-fpm
To ensure it starts on boot:
sudo systemctl enable php8.3-fpm
2. Verify PHP-FPM Socket Path
Ensure the PHP-FPM socket path in your Nginx configuration matches the actual path:
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
Check if the socket file exists:
ls -l /run/php/php8.3-fpm.sock
If the file does not exist, PHP-FPM might not be configured correctly.
3. Modify PHP-FPM Configuration
If you are running PHP-FPM under your own user account instead of the default www-data
, update the PHP-FPM pool configuration:
-
Locate and Edit the Configuration File
Open the configuration file for editing:
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
Change the
user
andgroup
directives to your username:user = your_username group = your_username
Replace
your_username
with your actual username. -
Ensure Permissions
Make sure PHP-FPM has the necessary permissions for the directories and files it needs to access:
sudo chown -R your_username:your_username /var/www/your_site
-
Restart PHP-FPM and Nginx
After making changes, restart both services:
sudo systemctl restart php8.3-fpm sudo systemctl restart nginx
4. Check Nginx and PHP-FPM Logs
Examine the Nginx error logs for details:
sudo cat /var/log/nginx/error.log
Also, check the PHP-FPM logs:
sudo cat /var/log/php8.3-fpm.log
5. Review Nginx Configuration
Ensure Nginx is correctly configured to communicate with PHP-FPM. Here’s a sample configuration snippet:
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
6. Restart Services
After any configuration changes, restart Nginx and PHP-FPM:
sudo systemctl restart php8.3-fpm
sudo systemctl restart nginx
Summary
- Check PHP-FPM status and ensure it is running.
- Verify PHP-FPM socket path and ensure it matches the Nginx configuration.
- Modify PHP-FPM configuration if necessary to run under your user account, and ensure proper permissions.
- Check logs for detailed error messages.
- Review and confirm Nginx and PHP-FPM configurations.
- Restart services to apply changes.
Following these steps should help you identify and resolve the 502 Bad Gateway error effectively.