61

Nginx+PHP (on fastCGI) works great for me. When I enter a path to a PHP file which doesn't exist, instead of getting the default 404 error page (which comes for any invalid .html file), I simply get a "No input file specified.".

How can I customize this 404 error page?

James T Snell
  • 1,588
  • 1
  • 15
  • 28
thomas55
  • 891
  • 2
  • 9
  • 12

5 Answers5

123

You can setup a custom error page for every location block in your nginx.conf, or a global error page for the site as a whole.

To redirect to a simple 404 not found page for a specific location:

location /my_blog {
    error_page    404 /blog_article_not_found.html;
}

A site wide 404 page:

server {
    listen 80;
    error_page  404  /website_page_not_found.html;
    ...

You can append standard error codes together to have a single page for several types of errors:

location /my_blog {
    error_page 500 502 503 504 /server_error.html
}

To redirect to a totally different server, assuming you had an upstream server named server2 defined in your http section:

upstream server2 {
    server 10.0.0.1:80;
}
server {
    location /my_blog {
        error_page    404 @try_server2;
    }
    location @try_server2 {
        proxy_pass http://server2;
    }

The manual can give you more details, or you can search google for the terms nginx.conf and error_page for real life examples on the web.

Great Turtle
  • 3,315
  • 7
  • 32
  • 36
  • 2
    Do you know if it's possible to use a error wildcard? Something like `error_page 50* = /error_50x.html;`? – Alix Axel Nov 27 '12 at 01:58
  • Wildcards are not allowed - the wiki page for this server command is here http://wiki.nginx.org/NginxHttpCoreModule#error_page - also they aren't necessary since the error codes are defined by the HTTP protocol which doesn't change very often. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html or http://en.wikipedia.org/wiki/List_of_HTTP_status_codes for the complete list and I suppose add whatever numbers you like if you think there will be future codes needed. – Great Turtle Nov 27 '12 at 17:17
  • 1
    Thanks. Currently I have 3 rules: `/403.html`, `/404.html` and `/5xx.html`, they all share the same `root` but somehow if I specify the location `~ /(?:40[34]|5xx)[.]html$` it will render the default nginx error pages, however, if I use a non-regex location it works. Do you have any idea why that happens? – Alix Axel Nov 27 '12 at 17:27
  • That's a separate issue too big to get into in these comments. I would make it a new question or just add the location entries. Link to the question if you make one and I will take a look. – Great Turtle Nov 28 '12 at 14:53
49

You use the error_page property in the nginx config.

For example, if you intend to set the 404 error page to /404.html, use

error_page 404 /404.html;

Setting the 500 error page to /500.html is just as easy as:

error_page 500 /500.html;
panepeter
  • 3,224
  • 1
  • 29
  • 41
WizKid
  • 4,888
  • 2
  • 23
  • 23
  • 4
    Although the link is OK and the answer minimally works without the link, it could benefit from additional elaboration. – Paul Aug 10 '15 at 00:38
  • 1
    @Paul I 100% agree with you on this, therefore I added some code examples to this answer ;-) – Uli Köhler Oct 18 '15 at 14:32
41

Be careful with the syntax! Great Turtle used them interchangeably, but:

error_page 404 = /404.html;

Will return the 404.html page with a status code of 200 (because = has relayed that to this page)

error_page 404 /404.html;

Will return the 404.html page with a (the original) 404 error code.

https://serverfault.com/questions/295789/nginx-return-correct-headers-with-custom-error-documents

Community
  • 1
  • 1
dhr_p
  • 2,364
  • 1
  • 22
  • 19
30

The "error_page" parameter makes a redirect, converting the request method to "GET", it is not a custom response page.

The easiest solution is

     server{
         root /var/www/html;
         location ~ \.php {
            if (!-f $document_root/$fastcgi_script_name){
                return 404;
            }
            fastcgi_pass   127.0.0.1:9000;
            include fastcgi_params.default;
            fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
        }

By the way, if you want Nginx to process 404 status returned by PHP scripts, you need to add

[fastcgi_intercept_errors][1] on;

E.g.

     location ~ \.php {
            #...
            error_page  404   404.html;
            fastcgi_intercept_errors on;
         }
  • thank you so much for posting this @Grigori, I used your code above to fix my nginx problem too – Chris Hough Sep 15 '11 at 04:29
  • 1
    Perfect, `fastcgi_intercept_errors on` is exactly what I was looking for. – wildpeaks Jul 28 '12 at 06:34
  • @TheBlackBenzKid because it is a redirect with "request method changed to “GET”", not a custom response, and the request body is lost. – Grigori Kochanov May 03 '19 at 09:42
  • thanks, i placed the error page destination outside of my location block. fastcgi_intercept_errors on helped me solved my custom 404 page problem for my laravel forge server. – Bruce Tong Feb 03 '21 at 12:01
18

These answers are no longer recommended since try_files works faster than if in this context. Simply add try_files in your php location block to test if the file exists, otherwise return a 404.

location ~ \.php {
    try_files $uri =404;
    ...
}
Isius
  • 6,712
  • 2
  • 22
  • 31
  • 1
    This helped me immensely. I haven't found any suggestions for using this on the internet. Had no idea you could use conditionals in try_files. – Steve Bauman Dec 16 '19 at 04:11