Score:2

nginx route all 404 requests to a php script

in flag

I want to route all 404 requests to a php script, How should I do that? My nginx config is:

server {
    listen 81;
    listen [::]:81;
    root /srv/http/paste.lan/www;
    autoindex on;
    client_max_body_size 20M;
    index index.txt index.html index.htm index.php;
    server_name paste.lan;
    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }

    # pass PHP scripts to FastCGI server
    #
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
    #
    #   # With php-fpm (or other unix sockets):
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    #   # With php-cgi (or other tcp sockets):
    #   fastcgi_pass 127.0.0.1:9000;
    }


    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    location ~ /\.ht {
        deny all;
    }
}

Things I have tried:

Attempt #1:

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ /index.php;
    }
  • This only works for URI's that does not end with .php , for example /DoesNotExist.ph is passed to index.php , but /DoesNotExist.php get the standard nginx 404 page.

Attempt #2:

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }
    error_page 404 /index.php;

This sort-of works, all 404 requests are passed to index.php but this forces the response code to be 404, even if index.php contains:

<?php
http_response_code(200);
die("index.php");

it will still be served with response code 404 :(

Attempt #3:

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }
    error_page 404 =200 /index.php;

This also sort-of works, all 404 requests are passed to index.php but this forces the response code to be 200, even if index.php contains:

<?php
http_response_code(400);// HTTP 400 Bad Request
die("index.php");

it will still be served as HTTP 200 OK :(

Richard Smith avatar
jp flag
Almost there, the one you want is `error_page 404 = /index.php;` [to respond with the code it returns](http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page). Also, you may want to add `try_files $uri =404;` to your `location ~ \.php$` block to catch non-existent PHP files.
in flag
@RichardSmith dang that works! and i don't need to add anything to the \.php$ block! want to post it as an answer?
Score:3
jp flag

The error_page directive includes an option to change the response code to another.

From the manual page:

If an error response is processed by a proxied server or a FastCGI/uwsgi/SCGI/gRPC server, and the server may return different response codes (e.g., 200, 302, 401 or 404), it is possible to respond with the code it returns:

error_page 404 = /404.php;

You should use:

error_page 404 = /index.php;
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.