Complete Guide to Rewriting Requests to index.php in Nginx

Dec 01, 2025 · Programming · 8 views · 7.8

Keywords: Nginx configuration | request rewriting | index.php

Abstract: This article provides an in-depth exploration of rewriting all requests to index.php in Nginx servers. By analyzing the migration from Apache configurations, it details the use of try_files directive, rewrite rules, and advanced location block techniques. Based on the best-practice answer, it offers complete configuration examples covering static file handling, PHP script execution, and URL beautification, while comparing different solutions for comprehensive developer guidance.

Introduction

In modern web development, rewriting requests to a single entry script is a common requirement, especially when using PHP frameworks with front controller patterns. Apache servers achieve this via .htaccess and mod_rewrite, while Nginx requires different configuration approaches. This article, based on Q&A data and reference materials, thoroughly explains how to implement request rewriting to index.php in Nginx, including hiding .php extensions.

Apache Configuration Review

In Apache, a typical rewrite rule is:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.+$ index.php [L]
</IfModule>

This rule first checks if the requested file or directory exists; if not, it rewrites to index.php. When migrating to Nginx, understanding the differences in configuration logic is essential.

Basic Nginx Configuration

Nginx uses location blocks and directives to handle requests. An initial configuration might be:

server {
    root /home/user/www;
    index index.php;
    server_name some-domain.dev;
    
    location / {
        include /etc/nginx/fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/index.php$args;
        fastcgi_pass 127.0.0.1:9000;
    }
    
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

This configuration attempts to pass all requests directly to index.php but does not handle static files or missing files, leading to incomplete functionality.

Core Solution: try_files and rewrite

Based on the best answer, the core of implementing rewrites combines the try_files directive and rewrite rules. First, add to the PHP location block:

location ~ \.php$ {
    try_files $uri @missing;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    include fastcgi_params;
}

The try_files directive first attempts to serve the requested file ($uri); if it does not exist, it jumps to the @missing named location. Then, add to the server block:

location @missing {
    rewrite ^ $scheme://$host/index.php permanent;
}

This rule permanently redirects missing requests to index.php. However, this method may cause redirect loops and should be used cautiously. A better approach is internal rewriting:

location @missing {
    rewrite ^ /index.php last;
}

Using the last flag ensures processing continues after rewriting, avoiding external redirects.

Handling Static Files

To efficiently serve static files, add a dedicated location block:

location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico)$ {
    access_log off;
    expires 30d;
}

This block matches common static file extensions, disables access logs, and sets cache expiration. Also, ensure the root location correctly handles file requests:

location / {
    try_files $uri $uri/ @missing;
}

try_files attempts in order: as a file ($uri), as a directory ($uri/), and finally jumps to @missing. This mimics Apache's !-f and !-d conditions.

Hiding .php Extensions

Hiding .php extensions in URLs can be achieved via rewrite rules. Referencing external articles, configure as follows:

location / {
    set $page_to_view "/index.php";
    try_files $uri $uri/ @rewrites;
    root /var/www/site;
    index index.php index.html index.htm;
}

location ~ \.php$ {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www/site$page_to_view;
}

location @rewrites {
    if ($uri ~* ^/([a-z]+)$) {
        set $page_to_view "/$1.php";
        rewrite ^/([a-z]+)$ /$1.php last;
    }
}

This configuration uses the @rewrites location to capture extensionless URLs (e.g., /about), internally rewriting them to corresponding .php files (e.g., /about.php), while setting the $page_to_view variable for the PHP location. Note the performance impact of if directives; use judiciously.

Alternative Solutions Comparison

Other answers provide simplified approaches. For example, using try_files for direct fallback:

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

This method is concise, directly passing missing requests to index.php while preserving query parameters ($args). However, it may not handle complex rewrite logic like extension hiding. Lower-scored answers (4.7 points) supplement with $args usage to ensure GET variable transmission.

Complete Configuration Example

Integrating the above, a complete Nginx configuration is:

server {
    root /home/user/www;
    index index.php index.html;
    server_name some-domain.dev;
    
    # Handle static files
    location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico)$ {
        access_log off;
        expires 30d;
    }
    
    # Hide .php extensions and rewrite logic
    location / {
        set $page_to_view "/index.php";
        try_files $uri $uri/ @rewrites;
    }
    
    location @rewrites {
        if ($uri ~* ^/([a-z]+)$) {
            set $page_to_view "/$1.php";
            rewrite ^/([a-z]+)$ /$1.php last;
        }
        rewrite ^ /index.php last;
    }
    
    # PHP processing
    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$page_to_view;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
    }
    
    # Other configurations (e.g., favicon, robots.txt)
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }
    location ~ /\. {
        deny all;
    }
}

This configuration implements request rewriting, static file serving, and extension hiding while maintaining performance and security.

Performance and Security Considerations

When configuring Nginx, note:

Reference articles mention that Nginx configurations are generally more efficient but require correct understanding of directive behaviors.

Conclusion

Migrating Apache rewrite rules to Nginx requires understanding their differences. Through combinations of try_files, rewrite, and location blocks, powerful request rewriting can be achieved. Best practices recommend using try_files for file existence checks, combined with named locations for complex rewrites, while optimizing static file serving. The configuration examples provided in this article, based on actual Q&A and references, offer reliable solutions for developers. When implementing, adjust according to specific application needs and test to ensure functionality.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.