Back to Blog Engineering
2 min read ✉ Subscribe
Soft 404s are quietly costing you search traffic
Engineering

Soft 404s are quietly costing you search traffic

If every mistyped URL returns your home page with a 200, search engines will index all of them as real pages — and split your ranking across the duplicates.

AX
Alien XP
Jul 26, 2026 · 2 min read

Here is a configuration almost every PHP site has, and it is usually correct:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Any path that is not a real file goes to index.php, which routes it. Clean URLs, no rewrite rules per page. The problem is what happens at the end of that router, when nothing matched.

The failure mode

If the fallback is "render the home page", then every typo, every dead link from an old post, every URL a scanner invents, returns HTTP 200 with a full page of content. To a crawler that is not an error. That is a real page that happens to look identical to your home page.

Google calls this a soft 404, and it treats it as a quality problem. You end up with an unbounded set of URLs serving duplicate content, crawl budget spent on paths that do not exist, and ranking signals split across them.

$ curl -s -o /dev/null -w '%{http_code}\n' https://example.com/this-does-not-exist
200      # should be 404

The fix is three lines

At the point where your router has run out of options, say so:

if ($path !== '' && $path !== 'index.php') {
    http_response_code(404);
    header('X-Robots-Tag: noindex');
}
// then render whatever body you like

Note that the body can still be useful. Showing your home page, or a search box, is kinder to a human who mistyped than a bare error. The status code is what tells the crawler the truth, and the two are independent.

X-Robots-Tag: noindex is belt and braces — a 404 is already enough for most crawlers, but the header removes any ambiguity for the ones that render before checking status.

Check the rest of the family while you are there

  • An unpublished draft should 404, not redirect to the index — a redirect tells the crawler the content moved.
  • A deleted post should 404 or 410, not 301 to the home page. Redirecting everything to / is a classic soft-404 generator.
  • A paginated listing beyond the last page should 404 rather than render an empty grid with a 200.

How to verify it

Do not trust the browser — it renders the body and shows you nothing about status. Ask for the code directly, across the routes that matter:

for u in / /real-page /nope /blog /blog/nope; do
  printf '%-16s %s\n' "$u" "$(curl -s -o /dev/null -w '%{http_code}' https://example.com$u)"
done

You want 200 for the pages that exist and 404 for everything else. If that list is all 200s, you have been publishing an infinite website and telling search engines every page of it is real.

Filed under #seo#nginx#http#php
AX

Alien XP

Engineering · 10 essays

Runs the servers behind AlphaPanel and writes up what breaks.

Keep reading

All posts