Setting up isolated multisite WordPress environments on RHEL 9 using Nginx map directive virtual hosts configuration
Prerequisites and Initial Setup
This guide assumes a fresh RHEL 9 installation with root or sudo privileges. We’ll be setting up a robust, isolated multisite WordPress environment leveraging Nginx’s powerful `map` directive for efficient virtual host routing. This approach is highly scalable and simplifies management compared to traditional per-site Nginx configuration files.
Ensure the following packages are installed. If not, use dnf to install them:
- Nginx
- PHP-FPM (version compatible with your WordPress installation, typically PHP 8.1 or higher on RHEL 9)
- MariaDB or MySQL
php-mysqlnd,php-gd,php-xml,php-mbstring,php-intl,php-opcache,php-fpm
Install necessary packages:
sudo dnf update -ysudo dnf install -y nginx php-fpm php-mysqlnd php-gd php-xml php-mbstring php-intl php-opcache mariadb-server
Start and enable the services:
sudo systemctl start nginx php-fpm mariadbsudo systemctl enable nginx php-fpm mariadb
Secure your MariaDB installation:
sudo mysql_secure_installation
Database Configuration for Multisite
For a multisite setup, a single database is typically used, with WordPress handling the separation of sites through table prefixes. Create a dedicated database and user for your WordPress installation.
-- Connect to MariaDB sudo mysql -u root -p -- Create the database CREATE DATABASE wordpress_multisite CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- Create a user for the database CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'your_strong_password'; -- Grant privileges to the user GRANT ALL PRIVILEGES ON wordpress_multisite.* TO 'wp_user'@'localhost'; -- Apply privileges FLUSH PRIVILEGES; -- Exit MariaDB EXIT;
Replace your_strong_password with a secure password.
Nginx Configuration with the `map` Directive
The core of our isolated multisite setup lies in Nginx’s `map` directive. This allows us to dynamically set variables based on the incoming hostname, which we’ll use to determine the correct PHP-FPM pool and document root. This avoids the need for numerous individual server blocks.
First, create a directory to store your site configurations. This will be managed by the `map` directive.
sudo mkdir -p /etc/nginx/sites-available/sites
Next, create a `map` file that associates hostnames with their respective document roots and PHP-FPM pool configurations. For a multisite, the primary domain will point to the main WordPress installation, and subdomains (or subdirectories, though subdomains are more common with this Nginx setup) will be handled by WordPress’s internal routing.
# /etc/nginx/conf.d/wordpress_map.conf
# Map hostnames to document roots and PHP-FPM pools
map $host $site_config {
hostnames;
# Default site configuration (e.g., for the main domain)
# This will point to your main WordPress installation directory.
# Ensure this directory exists and contains your WordPress files.
default /var/www/html/wordpress_main;
# Example for a specific subdomain/site
# If you have a site like 'blog.example.com', it will also use the main WP install
# and WordPress will handle the routing.
# If you were doing single sites, you'd map them here to their specific directories.
# For multisite, the 'default' is usually sufficient as WP handles subdomains.
# example.com /var/www/html/wordpress_main;
# www.example.com /var/www/html/wordpress_main;
# blog.example.com /var/www/html/wordpress_main;
}
Now, configure the main Nginx server block. This block will use the `$site_config` variable determined by the `map` directive.
# /etc/nginx/nginx.conf (or a new file in /etc/nginx/conf.d/)
# ... other Nginx configurations ...
http {
# ... other http configurations ...
# Include the map file
include /etc/nginx/conf.d/wordpress_map.conf;
# Define PHP-FPM pool for WordPress
# Ensure this matches your PHP-FPM configuration (e.g., /etc/php-fpm.d/www.conf)
# For RHEL 9, the socket is typically /run/php-fpm/www.sock
upstream php_fpm_wp {
server unix:/run/php-fpm/www.sock;
}
# Main server block for WordPress Multisite
server {
listen 80;
server_name example.com *.example.com; # Adjust to your domain(s)
root $site_config; # Use the document root from the map directive
index index.php index.html index.htm;
# Access and error logs
access_log /var/log/nginx/wordpress_access.log;
error_log /var/log/nginx/wordpress_error.log;
# Serve static files directly
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
try_files $uri =404;
}
# Deny access to hidden files
location ~ /\. {
deny all;
}
# Pass PHP scripts to PHP-FPM
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php_fpm_wp; # Use the upstream defined above
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# For WordPress Multisite, ensure the correct SCRIPT_FILENAME is passed
# This is crucial for subsite routing.
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
}
# Rewrite rules for WordPress permalinks
location / {
try_files $uri $uri/ /index.php?$args;
}
}
# ... other server blocks or configurations ...
}
Important Notes on the Nginx Configuration:
- `server_name example.com *.example.com;`: This directive should match your primary domain and any subdomains you intend to use for your multisite network.
- `root $site_config;`: This dynamically sets the document root based on the hostname, as defined in our `map` file. For multisite, this typically points to the single WordPress installation directory.
- `upstream php_fpm_wp`: This defines an upstream server for PHP-FPM. Ensure the socket path (`unix:/run/php-fpm/www.sock`) is correct for your RHEL 9 PHP-FPM installation.
- `fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;`: This is critical for PHP execution.
- `fastcgi_param PATH_INFO $fastcgi_path_info;`: Essential for WordPress’s URL rewriting and multisite subdirectory/subdomain routing.
- `location / { try_files $uri $uri/ /index.php?$args; }`: The standard WordPress rewrite rule.
After creating or modifying these configuration files, test your Nginx configuration and reload the service:
sudo nginx -t sudo systemctl reload nginx
WordPress Installation and Multisite Setup
Now, download and install WordPress into the directory specified by your `map` directive’s default value (e.g., /var/www/html/wordpress_main).
# Navigate to the web root
cd /var/www/html/
# Download WordPress (check for the latest version)
sudo wget https://wordpress.org/latest.tar.gz
# Extract WordPress
sudo tar -xzf latest.tar.gz
# Move extracted files to the desired directory
sudo mv wordpress/ wordpress_main
# Set ownership and permissions
sudo chown -R apache:apache /var/www/html/wordpress_main # Or nginx:nginx if your PHP-FPM runs as nginx
sudo find /var/www/html/wordpress_main -type d -exec chmod 755 {} \;
sudo find /var/www/html/wordpress_main -type f -exec chmod 644 {} \;
sudo chmod 644 /var/www/html/wordpress_main/wp-config.php # Ensure wp-config.php is writable during setup
Navigate to your WordPress installation directory and create the wp-config.php file.
cd /var/www/html/wordpress_main sudo cp wp-config-sample.php wp-config.php
Edit wp-config.php to include your database credentials and enable multisite.
<?php /** * The database name for your WordPress installation. */ define( 'DB_NAME', 'wordpress_multisite' ); /** * MySQL database username. */ define( 'DB_USER', 'wp_user' ); /** * MySQL database password. */ define( 'DB_PASSWORD', 'your_strong_password' ); /** * MySQL hostname. */ define( 'DB_HOST', 'localhost' ); /** * Database Charset to use in creating database tables. */ define( 'DB_CHARSET', 'utf8mb4' ); /** * The Database Collate type. */ define( 'DB_COLLATE', '' ); /** * Authentication Unique Keys and Salts. * * All of these must be unique for each installation and can be generated using * https://api.wordpress.org/secret-key/1.1/salt/ * A good practice is to use a secure password manager or a dedicated tool. */ define( 'AUTH_KEY', 'put your unique phrase here' ); define( 'SECURE_AUTH_KEY', 'put your unique phrase here' ); define( 'LOGGED_IN_KEY', 'put your unique phrase here' ); define( 'NONCE_KEY', 'put your unique phrase here' ); define( 'AUTH_SALT', 'put your unique phrase here' ); define( 'SECURE_AUTH_SALT', 'put your unique phrase here' ); define( 'LOGGED_IN_SALT', 'put your unique phrase here' ); define( 'NONCE_SALT', 'put your unique phrase here' ); /** * For developers: WordPress debugging mode. * * Change this to true to enable the display of notices during development. * It is recommended to leave this as false on production websites. */ define( 'WP_DEBUG', false ); /* That's all, stop editing! Happy publishing. */ /** * WordPress Multisite * * Make WordPress a "network" of sites in a single WordPress installation. * * To multisite: * 1. Add the following line to wp-config.php: */ define( 'WP_ALLOW_MULTISITE', true ); /** * For WordPress Multisite, you'll need to configure the subdirectory or subdomain * installation. For this Nginx setup, subdomain is generally easier. * * If using subdomains: * define( 'SUBDOMAIN_INSTALL', true ); * define( 'DOMAIN_CURRENT_SITE', 'example.com' ); // Your main domain * define( 'PATH_CURRENT_SITE', '/' ); * define( 'SITE_ID_CURRENT_SITE', 1 ); * define( 'BLOG_ID_CURRENT_SITE', 1 ); * * If using subdirectories (requires more complex Nginx/Apache rewrite rules, * and is generally not recommended with this Nginx map setup for simplicity): * define( 'SUBDOMAIN_INSTALL', false ); * define( 'DOMAIN_CURRENT_SITE', 'example.com' ); // Your main domain * define( 'PATH_CURRENT_SITE', '/' ); * define( 'SITE_ID_CURRENT_SITE', 1 ); * define( 'BLOG_ID_CURRENT_SITE', 1 ); */ // Example for Subdomain installation (recommended for this Nginx setup) define( 'SUBDOMAIN_INSTALL', true ); define( 'DOMAIN_CURRENT_SITE', 'example.com' ); // *** CHANGE THIS TO YOUR DOMAIN *** define( 'PATH_CURRENT_SITE', '/' ); define( 'SITE_ID_CURRENT_SITE', 1 ); define( 'BLOG_ID_CURRENT_SITE', 1 ); /** * Multisite specific configurations for Nginx. * * If you are using subdomains, WordPress will handle the routing. * If you are using subdirectories, you might need additional Nginx rules * or a more complex map directive to handle the path-based routing. * For this guide, we assume subdomain installation. */ // Define the base URL for the network define( 'WP_SITEURL', 'http://example.com' ); // For the main site admin define( 'WP_HOME', 'http://example.com' ); // For the main site frontend // If using subdomains, WordPress will automatically handle subsite URLs like http://subsite.example.com // Ensure correct file permissions for wp-config.php after setup // chmod 644 /var/www/html/wordpress_main/wp-config.php ?>
Crucially, replace the placeholder values:
- Generate unique keys and salts from https://api.wordpress.org/secret-key/1.1/salt/ and paste them into the respective
define()statements. - Update
DB_NAME,DB_USER, andDB_PASSWORDto match your database configuration. - Most importantly, set
DOMAIN_CURRENT_SITEto your primary domain (e.g.,'example.com'). - Ensure
SUBDOMAIN_INSTALLis set totruefor this Nginx setup.
After saving wp-config.php, change its permissions back to read-only for security:
sudo chmod 644 /var/www/html/wordpress_main/wp-config.php
Completing the Multisite Setup in the WordPress Admin
Now, access your primary domain (e.g., http://example.com) in your web browser. You should see the standard WordPress installation screen. Complete the initial WordPress setup (site title, admin username, password, email).
Once WordPress is installed, navigate to the Network Setup screen:
- Go to Tools > Network Setup in your WordPress admin dashboard.
- You will be prompted to enable the network. Choose whether to use subdomains or subdirectories (subdomains are recommended for this Nginx configuration).
- Click “Install”.
WordPress will then provide you with two code snippets. You’ll need to add the first snippet to your wp-config.php file and the second snippet to your .htaccess file (though for Nginx, this is handled by the main server block configuration).
Add the following lines to your wp-config.php file (usually just below the WP_ALLOW_MULTISITE definition):
// These are the lines WordPress will provide after Network Setup // Ensure they are consistent with your earlier manual definitions if you defined them. // If you defined them manually, WordPress might not show them again. // If it does, ensure they match. // Example: // define( 'MULTISITE', true ); // define( 'SUBDOMAIN_INSTALL', true ); // define( 'DOMAIN_CURRENT_SITE', 'example.com' ); // define( 'PATH_CURRENT_SITE', '/' ); // define( 'SITE_ID_CURRENT_SITE', 1 ); // define( 'BLOG_ID_CURRENT_SITE', 1 );
For the Nginx configuration, you do NOT need to create or modify a .htaccess file. The rewrite rules are handled within the main Nginx server block. WordPress’s instructions for .htaccess are for Apache servers.
After updating wp-config.php, you will need to log out and log back into your WordPress admin. You should now see “My Sites” in the admin bar, allowing you to manage your network and add new sites.
Testing and Verification
To test your setup, you’ll need to configure your local /etc/hosts file or DNS to point your domain and subdomains to your server’s IP address. For example:
# On your local machine, edit /etc/hosts (Linux/macOS) or C:\Windows\System32\drivers\etc\hosts (Windows) # Add lines like these, replacing YOUR_SERVER_IP and example.com: YOUR_SERVER_IP example.com www.example.com site1.example.com site2.example.com
Now, try accessing:
http://example.com(your main site)http://site1.example.com(a new site created within your multisite network)http://site2.example.com(another new site)
Each of these should load correctly, served by the single WordPress installation but appearing as distinct sites due to WordPress’s multisite routing and Nginx’s ability to handle the hostnames. The `map` directive ensures that all these hostnames correctly resolve to the single WordPress installation directory.
Security and Performance Considerations
Security:
- Keep WordPress, themes, and plugins updated.
- Use strong, unique passwords for database users and WordPress administrators.
- Regularly review Nginx and PHP-FPM logs for suspicious activity.
- Consider implementing a Web Application Firewall (WAF) like ModSecurity.
- Ensure PHP-FPM is configured to run as a non-privileged user.
Performance:
- Enable OPcache for PHP.
- Configure Nginx caching (e.g., using
proxy_cacheor FastCGI cache). - Optimize your database (e.g., using WP-Optimize plugin or regular maintenance).
- Use a CDN for static assets.
- Tune PHP-FPM pool settings (e.g.,
pm.max_children,pm.start_servers) based on your server’s resources.
This advanced Nginx `map` directive approach provides a clean, efficient, and scalable foundation for managing WordPress multisite environments on RHEL 9, minimizing configuration overhead while maximizing flexibility.
Leave a Reply
You must be logged in to post a comment.