NGINX: Create Custom 404 / 403 Error Pages on Linux or Unix

How do I create a custom static HTTP 404 or HTTP 403 error page under nginx web server running on Linux or Unix-like system?

Nginx is a free and open source web server. It also act as a reverse proxy, caching and load balancer server. This tutorial shows, how to configure Nginx to use custom error pages for 404/403 on Linux or Unix-like system.

How to configure Nginx to use custom 404 error page

First create a 404.html in your document root. The default is location is /usr/local/nginx/html/ or /var/www/htm/. So create a HTML file as follows:
# vi /usr/local/nginx/html/404.html
# vi /var/www/html/404.html
Sample outputs:

<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Error 404 Not Found</title>
	body {font-family: arial,sans-serif}
	img { border:none; }
	<h2>Error 404 Not Found</h2>
	<p>Our apologies for the temporary inconvenience. The requested URL was not found on this server.  We suggest you try one of the links below:
		  <li><b>Verify url and typos</b> - The web page you were attempting to view may not exist or may have moved - try <em>checking the web address for typos</em>.<//li>
		  <li><b>E-mail us</b> - If you followed a link from somewhere, please let us know at <a href=""></a>. Tell us where you came from and what you were looking for, and we'll do our best to fix it.</li>

How to configuring Nginx to use my 404.html file as error page

Edit /usr/local/nginx/conf/nginx.conf file, enter:
# vi /usr/local/nginx/conf/nginx.conf
# vi /etc/nginx/sites-available/default
Append / edit config as follows:

error_page   404  =  /404.html;

An example to prevent clients fetching error pages directly:

error_page 404 /404.html;
location  /404.html {

An example of HTTP 403 error page:

       error_page 403 /403.html;
       location = /403.html {
           root   html;
           allow all;

The error_page can be placed in only http, server and location directives. Save and close the file. Reload the nginx server, enter:
# /usr/local/nginx/sbin/nginx -t && /usr/local/nginx/sbin/nginx -s reload
# nginx -t && nginx -s reload
$ sudo systemctl reload nginx
Here is a sample error page from my site when visited (your-domain/404dfoo):

Fig.01: Sample custom error 404 page in Nginx

How do I redirect to a specific URL for error processing?

Yes, URL redirects for error processing is possible as follows:

# Redirect to forbidden.php for HTTP status code 403
error_page 403;
# Redirect to for HTTP status code 404 
# with redirect status codes to 301
error_page 404 =301;

A list of common error code

  1. HTTP 404 – Web page not found on this server.
  2. HTTP 403 – The server is configured to deny access to your request. Usually login urls such as /wp-admin/ or /phpmysqladmin/ are blocked using this method.
  3. HTTP 500/502/503/504 – Internal server problem such as miss configured server or back-end down.

For more info see Nginx documentation.

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 12 comments so far... add one

CategoryList of Unix and Linux commands
Disk space analyzersdf ncdu pydf
File Managementcat cp mkdir tree
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
12 comments… add one
  • yoyo Aug 9, 2011 @ 20:43

    why in /usr/local?
    I always pack this brilliant piece of software for OS I use.

  • khupcom Sep 19, 2011 @ 23:52

    Thanks for the tutorial. I need dynamic 404 page with php example 404.php but looks like nginx ignore php file for 404 page.
    Any help realy appreciate.

  • Phoenix May 16, 2012 @ 17:14

    Thanks, but this is a highly unclear posting. Where do those lines go — inside the “http” directive, or inside each server block?

    • 🐧 nixCraft May 16, 2012 @ 17:27

      Try any one of the following context:

      1. http
      2. server
      3. location
      4. if in location
  • Phoenix May 16, 2012 @ 17:28

    Thanks Vivek. Can I do outside http?

  • Phoenix May 16, 2012 @ 17:29

    And what do the permissions of the files have to be — chmod 777?

    • cybernet Jul 6, 2014 @ 7:21

      files should always have 644 and directories 755

  • Phoenix May 16, 2012 @ 17:32

    Doesn’t work inside http context, and doesn’t work outside it.

    Shows me this error:

    Restarting nginx daemon: nginxRemaining processes: 12683
    nginx: [emerg] "location" directive is not allowed here in /etc/nginx/nginx.conf:67

    Is this only allowed inside location blocks? I’m using 1.0.8.

    • 🐧 nixCraft May 16, 2012 @ 18:34

      Here is another example put it in server context:

      server {
            access_log  logs/ main;
            error_log   logs/;
            index       index.html;
            root        /usr/local/nginx/html;
           ## Only requests to our Host are allowed
            if ($host !~ ^(|$ ) {
               return 403;
           ## redirect www to nowww
            if ($host = '' ) {
               rewrite  ^/(.*)$$1  permanent;
           ## Only allow these request methods
            if ($request_method !~ ^(GET|HEAD|POST)$ ) {
               return 444;
           ## PROXY - Web
            location / {
              proxy_pass  http://examplebackend;
              proxy_cache            cache;
              proxy_cache_valid      200 24h;
              proxy_cache_use_stale  error timeout invalid_header updating http_500 http_502 http_503 http_504;
              proxy_ignore_headers   Expires Cache-Control;
              proxy_set_header        Host            $host;
              proxy_set_header        X-Real-IP       $remote_addr;
              proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
              if ( $blockspammers = yes ) {
                     return 403;
           # redirect server error pages to the static page /50x.html
              error_page   500 502 503 504  /50x.html;
              location = /50x.html {
                  root   html;
              error_page 403 /;
              location = / {
                 root   html;
                 allow all;
      • Phoenix May 16, 2012 @ 19:04

        Firstly, that’s a highly inefficient nginx conf file with all those IF conditions.

        Anyway, my error_pages blocks are exactly the same, except that I want the error pages across my site — at least the default ones — to be the same. So I have this:

        error_page 404 /404.html;
        location = /404.html {
        root /etc/nginx/html;
        error_page 403 /403.html;
        location = /403.html {
        root /etc/nginx/html;
        allow all;
        error_page 500 502 503 504 /500.html;
        location = /500.html {
        root /etc/nginx/html;

        Where /etc/nginx/html is CHMOD 777.

        Not working.

        Any ideas?

        • gonza Oct 10, 2012 @ 20:35

          Phoenix, What you posted worked perfect! And the files don’t need to be 777.

          server {
          error_page 403 = /403.html;
          location = /403.html {
          root /var/www/FOLDER;
          error_page 404 = /404.html;
          location = /404.html {
          root /var/www/FOLDER;

  • Joseph Jan 9, 2015 @ 16:17

    Make sure that your custom error pages are still sending the correct status codes..

    Like a 403 should still be a 403 and not a 200..
    I had to do it like this..
    error_page 403 =403 /403.html;

    Otherwise the 403 would be cached in varnish which is not cool non attacking visitors.

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum