Visitors reach missing pages all the time. They mistype an address, follow an old link or click a result for something you deleted. What they see next is up to you. The default server error page is blunt and unbranded. A well-made custom 404 page keeps people on your site by pointing them to something useful.
There is also a technical side, and it is where most mistakes happen. A custom 404 page must still send a genuine 404 status code. If the page looks like an error but the server answers 200, search engines can treat it as a soft 404, and your error page can end up in reports as a problem.
This guide is for site owners and developers. You will design a useful error page, configure your server so the page appears with the correct status, and test the result.
Before you begin
- Access: you need to edit server configuration, application code or your CMS theme, depending on your platform.
- Know your stack: this guide gives examples for nginx, Apache and ASP.NET Core. Hosted platforms such as website builders often have a settings page for the 404 template, and you cannot change the status code there. Check that the platform returns 404.
- Time: about an hour for design and an hour for configuration and testing.
- Risk: low if you test on a staging copy. A configuration mistake can break every error response, so keep a backup of the current server configuration.
- Gather: your main navigation links, your most visited pages and your contact route. They go on the page.
Why the status code matters more than the design
Google's documentation on HTTP status codes explains how it handles errors. It treats all 4xx errors except 429 as telling it the content does not exist. URLs that return 404 are not indexed, and URLs already in the index that start returning 404 are removed from it. Newly found 404 pages are not processed, and Google gradually crawls them less often. Google ignores any content on a 4xx response, so the text and links on your error page are for people, not for search.
A soft 404 is the failure case. Google describes it as a page that returns a 2xx success code but whose content looks like an error, an empty page or an error message, and says Search Console reports it as a soft 404. A pretty "page not found" design served with a 200 status is exactly that. Our soft 404 guide covers finding and fixing existing ones.
Step-by-step instructions
Step 1: Decide what the page must do
A good error page does four things:
- Says plainly that the page was not found, in the same tone as the rest of the site.
- Keeps the normal header and navigation so visitors can continue.
- Offers a way forward: a search box, links to your most popular sections and a contact link.
- Does not pretend nothing is wrong. Avoid jokes that hide the message.
Why: the visitor arrived with a goal. Your job is to get them back on track in one click.
You have succeeded when you can write the page copy in three sentences and list five helpful links.
Step 2: Build the page as a real template
Create a normal page in your site's template, with a clear heading and useful links. Use relative asset paths that work from any URL depth, or absolute ones starting with /. A 404 page is served at whatever address the visitor requested, such as /old/path/that/is/missing, so a link like images/logo.png would break.
A minimal body might look like this:
<main>
<h1>We could not find that page</h1>
<p>The address may be mistyped, or the page may have been moved or removed.</p>
<ul>
<li><a href="/">Go to the home page</a></li>
<li><a href="/guides">Browse our guides</a></li>
<li><a href="/contact">Contact us</a></li>
</ul>
</main>
Add a <meta name="robots" content="noindex"> tag only if you worry about an accidental 200 response. It is a safety net, not a replacement for the correct status. Keep the page light, since slow error pages frustrate people who are already lost.
You have succeeded when the page displays correctly when opened directly at several URL depths.
Step 3: Serve it with a real 404 status
This is the step that matters. Configure your server to show the template while keeping the 404 code.
nginx: use error_page with a local path. nginx documents that this causes an internal redirect to the given URI, so the visitor's address does not change.
error_page 404 /404.html;
location = /404.html {
internal;
}
Do not write error_page 404 =200 /404.html;. The = form changes the response code that the client receives, and writing 200 there turns your error page into a soft 404. If you write a URL with a scheme, such as error_page 404 http://example.com/notfound.html;, nginx sends a redirect (302 by default), which is also wrong.
Apache: use ErrorDocument with a local path that begins with a slash.
ErrorDocument 404 /404.html
Apache's documentation says an action that begins with a slash is treated as a local URL, while a valid full URL is treated as an external redirect. Do not use the full address of your own site, because it is still handled as an external redirect.
ASP.NET Core: Microsoft documents two relevant middleware choices. UseStatusCodePagesWithReExecute re-runs the pipeline with an alternate path and does not alter the original status code, so the visitor sees the original URL and a 404. UseStatusCodePagesWithRedirects sends a 302 redirect to the error endpoint, which typically returns 200, so avoid it for this purpose.
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Then make sure the /StatusCode/404 handler does not set its own 200 status.
Single-page apps: client-side routing often returns 200 for every route. Google's JavaScript guidance suggests either redirecting to a URL that the server answers with a real 404, or adding a noindex robots meta tag when the content does not exist. The first is more reliable if you can do it. See JavaScript SEO rendering basics.
You have succeeded when requesting a missing URL shows your page at the same address in the address bar.
Step 4: Test the response code
Look at the raw response:
curl -sI https://example.com/this-page-does-not-exist-12345 | head -n 1
You should see:
HTTP/2 404
Also test a missing URL inside a folder, a missing file such as /missing.jpg, and a mixed-case or trailing-slash variation. Different parts of a site often use different error handling, and the one you did not test is the one that fails.
You have succeeded when every kind of missing URL returns 404 and shows the right page.
Step 5: Avoid redirecting missing URLs to the home page
It is tempting to send every unknown address to the home page. Visitors then land somewhere unrelated without explanation, and you lose the chance to tell them what happened. Reserve redirects for old URLs that have a real replacement (see 301 vs 302 redirects), and let everything else return 404. For permanently removed pages, you may also consider 410, as covered in 410 vs 404 for removed pages.
You have succeeded when random made-up URLs show the error page rather than the home page.
Step 6: Use the 404 report to find broken links
Your logs and Search Console show which missing URLs people and crawlers actually request. A URL that is requested often and has a clear replacement deserves a redirect. A broken link on your own site deserves a fix at the source. The broken internal links audit explains how to find them.
You have succeeded when you have a short list of recurring missing URLs, each with a decision: redirect, fix the link or leave as 404.
Final verification checklist
- A made-up URL returns a 404 status in the raw response.
- The custom page appears at the requested address, with no redirect.
- The page has the site header, navigation and links to key sections.
- Missing images, scripts and files also return 404, not a 200 HTML page.
- The error page loads quickly and its assets load from any URL depth.
- Missing URLs do not redirect to the home page.
- The page is not linked from your sitemap.
- Search Console shows no new soft 404 reports after a recrawl.
Common mistakes to avoid
- Serving the page with a 200 status. This creates a soft 404. Fix the server configuration, not the page text.
- Using
error_page 404 =200in nginx. The=200overrides the status. Remove it. - Using a full URL in Apache's
ErrorDocument. Apache handles it as an external redirect. Use a local path starting with/. - Choosing the redirect middleware in ASP.NET Core.
UseStatusCodePagesWithRedirectssends a 302 and the error endpoint usually returns 200. Use re-execute. - Relative asset links. The page appears at many URL depths, so
images/logo.pngbreaks. Use root-relative paths. - No navigation on the page. A dead end sends visitors away. Add a search box and key links.
- Redirecting all 404s to the home page. It confuses visitors and hides your broken links. Return a real 404.
Frequently asked questions
Does a custom 404 page help my rankings?
No. Google ignores the content of 4xx responses for indexing. The page is for visitors. Its technical correctness, meaning a true 404 status, is what matters to search engines.
Should the 404 page be in my sitemap?
No. A sitemap should list live, indexable pages, and the error page is not one of them.
Should I add noindex to my 404 page?
It is not needed if the status is 404, since Google does not index 4xx URLs. Some sites add it as an extra safeguard against a configuration error. It does not replace fixing the status.
What about my custom 404 page for non-HTML files?
Requests for a missing image or script should also return 404. They need not show the full designed page, and often a short response is better.
Can I have different 404 pages for different sections?
Yes, if your server or framework supports it. Each must return a real 404. Keep the number small so you can maintain them.
Is a 404 cached?
It can be. The HTTP standard (RFC 9110) describes a 404 response as heuristically cacheable, which means caches may keep it for a while unless headers say otherwise. If you restore a page, cached error responses may linger until they expire, so avoid long cache lifetimes on error pages.
Related guides
- 410 vs 404 for Removed Pages: Which Status Code to Return
- Soft 404 Errors: How to Find and Fix Them in Search Console
- Redirect Chains, Loops, and Incorrect HTTP Status Codes
- Find Broken Internal Links and Redirects Across Your Website
- JavaScript SEO: Server Rendering, Client Rendering and Crawlers
Official references
- https://developers.google.com/crawling/docs/troubleshooting/http-status-codes
- https://developers.google.com/search/docs/crawling-indexing/javascript/fix-search-javascript
- https://nginx.org/en/docs/http/ngx_http_core_module.html
- https://httpd.apache.org/docs/2.4/custom-error.html
- https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling
Next step: See how Crawvix checks a website and capture a baseline once scanning opens. This guide provides technical information, not a guarantee of rankings, traffic or index inclusion.
Crawvix Editorial Team
· Published October 29, 2026 · Last updated October 29, 2026 · 8 min read