Free migration · 30-day money backGet started
TopSyde
NGINX server configuration screen showing WordPress permalink rewrite rules being edited

NGINX Returns 404 on Every WordPress Permalink

Step-by-step guide to fix NGINX WordPress permalinks 404 errors. Server block configuration, try_files rewrite rules, and the most common misconfigurations.

Marcus Webb

Marcus Webb

DevOps & Security Lead

··13 min read

Last updated: October 13, 2026

NGINX WordPress permalink 404 errors occur when your server can't process pretty URLs, typically due to missing or incorrect rewrite rules in your NGINX configuration. Unlike Apache's .htaccess files, NGINX requires explicit server-level configuration to handle WordPress permalinks.

NGINX handles URL rewriting differently than Apache, which causes permalink problems for WordPress sites. Apache automatically processes .htaccess files in each directory, while NGINX requires explicit configuration in server blocks.

WordPress generates permalink structures like /post-name/ or /category/post-name/, but these URLs don't correspond to actual files on your server. Without proper rewrite rules, NGINX returns 404 errors because it can't find physical files matching these URLs.

According to W3Techs, NGINX powers 33.6% of all websites (2024), but WordPress permalink issues remain one of the most common configuration problems. The root cause is always the same: NGINX doesn't know how to route pretty URLs to WordPress's index.php file.

Start by identifying whether the problem affects all permalinks or specific patterns. Test these URL types on your site:

  • Posts: /sample-post/
  • Pages: /about/
  • Categories: /category/news/
  • Archives: /2024/01/
  • Admin: /wp-admin/ (should work)

If only the admin works while all pretty URLs return 404s, you have a complete rewrite rule failure. Partial failures indicate location block conflicts or incomplete configuration.

Check your current NGINX configuration:

sudo nginx -T | grep -A 20 "server_name yourdomain.com"

Look for try_files directives and location blocks. Missing or incorrect try_files configuration is the primary culprit in 95% of permalink issues.

Common diagnostic signs include:

SymptomLikely Cause
All pretty URLs 404Missing try_files directive
Admin works, posts don'tWordPress location block missing
Some permalinks work randomlyLocation block priority conflict
URLs work without trailing slashtry_files missing $uri/ pattern

The Complete NGINX WordPress Configuration Fix

The standard WordPress NGINX configuration requires specific location blocks and rewrite rules. Here's the complete server block configuration that resolves permalink 404s:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/yourdomain.com/public_html;
    index index.php index.html index.htm;

    # Main WordPress location block
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

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

    # WordPress admin and includes
    location ~* ^/(wp-admin|wp-includes)/ {
        try_files $uri $uri/ /index.php?$args;
    }

    # Block access to sensitive files
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }

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

The critical line is try_files $uri $uri/ /index.php?$args; in the main location block. This directive tells NGINX:

  1. First, try to serve the exact URI as a file ($uri)
  2. If not found, try it as a directory ($uri/)
  3. Finally, pass the request to WordPress (/index.php?$args)

For managed WordPress hosting environments, this configuration is automatically optimized and maintained, eliminating the need for manual server management.

Advanced NGINX WordPress Rewrite Rules

Complex WordPress sites often need additional rewrite rules beyond the basic configuration. Here are advanced patterns for common scenarios:

Multisite Network Configuration

WordPress multisite requires specific handling for subdirectory installations:

# Multisite subdirectory support
location ~ ^(/[^/]+/)?files/(.+) {
    try_files /wp-content/blogs.dir/$1$2 /wp-includes/ms-files.php?file=$2;
}

# Main multisite location
location / {
    try_files $uri $uri/ /index.php?$args;
}

location ~ ^/[_0-9a-zA-Z-]+(/wp-.*) {
    try_files $uri $uri/ /index.php?$args;
}

Custom Post Type Permalinks

Sites using custom post types with specific permalink structures need targeted rewrite rules:

# Custom post type: portfolio
location ~ ^/portfolio/([^/]+)/?$ {
    try_files $uri $uri/ /index.php?portfolio=$1&$args;
}

# Custom taxonomy: project-type
location ~ ^/project-type/([^/]+)/?$ {
    try_files $uri $uri/ /index.php?project_type=$1&$args;
}

REST API and AJAX Handling

WordPress REST API and AJAX requests require specific location handling:

# WordPress REST API
location ~ ^/wp-json/ {
    try_files $uri $uri/ /index.php?$args;
}

# Admin AJAX requests
location = /wp-admin/admin-ajax.php {
    try_files $uri /index.php?$args;
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
}

According to Kinsta's 2024 performance study, proper NGINX configuration can improve WordPress response times by up to 200% compared to poorly configured setups.

Common NGINX WordPress Misconfigurations

Several configuration mistakes consistently cause permalink problems. Understanding these patterns helps prevent recurring issues.

Location Block Priority Problems

NGINX processes location blocks in specific order, and incorrect priority can override WordPress rules:

# WRONG - Too specific location blocks first
location /wp-content/ {
    # This overrides WordPress handling
}

location / {
    try_files $uri $uri/ /index.php?$args;
}

