BLOG POSTS
Install WordPress with Nginx on Ubuntu

Install WordPress with Nginx on Ubuntu

Setting up WordPress with Nginx on Ubuntu is a cornerstone skill for anyone running serious web operations. Unlike Apache’s module-based approach, Nginx’s event-driven architecture delivers superior performance under high load while consuming significantly less memory. This guide walks you through the complete installation process, from initial server setup to production-ready configuration, including PHP-FPM integration, database setup, and security hardening that you won’t find in basic tutorials.

How Nginx and WordPress Work Together

Nginx operates as a reverse proxy and web server, handling static files directly while passing PHP requests to PHP-FPM (FastCGI Process Manager). This separation creates a more efficient architecture than traditional setups. When a user requests a WordPress page, Nginx first checks if it can serve static content (images, CSS, JS) directly from disk. For PHP files, it forwards the request to PHP-FPM via Unix sockets or TCP, which processes the WordPress code and returns the result.

The key advantage lies in Nginx’s ability to handle thousands of concurrent connections with minimal resource overhead. While Apache creates a new process or thread for each connection, Nginx uses an asynchronous, event-driven model that can serve multiple requests within a single worker process.

System Requirements and Performance Expectations

Component Minimum Specs Recommended Specs High Traffic Specs
RAM 1GB 2GB 4GB+
CPU Cores 1 Core 2 Cores 4+ Cores
Storage 10GB HDD 20GB SSD 50GB+ NVMe SSD
Concurrent Users 100 1,000 10,000+

Step-by-Step Installation Guide

Initial System Update and Package Installation

Start with a fresh Ubuntu installation and update the package repositories:

sudo apt update && sudo apt upgrade -y
sudo apt install nginx mysql-server php-fpm php-mysql php-curl php-gd php-intl php-mbstring php-soap php-xml php-xmlrpc php-zip unzip curl -y

Enable and start the required services:

sudo systemctl enable nginx mysql php8.1-fpm
sudo systemctl start nginx mysql php8.1-fpm

MySQL Database Configuration

Secure your MySQL installation and create the WordPress database:

sudo mysql_secure_installation

Access MySQL and create the database structure:

sudo mysql -u root -p

CREATE DATABASE wordpress_db;
CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'secure_password_here';
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

PHP-FPM Optimization

Configure PHP-FPM for optimal WordPress performance by editing the pool configuration:

sudo nano /etc/php/8.1/fpm/pool.d/www.conf

Key settings to modify:

user = www-data
group = www-data
listen = /run/php/php8.1-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500

Update PHP configuration for WordPress:

sudo nano /etc/php/8.1/fpm/php.ini

Critical WordPress-specific settings:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 300
max_input_vars = 3000
max_input_time = 1000

Nginx Configuration for WordPress

Create a new server block specifically optimized for WordPress:

sudo nano /etc/nginx/sites-available/wordpress

Here’s a production-ready configuration that handles WordPress permalinks, security headers, and caching:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    root /var/www/wordpress;
    index index.php index.html index.htm;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied expired no-cache no-store private must-revalidate max-age=0;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss;

    # WordPress specific rules
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # PHP handler
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # Static files caching
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Block access to sensitive files
    location ~ /(\.|wp-config.php|readme.html|license.txt) {
        deny all;
    }

    # Block access to WordPress admin from unauthorized IPs (optional)
    location /wp-admin {
        # allow YOUR_IP_ADDRESS;
        # deny all;
        try_files $uri $uri/ /index.php$is_args$args;
    }
}

Enable the site and remove the default configuration:

sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

WordPress Installation

Download and configure WordPress:

cd /tmp
curl -LO https://wordpress.org/latest.tar.gz
tar xzvf latest.tar.gz
sudo cp -R wordpress/* /var/www/wordpress/
sudo chown -R www-data:www-data /var/www/wordpress/
sudo chmod -R 755 /var/www/wordpress/

Create the WordPress configuration file:

cd /var/www/wordpress/
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php

Update the database configuration and add security keys:

define('DB_NAME', 'wordpress_db');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'secure_password_here');
define('DB_HOST', 'localhost');

// Add security keys from https://api.wordpress.org/secret-key/1.1/salt/
// Paste the generated keys here

// Additional security configurations
define('DISALLOW_FILE_EDIT', true);
define('WP_AUTO_UPDATE_CORE', true);

Performance Optimization and Caching

Implement FastCGI caching at the Nginx level for dramatic performance improvements:

sudo nano /etc/nginx/nginx.conf

Add within the http block:

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

Update your WordPress server block to include caching directives:

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    
    # FastCGI cache settings
    fastcgi_cache WORDPRESS;
    fastcgi_cache_valid 200 301 302 60m;
    fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
    fastcgi_cache_min_uses 1;
    fastcgi_cache_lock on;
    add_header X-FastCGI-Cache $upstream_cache_status;
}

Create the cache directory:

sudo mkdir -p /var/cache/nginx
sudo chown -R www-data:www-data /var/cache/nginx

SSL/TLS Configuration with Let’s Encrypt

Install Certbot and obtain SSL certificates:

sudo apt install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Generate certificates and automatically configure Nginx:

sudo certbot --nginx -d your-domain.com -d www.your-domain.com

Nginx vs Apache Performance Comparison

Metric Nginx + PHP-FPM Apache + mod_php Performance Difference
Memory Usage (idle) ~10MB ~25MB 60% less memory
Concurrent Connections 10,000+ 500-1,000 10x more connections
Static File Serving ~50,000 req/sec ~5,000 req/sec 10x faster
Configuration Complexity Moderate Simple More setup required

Common Issues and Troubleshooting

File Permission Problems

WordPress file permission issues are extremely common. Use this script to set correct permissions:

sudo find /var/www/wordpress/ -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress/ -type f -exec chmod 644 {} \;
sudo chown -R www-data:www-data /var/www/wordpress/

PHP-FPM Connection Issues

If you encounter “502 Bad Gateway” errors, check PHP-FPM status:

sudo systemctl status php8.1-fpm
sudo tail -f /var/log/php8.1-fpm.log

Common fixes include adjusting the socket path in both Nginx and PHP-FPM configurations and ensuring proper permissions on the socket file.

WordPress Permalink Issues

If pretty permalinks don’t work, verify that your Nginx configuration includes the correct try_files directive and that the WordPress .htaccess rules are properly converted to Nginx format.

Security Hardening Best Practices

  • Implement fail2ban to prevent brute force attacks on wp-login.php
  • Use strong database passwords and consider database name obfuscation
  • Enable automatic WordPress core updates and monitor plugin vulnerabilities
  • Configure UFW firewall to only allow necessary ports (22, 80, 443)
  • Regular backup automation using tools like wp-cli or custom scripts
  • Consider implementing two-factor authentication for WordPress admin accounts

Real-World Use Cases and Performance Results

This Nginx + WordPress setup excels in several scenarios. E-commerce sites running WooCommerce see 40-60% faster page load times compared to Apache configurations. High-traffic blogs handling 100,000+ daily pageviews report stable performance with minimal server resources. News websites with frequent content updates benefit from the FastCGI caching layer, reducing database queries by up to 80%.

A typical performance profile shows sub-200ms response times for cached pages and under 800ms for dynamic content, assuming proper server specifications and optimized WordPress themes and plugins.

Advanced Monitoring and Maintenance

Implement monitoring with built-in tools:

# Enable Nginx status page
sudo nano /etc/nginx/sites-available/wordpress

Add within server block:

location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

Monitor PHP-FPM performance:

sudo nano /etc/php/8.1/fpm/pool.d/www.conf

Enable status page:

pm.status_path = /fpm-status
pm.status_listen = 127.0.0.1:9001

For comprehensive monitoring, consider integrating with tools like Netdata, Prometheus, or commercial services like New Relic. Regular log analysis helps identify performance bottlenecks and security threats before they become critical issues.

This setup provides a solid foundation for WordPress hosting that can scale from small personal blogs to high-traffic commercial websites. The key lies in understanding how each component interacts and tuning the configuration based on your specific traffic patterns and performance requirements.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked