WordPress-Server-Ubuntu-24.04
3 Add WordPress Site

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

  1. 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.

  2. 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.

  3. Grant Privileges:

    GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress_user'@'localhost';

    This grants all privileges on the wordpress database to the wordpress_user.

  4. Apply the Changes:

    FLUSH PRIVILEGES;

    This reloads the privilege tables to ensure that all changes take effect immediately.

  5. 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:

  1. Update DNS records for the domain.
  2. Obtain a new SSL certificate using Certbot.
  3. Set up directories (logs, public) for the new site.
  4. Create a new Nginx server block and enable it by symlinking to sites-enabled.
  5. Create a new MySQL database and user.
  6. 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:

  1. Set Ownership for WordPress Directory:

    sudo chown -R www-data:www-data /var/www/www.example.com/public
  2. 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:

  1. 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
  2. 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

  1. 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.

  2. 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 same server_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)
  3. 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.
  4. 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.

  5. Reload Nginx

    Apply the changes by reloading Nginx:

    sudo service nginx reload

Summary

  1. Search for conflicting server_name directives.
  2. Review and edit or remove duplicate configurations.
  3. Test the configuration.
  4. 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:

  1. 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 and group directives to your username:

    user = your_username
    group = your_username

    Replace your_username with your actual username.

  2. 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
  3. 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

  1. Check PHP-FPM status and ensure it is running.
  2. Verify PHP-FPM socket path and ensure it matches the Nginx configuration.
  3. Modify PHP-FPM configuration if necessary to run under your user account, and ensure proper permissions.
  4. Check logs for detailed error messages.
  5. Review and confirm Nginx and PHP-FPM configurations.
  6. Restart services to apply changes.

Following these steps should help you identify and resolve the 502 Bad Gateway error effectively.