The reliable pattern is to create a static HTML file beneath the active Nginx root, map an HTTP status to that file with error_page, mark the file location internal, validate the configuration, and reload Nginx. For example, error_page 404 /404.html; serves a branded page without changing the URL or normally changing the 404 status.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
What a custom Nginx error page actually does
Nginx generates an error response when it cannot satisfy a request itself or when an upstream application returns an error that Nginx handles. A missing static file, for example, produces HTTP 404 by default. The error_page directive tells Nginx what content or handler to use when a specified status occurs.
As an Amazon Associate I earn from qualifying purchases.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →The directive accepts a status code, an optional response override, and a target URI, named location, or external URL:
error_page code ... [=[response]] uri;
It is valid in the http, server, and location contexts, and inside if in a location. Put it in the narrowest context that should own the behavior. A rule in one virtual server does not automatically affect an unrelated server block.
#1 Best Overall
For a local target, Nginx performs an internal redirect. The browser keeps its original URL, while Nginx internally requests the error document. For methods other than GET and HEAD, that internal request uses GET. This matters if a failed POST, PUT, or DELETE must retain its method or request body.
The simplest working 404 page
1. Put the HTML file under the active document root
Suppose the virtual server uses /var/www/example as its root. Create /var/www/example/404.html:
Free tools Windows power users keep installed
One-click scans. No signup required.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page not found</title>
</head>
<body>
<main>
<h1>We couldn't find that page</h1>
<p>The address may be mistyped, or the page may have moved.</p>
<p><a href="/">Return to the home page</a></p>
</main>
</body>
</html>
The URI /404.html maps to that file because Nginx appends the request URI to the configured root. If the file is outside the active root, the internal redirect reaches another missing file and you will see a second 404 instead of the custom content.
2. Add the mapping to the correct server block
server {
root /var/www/example;
error_page 404 /404.html;
location = /404.html {
internal;
}
}
internal is optional hardening, not a requirement for rendering. It prevents visitors from requesting the error document directly. A direct request to an internal location intentionally receives a 404.
3. Validate and reload
After editing the file, validate the configuration and then reload the running process:
nginx -t
nginx -s reload
Run these commands with the same privileges and configuration path used by your installation. If your packaging uses a service manager, an equivalent reload command is appropriate. If nginx -t is not recognized, consult the installed binary’s command-line help before changing a live configuration.
4. Test the actual virtual host
Request a path that does not exist on the intended hostname. Check both the HTTP status and the response body:
curl -i https://example.com/path-that-does-not-exist
You should see a 404 response with your HTML. Also inspect the configured access.log and error.log; they reveal which server handled the request, which URI failed, and whether the error document itself could be opened.
Use one page for several status codes
When the same explanation and recovery link make sense for multiple server failures, list the codes on one directive. This is the standard shared 5xx fallback:
Rank #2
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
The first rule handles only 404. The second maps internal server errors, bad gateway responses, temporary unavailability, and gateway timeouts to one file. Create /var/www/example/50x.html under the same root and keep its wording general enough to cover each condition.
You can group other codes when the user action is identical, but do not hide materially different situations behind an unhelpful message. A 403 usually means the resource exists but access is denied; a 404 means Nginx could not find it. Separate pages can explain those next steps more accurately.
When to give 403 its own page
A forbidden response often needs different guidance from a missing-page response. A 403 page can direct an authenticated user to sign in, explain that access is restricted, or provide a support contact. Do not include filesystem paths or permission diagnostics in the public HTML. If revealing whether a protected resource exists would disclose sensitive information, review whether the wording of your 403 and 404 responses should intentionally be similar.
Keep 5xx wording deliberately general
The same 50x.html file may be displayed for an Nginx failure, an unavailable upstream, or a gateway timeout. Say that the service is temporarily unable to complete the request and provide a safe retry or support path. Do not promise that the problem is fixed, and do not expose upstream hostnames, stack traces, credentials, or internal paths.
Choose the right error-page target
Local files, explicit response overrides, named locations, and external redirects behave differently. Select the form based on the status, URL, method, and backend behavior you need.
| Configuration form | Keeps original status? | Changes browser URL? | Changes method? | Typical use |
|---|---|---|---|---|
error_page 404 /404.html; |
Yes, unless another directive overrides it | No | Non-GET/HEAD requests become GET during the internal redirect |
Branded static 404 or 50x content |
error_page 404 =404 /404.html; |
Explicitly sets 404 | No | Internal redirect rules apply | Guaranteeing a selected status while serving a local or application page |
error_page 404 = /404.php; |
The upstream handler can determine the returned status | No | Internal redirect rules apply | Passing an error request to an application endpoint |
error_page 404 = @fallback; |
The named location or backend decides | No | Preserves the original URI and method for error processing | Proxy or application fallback that must retain request details |
error_page 404 =301 https://example.net/notfound.html; |
No; it returns the selected redirect status | Yes | The browser follows the redirect | Permanent migration to another address |
Serve a local page while selecting the response status
The equals form lets you choose the status sent to the client:
error_page 404 =404 /404.html;
Without an explicit code, Nginx normally retains the status that triggered processing. With =response, the chosen response code is used. This is useful when a handler’s status must be explicit rather than inherited.
Pass the request to an application or upstream
An application endpoint can render a dynamic page:
error_page 404 = /404.php;
With the equals form and no response number, the status returned by the upstream handler can be passed through. Ensure the application sets the status deliberately; otherwise it may turn a missing page into a misleading 200 response.
Use a named location when method and URI preservation matter
location / {
error_page 404 = @fallback;
}
location @fallback {
proxy_pass http://backend;
}
A named location avoids the ordinary local-URI behavior that changes non-GET/HEAD methods to GET. It is a better fit for an upstream service that needs the original method, URI, headers, or request body to decide how to respond.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #3
Redirect the browser to another URL
An external URL makes the browser navigate elsewhere:
error_page 403 http://example.com/forbidden.html;
error_page 404 =301 http://example.com/notfound.html;
When no redirect code is specified, Nginx uses a 302 redirect. The equals form supports 301, 302, 303, 307, or 308. A redirect therefore changes both the visible URL and the status the browser initially receives. Use it for a deliberate migration or centralized error site, not merely to display a local page.
Make sure Nginx can reach the error file
Understand root mapping
Nginx forms a filesystem path by adding the request URI to the root value. With root /var/www/example;, a request for /404.html resolves to /var/www/example/404.html. Check the effective root in the exact server and location that handles the failing request; a more specific location can use a different root.
Use try_files for explicit fallback rules
For sites that serve extensionless pages or a front controller, make the fallback order explicit:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
location / {
try_files $uri $uri/ $uri.html =404;
}
error_page 404 /404.html;
try_files checks files and directories in order. If none exists, =404 returns that status, which then invokes the configured error page. A misplaced fallback can create loops, so keep the error document itself available as a real file and avoid routing it back through a rule that always fails.
Account for location precedence and inheritance
An error_page setting is inherited from the previous configuration level only when the current level defines no error_page directives. If a nested location declares its own error-page rule, it stops inheriting the parent rules. This explains why a page may work at the site root but not inside an API or upload location.
Check permissions and deployment contents
The Nginx worker must be able to read the HTML file and traverse its parent directories. A deployment that copied the configuration but omitted 404.html or 50x.html has the same visible symptom as an incorrect root. Verify the file name’s capitalization, the generated path, and the permissions on every directory in that path. The error log is the quickest way to distinguish a missing file from an access failure.
Why a custom page is not showing
The request is handled by another server block
Multiple virtual hosts can share an IP address. If the Host header, listen address, or default-server selection points elsewhere, you will test the wrong configuration. Confirm the hostname in your request and inspect the access log for the selected server.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11The target file is missing or outside the active root
Check the exact path produced by the active root, file permissions, and case sensitivity. A typo in /404.html, a different root in a nested location, or a deployment that omitted the file causes the internal request to fail as another 404.
Rank #4
An internal location is being tested directly
Requesting /404.html in a browser is not a valid test when that location is marked internal; Nginx must reach it through an error. Test a genuinely missing URL instead.
The application supplied its own error body
For proxied requests, the upstream may return an error response that Nginx passes through rather than replacing. Decide whether the application or Nginx owns the page. If Nginx should intercept selected upstream errors, configure the relevant proxy error handling and use the appropriate = form; otherwise fix the template in the application.
A child location overrides the parent rule
Search the complete configuration for additional error_page directives. A rule in a more specific location can replace the server-level behavior. Include generated configuration files when your distribution assembles the final configuration from snippets.
The redirect is working, but the result looks different
External redirects intentionally change the URL and may return 301, 302, 303, 307, or 308 instead of the original error. Inspect with curl -i and follow redirects only when you want to test the destination as well.
An error loop hides the original problem
If the error URI is itself processed by the same failing location, Nginx can repeatedly attempt to render a page that cannot be opened. Give the document an exact location, keep it as a real file under the effective root, and make sure try_files does not send that URI back to the same failing fallback.
Hide Nginx version information
Generated error pages and the Server response header can disclose the Nginx version. Disable that disclosure with:
http {
server_tokens off;
}
Place the directive in the http block for a site-wide setting, or in an applicable server block when you need narrower scope. This changes Nginx’s version emission; it does not remove application banners, debug headers, or identifying text you put in your own HTML.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsCustom pages should never expose stack traces, upstream hostnames, credentials, internal filesystem paths, request headers, or other diagnostic data. Keep detailed diagnostics in protected logs rather than in a response visible to every visitor.
Design the page for recovery, not just appearance
- State what happened in plain language instead of displaying only “Error 404.”
- Provide a working link to a stable home page or relevant section.
- Offer site search when users commonly arrive through old links.
- Include a support or contact route if the failure may need human action.
- Use semantic headings, sufficient color contrast, keyboard-accessible links, and a responsive layout.
- Keep the page self-contained enough to render when stylesheets, JavaScript, APIs, or the application backend are unavailable.
- Do not reveal whether a sensitive resource exists merely by changing the wording of a 403 and 404 response unless that distinction is intentional.
Complete example for a static site
The following configuration gives a static site a dedicated 404 page, a shared 5xx page, an explicit file fallback, and version suppression:
http {
server_tokens off;
server {
listen 80;
server_name example.com;
root /var/www/example;
location / {
try_files $uri $uri/ $uri.html =404;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /404.html {
internal;
}
location = /50x.html {
internal;
}
}
}
Save the two HTML files under /var/www/example, run the configuration test, reload Nginx, and request one nonexistent path plus a controlled upstream failure if the site has a proxy. Verify the status code, body, URL, and logs separately; a visually correct page can still return the wrong status.
Best Value
Production checklist
- Identify the exact
serverandlocationthat handles the failing request. - Confirm the active
rootand place each error document beneath it. - Choose a local URI, explicit response override, named location, or external redirect according to method and status requirements.
- Add
internalto static error-document locations if direct access should be blocked. - Check whether nested locations or generated snippets override the rule.
- Run
nginx -tand correct every reported error before reloading. - Reload with
nginx -s reloador your operating system’s equivalent. - Test missing files, forbidden resources, and representative upstream failures with
curl -i. - Inspect
access.loganderror.logwhen the body, status, or selected server is unexpected. - Review the HTML for accessibility and confirm it contains no secrets, stack traces, hostnames, or filesystem paths.
Frequently Asked Questions
How do I create a custom Nginx 404 page?
Create a file such as /var/www/example/404.html, add error_page 404 /404.html; in the applicable server block, optionally protect the exact location with internal, then test and reload Nginx.
Recommended Free Tools
Can one page handle several Nginx errors?
Yes. Use a grouped directive such as error_page 500 502 503 504 /50x.html;. Keep the wording broad enough for every status, and use a separate 403 or 404 page when users need different guidance.
Why does requesting /404.html return 404?
If its location is marked internal, direct external requests intentionally receive 404. Trigger the page through a genuinely missing URL instead.
Can Nginx redirect an error to another URL?
Yes. An external target such as error_page 403 https://example.com/forbidden.html; redirects with 302 by default. Use =301, =302, =303, =307, or =308 when a specific redirect status is required.
How can I preserve the original method for an error handler?
A local URI internally changes methods other than GET and HEAD to GET. Use a named location, for example error_page 404 = @fallback;, when the fallback must preserve the original URI and method for an upstream.
Free tools Windows power users keep installed
One-click scans. No signup required.
How do I keep an upstream error status?
Route to an application endpoint with the equals form and no response number, such as error_page 404 = /404.php;. The upstream handler can then determine the returned status, so make sure it sets that status deliberately.
Why is my custom page not appearing for proxied requests?
The upstream application may be returning its own body and status. Decide whether Nginx or the application owns the error page, then configure the selected layer consistently and inspect both access and error logs.
How do I hide the Nginx version on error pages?
Set server_tokens off;, commonly in the http block for site-wide scope. This suppresses Nginx version emission on generated error pages and in the Server header, but not banners added by your application.
The Bottom Line
Put each static error document beneath the active root, map statuses with error_page, and use internal to prevent direct access when appropriate. Choose local URIs, explicit status overrides, named locations, or redirects based on whether the status, URL, method, and upstream response must be preserved. Validate, reload, test with curl -i, and use the logs to diagnose the selected server, file path, and final response.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