# CORRECT - General WordPress rule first
location / {
    try_files $uri $uri/ /index.php?$args;
}

location /wp-content/ {
    # Static file handling
}

Missing Query String Preservation

Failing to preserve query strings breaks WordPress functionality:

# WRONG - Loses query parameters
try_files $uri $uri/ /index.php;

# CORRECT - Preserves query strings
try_files $uri $uri/ /index.php?$args;

Incorrect PHP Handler Configuration

PHP processing problems often masquerade as permalink issues:

# WRONG - Missing SCRIPT_FILENAME
location ~ \.php$ {
    fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
    include fastcgi_params;
}

# CORRECT - Proper PHP handling
location ~ \.php$ {
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
    include fastcgi_params;
}

For agencies managing multiple client sites, these configuration complexities are why many choose managed hosting solutions that handle server optimization automatically.

Testing and Validating Your NGINX WordPress Configuration

After implementing configuration changes, systematic testing ensures your permalink fix works correctly across all WordPress features.

Configuration Syntax Testing

Always validate NGINX configuration before reloading:

# Test configuration syntax
sudo nginx -t

# If successful, reload NGINX
sudo systemctl reload nginx

Never skip syntax testing. Invalid configuration can bring down your entire server.

Test these URL patterns to verify complete functionality:

# Basic post permalinks
curl -I https://yourdomain.com/sample-post/

# Category archives  
curl -I https://yourdomain.com/category/news/

# Date archives
curl -I https://yourdomain.com/2024/01/

# WordPress admin
curl -I https://yourdomain.com/wp-admin/

# REST API endpoints
curl -I https://yourdomain.com/wp-json/wp/v2/posts

Each request should return HTTP 200 status codes, not 404 errors.

Go to WordPress Admin → Settings → Permalinks and test different permalink structures:

StructureURL PatternNGINX Requirement
Plain/?p=123Basic PHP handling
Day and name/2024/01/01/post-name/Full try_files configuration
Month and name/2024/01/post-name/Full try_files configuration
Numeric/archives/123Full try_files configuration
Post name/post-name/Full try_files configuration
Custom/blog/%postname%/Custom rewrite rules

Switch between structures to ensure your NGINX configuration handles all patterns correctly. This process is automatically managed with WordPress maintenance plans that include server optimization.

Performance Optimization for NGINX WordPress Sites

Beyond fixing 404 errors, optimize your NGINX WordPress configuration for maximum performance. These enhancements build on the basic permalink fix.

FastCGI Caching Configuration

Implement server-level caching to reduce WordPress processing overhead:

# FastCGI cache configuration
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=wordpress:100m max_size=1g inactive=60m use_temp_path=off;

server {
    # Cache configuration
    set $skip_cache 0;
    
    # Skip cache for admin, logged-in users, and POST requests
    if ($request_method = POST) { set $skip_cache 1; }
    if ($query_string != "") { set $skip_cache 1; }
    if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") { set $skip_cache 1; }
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { set $skip_cache 1; }

    location ~ \.php$ {
        fastcgi_cache wordpress;
        fastcgi_cache_valid 200 301 302 60m;
        fastcgi_cache_use_stale error timeout invalid_header http_500 http_503;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
        
        # Standard PHP processing
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
    }
}

Gzip Compression and Static File Optimization

Reduce bandwidth and improve load times:

# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;

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

Security Enhancements

Block common WordPress attack vectors while maintaining permalink functionality:

# Block XML-RPC attacks
location = /xmlrpc.php {
    deny all;
    access_log off;
}

# Prevent PHP execution in uploads
location ~* /(?:uploads|files)/.*\.php$ {
    deny all;
}

# Block sensitive WordPress files
location ~* /(?:wp-config\.php|wp-config-sample\.php|readme\.html|license\.txt)$ {
    deny all;
}

According to Sucuri's 2024 Website Security Report, properly configured NGINX servers experience 67% fewer successful attacks compared to default configurations.

When standard configuration fixes don't resolve NGINX permalink problems, systematic troubleshooting identifies underlying issues.

Debug NGINX Processing

Enable detailed logging to understand how NGINX processes WordPress URLs:

# Temporary debug logging
error_log /var/log/nginx/debug.log debug;
access_log /var/log/nginx/access.log combined;

# Add to location block for specific debugging
location / {
    try_files $uri $uri/ /index.php?$args;
    error_log /var/log/nginx/wordpress_debug.log debug;
}

Monitor logs while testing problematic URLs:

tail -f /var/log/nginx/wordpress_debug.log

WordPress-Specific Debugging

Enable WordPress debug logging to identify theme or plugin conflicts:

// Add to wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

Check /wp-content/debug.log for WordPress-level errors that might interfere with permalink processing.

DNS and SSL Certificate Issues

Sometimes permalink problems stem from domain configuration rather than NGINX:

# Check DNS resolution
dig yourdomain.com

# Verify SSL certificate
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com

SSL certificate problems can cause browsers to display connection errors that appear as 404s.

For complex WordPress installations with custom requirements, professional WordPress hosting solutions provide expert configuration management and troubleshooting from senior developers.

Automated NGINX WordPress Management

Manual NGINX configuration management becomes complex as your WordPress portfolio grows. Modern hosting platforms provide automated solutions that eliminate configuration headaches.

Configuration Management Tools

Use configuration management for consistent NGINX setups across multiple sites:

# Ansible playbook example
- name: Configure NGINX for WordPress
  template:
    src: wordpress-nginx.conf.j2
    dest: /etc/nginx/sites-available/{{ domain }}
  notify: reload nginx

- name: Enable site
  file:
    src: /etc/nginx/sites-available/{{ domain }}
    dest: /etc/nginx/sites-enabled/{{ domain }}
    state: link

Monitoring and Alerting

Implement monitoring to catch permalink issues before they impact users:

#!/bin/bash
# Basic permalink monitoring script: /usr/local/bin/check-permalinks.sh
URL="https://yourdomain.com/sample-post/"
ALERT_EMAIL="you@yourdomain.com"

response=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$response" -ne 200 ]; then
    echo "Permalink check failed for $URL: HTTP $response" | mail -s "Permalink 404 detected on yourdomain.com" "$ALERT_EMAIL"
fi

Make it executable with chmod +x /usr/local/bin/check-permalinks.sh, then run it every five minutes from cron (crontab -e):

*/5 * * * * /usr/local/bin/check-permalinks.sh

The mail command needs a mail transfer agent on the server (the mailutils package on Debian and Ubuntu). If you'd rather not run mail on a web server, swap the mail line for a curl POST to a Slack or Discord webhook. Check more than one URL, too: one post, one page, one category archive, and /wp-json/. A single-URL check misses the selective 404s caused by location block conflicts.

Let the Host Own the Configuration

Every fix above assumes you have root access and the time to maintain server blocks across PHP upgrades, NGINX updates, and new plugins that need their own rules. On managed WordPress hosting, that work belongs to the host.

TopSyde runs every site on NGINX with PHP 8.5, Redis object caching, and the Cloudflare CDN, with the WordPress rewrite rules, PHP handler, and cache exclusions already configured and tested. Permalinks work on day one, and uptime monitoring checks real pages rather than only the homepage, so a broken rule gets caught before your visitors find it. Plans start at $89/mo per site, and the full stack is listed on the spec sheet.

Frequently Asked Questions

On Apache, saving Settings → Permalinks rewrites the .htaccess file, which fixes the routing. NGINX never reads .htaccess, so saving only flushes WordPress's internal rewrite rules. Look at the 404 page itself to tell the two problems apart: a plain "404 Not Found" page with "nginx" at the bottom means the request never reached WordPress and your server block needs the try_files fix. A 404 rendered by your theme means NGINX did its job and WordPress couldn't match the URL, so flushing rewrite rules (saving permalinks, or running wp rewrite flush) is the right fix.

Should I use /index.php?$args or /index.php$is_args$args?

Both work for WordPress. $args holds the query string, and /index.php?$args is the pattern most WordPress NGINX guides use. $is_args evaluates to ? only when a query string exists, so /index.php$is_args$args avoids passing a trailing ? on requests without one. WordPress handles either form the same way. What breaks things is dropping the query string entirely with a bare /index.php, which loses search, pagination, and preview parameters.

Do I need to restart NGINX after changing the configuration?

No. A reload is enough and is safer: sudo systemctl reload nginx starts new worker processes with the new configuration while the old ones finish their current requests, so visitors see no interruption. Always run sudo nginx -t first. If the syntax test fails, NGINX keeps serving the old configuration until you fix the error, but a full restart with a broken file can leave the server down.

Selective 404s usually come from a regex location block that matches before your main location / block. NGINX checks exact matches (=) first, then remembers the longest matching prefix, then tests regex locations in the order they appear and uses the first one that matches. A regex block written for static files or a plugin can catch WordPress URLs and return 404 because it has no try_files fallback to index.php. If the failing URLs belong to a custom post type you just registered, flush rewrite rules with wp rewrite flush before touching NGINX.

Usually not directly. Most hosts don't let customers edit server blocks, so the fix is a support ticket asking them to add the standard WordPress try_files rule for your site. On a managed WordPress host, permalinks should work out of the box; if they don't, the problem is more likely a plugin, a stale rewrite rule cache, or a custom redirect. Start with wp rewrite flush and the WordPress redirect guide before escalating.

Keep Reading on TopSyde

Marcus Webb
Marcus Webb

DevOps & Security Lead

12+ years DevOps, Linux & cloud infrastructure certified

Marcus leads infrastructure and security at TopSyde, managing the server fleet and AI monitoring systems that keep client sites fast and protected. Former sysadmin turned WordPress hosting specialist.

Related Articles

View all →

Free AI audit

Is your site actually fast?

Get a free homepage audit covering performance, SEO and usability, with a prioritized fix list. See the report on screen and get a copy by email. No account or payment required; allow a few minutes for the checks.

Free homepage report. No account or payment required.