How to Fix 404 Not Found Error

404 Not Found is the HTTP status code a web server returns when it receives a valid request for a resource that does not exist on that server. Unlike a 500 or 503, nothing is broken on the server itself — the request was understood, it simply has no matching file, route, or handler to serve. The browser then shows the familiar "404 — Page Not Found" screen, and search engines treat the URL as non-existent.

A 404 is not always a crisis. Resources are deleted, redesigned, and reorganized all the time, and a handful of 404s is the normal cost of running a site. The problem begins when the 404s point at content that should exist — a live product page, a published article, an API endpoint your app depends on. Those 404s lose visitors, break integrations, and erode search rankings. The good news is that almost every 404 traces back to one of six root causes, each with a clear fix. This guide walks through all of them, with server configuration examples for Nginx and Apache.

What Is a 404 Not Found?

When a browser asks a server for https://example.com/about.html, the server maps that path to a file on disk (or hands it to an application router). If the file is missing, the router has no matching route, and no rewrite rule rescues the request, the server responds with HTTP/1.1 404 Not Found. The response body is usually a generic error page, but the status code in the headers is what matters — it tells every client and crawler unambiguously that the resource is absent.

It is important to distinguish a true 404 (the server genuinely cannot find the resource) from a soft 404, where an application returns a 200 OK status with a "page not found" body. Search engines detect soft 404s and treat them like real ones, but they are harder to spot because the status code lies. Whenever you debug a 404, confirm the actual status code with curl -I rather than trusting the on-screen message.

A 404 is also distinct from a 403 Forbidden. A 403 means the resource exists but the server refuses to let you see it, usually because of permissions or access rules. A 404 means the server will not even confirm the resource exists. Mixing these up leads to wasted time changing permissions on a file that simply is not there.

Common Causes

Use this table to match your situation to its most likely root cause and the step that resolves it before reading the full guide.

Cause Where It Happens Fix
Typo in the URL — wrong case, trailing slash, or percent-encoding Address bar, inbound links, sitemaps Compare character by character with the real path (Step 1)
File is missing or unreadable due to permissions/ownership Server filesystem (/var/www, public_html) Set dirs to 755 and files to 644; fix ownership (Step 2)
Broken try_files or RewriteRule sends real paths to a missing fallback Nginx.conf, Apache .htaccess Disable rules and bisect to find the offending line (Step 3)
Page was moved or renamed during a redesign Old bookmarks, search indexes, internal links Find the new location in the access log (Step 4)
Browser or CDN serves a cached 404 or stale URL Client browser, Cloudflare/CDN edge cache Hard-reload, purge CDN, test incognito (Step 5)
No redirect exists for a permanently moved URL Server config, CMS redirect rules Add a 301 to the new URL or return 410 Gone (Step 6)

Step-by-Step Fix Guide

Step 1: Check the URL for typos

The cheapest 404 to fix is the one caused by a typo. Read the requested URL character by character and compare it against the real path of the file on the server. Pay attention to three things that browsers silently normalize but servers do not: trailing slashes (/about vs /about/), letter case (About.html vs about.html on case-sensitive filesystems like Linux), and percent-encoding (%20 vs a literal space). Confirm the typo theory by hitting the corrected URL:

# See the exact status code the server returns
curl -I https://example.com/about.html

If the corrected URL returns HTTP/1.1 200 OK, the original 404 was a typo or a malformed link. Update the inbound link that produced the wrong URL so other visitors do not hit the same dead end. Only when the corrected path also 404s should you move on to the server.

Step 2: Check file permissions

If the URL is correct, confirm the file actually exists on disk and that the web server can read it. SSH into the server and list the directory:

ls -l /var/www/example/about.html
# Expected: -rw-r--r-- 1 www-data www-data ... about.html

The web server process (commonly www-data, nginx, or apache) needs read access to the file and execute (traverse) access on every parent directory. A standard, safe setup is directories at 755 and files at 644, with ownership matching the web server user. If the file is present but the mode or owner blocks the server, you get a 404 (or sometimes a 403). Fix it:

# Correct ownership and permissions
chown -R www-data:www-data /var/www/example
find /var/www/example -type d -exec chmod 755 {} \;
find /var/www/example -type f -exec chmod 644 {} \;

Files uploaded by a different user, restored from a tarball, or synced from a CI pipeline frequently arrive with wrong ownership — this is one of the most overlooked causes of sudden 404s after a deploy.

Step 3: Verify .htaccess or Nginx rewrite rules

Modern sites rarely serve files straight from disk; a rewrite rule routes requests to an application or a fallback. If that rule is misconfigured, a perfectly valid URL gets rewritten to a path that does not exist, and the server returns a 404 even though the file is sitting right there. The classic example is a single-page app whose try_files falls through to a missing index.html, or a WordPress install whose .htaccess permalink rules were wiped.

To isolate the problem, temporarily disable the rewrite layer and reload. On Apache, rename .htaccess to .htaccess.bak. On Nginx, comment out the try_files line and run nginx -s reload. If the page now loads, the rewrite was the culprit. Restore the file and bisect — re-enable rules block by block, reloading after each, until the 404 returns. The last block you enabled contains the bad directive.

Step 4: Check for moved or renamed files

Redesigns, CMS migrations, and reorganizations routinely rename or relocate pages. The new site works perfectly, but every old bookmark, search result, and internal link still points at the previous URL — which now 404s. These are not typos and the files are not missing; they simply live somewhere else now.

Find the 404 paths in your access log and match each to its new home:

# List the most frequent 404s in the last 24h
grep ' 404 ' /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head

For each popular 404 path, locate the replacement page on the new site and add a 301 redirect (see Step 6). Do not leave moved content returning 404 — even a few high-traffic dead URLs can drag down your crawl budget and your search rankings.

Step 5: Clear browser and CDN cache

Browsers and CDNs cache responses, and that includes 404s. A page may have been fixed on the server minutes ago, yet you still see the old "Not Found" screen because the 404 response is cached at the edge or in your browser. Before you spend an hour debugging a problem that is already solved, rule out caching.

Hard-reload the page (Ctrl+Shift+R or Cmd+Shift+R), then test in a fresh incognito window. If you sit behind a CDN like Cloudflare, purge the cache from the dashboard or with the API. If the page loads after the purge, the 404 was a stale cache entry, not a live server response — nothing further needs to change on the origin.

Step 6: Set up proper 301 redirects

Once you know a URL has permanently moved, do not leave it returning 404. Add a 301 Moved Permanently redirect from the old URL to the new one. A 301 tells browsers and search engines to update their records, passes link equity to the new page, and is far better for SEO than leaving a dead end. For content that is genuinely gone forever and has no replacement, return 410 Gone instead — it tells crawlers the removal is intentional and the URL can be dropped from the index faster.

For the rare 404s you cannot eliminate (deleted pages with no replacement, mistyped inbound links you cannot control), serve a helpful custom 404 page with your site navigation and a search box so visitors can find their way back instead of bouncing.

Server Configuration Examples

Both Nginx and Apache give you a single directive to handle missing files gracefully and a second to add 301 redirects. Use these as a starting point and adapt the paths to your layout.

Nginx: try_files and custom 404

The try_files directive tells Nginx what to do when a file is not found on disk. The last argument is the fallback — usually your front controller or a single-page app shell. Pair it with error_page to serve a branded 404 for genuinely missing routes.

server {
    listen 80;
    server_name example.com;
    root /var/www/example;

    location / {
        # Try the exact file, then a directory, then fall back to the SPA shell
        try_files $uri $uri/ /index.html?$args;
    }

    # Serve a branded 404 page for unmatched routes
    error_page 404 /404.html;
    location = /404.html {
        internal;
        root /var/www/example;
    }

    # 301 redirect an old path to its new home
    location = /old-page.html {
        return 301 /new-page.html;
    }
}

Apache: .htaccess rewrites and redirects

On Apache, the same behavior lives in .htaccess. ErrorDocument controls the 404 page, RewriteRule sends missing files to your front controller, and Redirect handles permanent moves.

# Branded 404 page for missing routes
ErrorDocument 404 /404.html

<IfModule mod_rewrite.c>
    RewriteEngine On
    # If the request is not a real file or directory, route to the front controller
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
</IfModule>

# 301 redirect an old path to its new home
Redirect 301 /old-page.html /new-page.html

After editing Nginx, validate and reload with nginx -t && nginx -s reload. Apache picks up .htaccess changes immediately with no restart.

Quick Reference Table

The 4xx family of status codes all describe client-side problems, but they mean very different things. Mixing them up leads to fixing the wrong thing — changing permissions on a file that does not exist, or hunting for a missing page that is actually forbidden. Use this table to read a status code correctly before you start debugging.

Code Name Meaning Typical Cause
400 Bad Request Server cannot parse the request Malformed URL or query string
401 Unauthorized Authentication required and missing/invalid Missing or expired login credentials
403 Forbidden Authenticated (or not) but not allowed File permissions, .htaccess deny rules
404 Not Found Resource does not exist on the server Broken link, missing file, wrong rewrite rule
410 Gone Resource existed but was permanently removed Intentionally deleted page with no replacement

The practical distinction: 401 asks "who are you?", 403 says "I know who you are and the answer is no", 404 says "I have no idea what you are asking for", and 410 says "that used to exist but I deleted it on purpose". Choose 410 over 404 when a page is deliberately removed — it speeds up removal from search indexes.

FAQ

Is a 404 error bad for SEO?

A handful of 404s is normal and not harmful on its own — Google simply drops those URLs from its index. What hurts is 404s on pages that should exist and that have inbound links or search traffic. Those lose link equity and rankings. Fix 404s on important pages with 301 redirects, and let genuinely deleted pages return 410 Gone or a helpful custom 404 so visitors are not stranded.

How do I find all 404 errors on my site?

Three sources cover most cases. Google Search Console lists 404s under Coverage → Excluded → "Not found (404)". Your server access log shows every 404 in real time — filter with grep ' 404 ' access.log. And server-side error monitoring or a link crawler like Screaming Frog will surface broken internal links during a full-site crawl. Cross-reference the three to prioritize by traffic.

Should I redirect 404s to the homepage?

Generally, no. Bulk-redirecting every 404 to the homepage is treated by Google as a soft 404 — the homepage returns 200, but since the content is unrelated, the original URL is still effectively dropped. Instead, 301 each old URL to its closest topical replacement. Only send visitors to the homepage (or a custom 404 with navigation) when no relevant replacement exists.

What is the difference between a soft 404 and a hard 404?

A hard 404 returns the actual 404 Not Found status code in the HTTP headers. A soft 404 returns 200 OK but shows a "page not found" message in the body — typically because an application catches a missing record and renders an error template without setting the status code. Search engines detect soft 404s and treat them like real ones, so always confirm the status code with curl -I and make sure your app returns a real 404 status when content is missing.

Conclusion

A 404 Not Found is the server's honest way of saying "that resource is not here". Most of the time the fix is simple: confirm the URL is typed correctly, verify the file exists with the right permissions, make sure your rewrite rules are not misrouting valid paths, locate content that was moved, clear cached 404s, and add 301 redirects for anything that has permanently relocated. Work through the six steps in order, confirm the real status code with curl -I at each stage, and remember that a clean 200 on the canonical URL — not the absence of an error page — is the signal you are done.

Related Guides