{"id":24,"date":"2026-10-13T20:51:00","date_gmt":"2026-10-13T20:51:00","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2014\/07\/21\/404\/"},"modified":"2026-10-13T20:51:00","modified_gmt":"2026-10-13T20:51:00","slug":"404","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/404\/","title":{"rendered":"HTTP 404 for DevOps: Root-Cause, Routing, and Prevention Across Edge, Ingress, and App Layers"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">HTTP 404 errors look straightforward to end users, but in real-world platforms they can originate from several layers: edge, ingress, reverse proxy, or application routing. This guide is for DevOps engineers who need a fast, repeatable way to isolate the source, fix it safely, and reduce recurring not-found incidents.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Originally published on 2014-07-21; fully revised and updated.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What an HTTP 404 means operationally<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A <strong>404 Not Found<\/strong> response means the server handling the request could not find a resource at the requested path. In distributed deployments, this does <em>not<\/em> immediately prove the application is broken; it may indicate routing, rewrite, cache, or host-header mismatches before traffic even reaches the app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where 404s commonly originate<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Layer<\/th><th>Typical 404 cause<\/th><th>First check<\/th><\/tr><\/thead><tbody><tr><td>CDN or load balancer<\/td><td>Path rule, origin mapping, or stale cache behavior<\/td><td>Edge logs and cache config for the exact URL<\/td><\/tr><tr><td>Ingress or API gateway<\/td><td>Host\/path mismatch, missing rewrite, wrong backend service<\/td><td>Ingress route definitions and host header used in request<\/td><\/tr><tr><td>Reverse proxy (Nginx\/Apache)<\/td><td>Location block mismatch or try_files behavior<\/td><td>Effective server block and access logs<\/td><\/tr><tr><td>Application router<\/td><td>Missing endpoint or route regression after deploy<\/td><td>App route map and release diff<\/td><\/tr><tr><td>Content\/data store<\/td><td>Resource deleted, unpublished, or wrong identifier<\/td><td>Lookup of expected object in datastore\/CMS<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">404 triage workflow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use a top-down flow: reproduce the error, determine which layer generated it, then patch the specific route or resource. This avoids chasing application bugs when the issue is at the edge.<\/p>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[User reports missing page] --> B[Reproduce with curl and host header]\n    B --> C{Response is 404?}\n    C -- no --> D[Investigate non 404 issue]\n    C -- yes --> E[Check CDN or load balancer logs]\n    E --> F{404 at edge?}\n    F -- yes --> G[Fix edge route or cache rule]\n    F -- no --> H[Check ingress or reverse proxy routes]\n    H --> I{Route match exists?}\n    I -- no --> J[Fix path mapping or rewrite]\n    I -- yes --> K[Check app routes and resource data]\n    K --> L[Deploy fix and add alert]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step-by-step checks with commands<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Reproduce from the client side and with explicit host header<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">curl -i https:<span class=\"hljs-comment\">\/\/example.com\/docs\/install<\/span>\ncurl -i -H <span class=\"hljs-string\">\"Host: example.com\"<\/span> http:<span class=\"hljs-comment\">\/\/INGRESS_IP\/docs\/install<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The second request helps confirm whether DNS\/CDN behavior differs from direct ingress behavior.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Validate Kubernetes ingress and service wiring<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">kubectl <span class=\"hljs-keyword\">get<\/span> ingress -A\nkubectl describe ingress my-app -n prod\nkubectl <span class=\"hljs-keyword\">get<\/span> svc -n prod\nkubectl <span class=\"hljs-keyword\">get<\/span> endpoints my-service -n prod<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Look for host\/path rules that do not match the failing URL, and ensure the target service has healthy endpoints.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Confirm reverse-proxy route behavior<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-nginx\">server {\n    listen <span class=\"hljs-number\">80<\/span>;\n    server_name example.com;\n\n    location \/ {\n        try_files $uri $uri\/ =<span class=\"hljs-number\">404<\/span>;\n    }\n\n    error_page <span class=\"hljs-number\">404<\/span> \/<span class=\"hljs-number\">404.<\/span>html;\n    location = \/<span class=\"hljs-number\">404.<\/span>html {\n        internal;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Choose the right response code<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Status code<\/th><th>Use when<\/th><th>Operational note<\/th><\/tr><\/thead><tbody><tr><td>404 Not Found<\/td><td>Resource is not found at the requested path<\/td><td>Good default for unknown or missing URLs<\/td><\/tr><tr><td>410 Gone<\/td><td>Resource was intentionally removed and will not return<\/td><td>Useful when removal is deliberate and permanent<\/td><\/tr><tr><td>403 Forbidden<\/td><td>Resource exists but access is denied<\/td><td>Avoid replacing auth failures with 404 unless policy requires it<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Monitor 404 trends before users escalate<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Track top missing paths and sudden spikes. Even simple log analysis can reveal broken links, bad rewrites, and deployment regressions quickly.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">awk <span class=\"hljs-string\">'$9 == 404 {print $7}'<\/span> \/<span class=\"hljs-keyword\">var<\/span>\/log\/nginx\/access.log | sort | uniq -c | sort -nr | head <span class=\"hljs-number\">-20<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Best practices<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Test critical URLs in CI\/CD after each deployment.<\/li><li>Validate host and path routing at every layer (edge, ingress, proxy, app).<\/li><li>Use consistent rewrite rules across environments to avoid drift.<\/li><li>Create alerts on abnormal 404 rate changes, not only absolute counts.<\/li><li>Serve a helpful custom 404 page, but keep the HTTP status code accurate.<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>HTTP 404 errors are simple for users but often complex in distributed systems. This guide shows DevOps teams how to locate the failing layer, apply the right fix, and prevent repeat incidents.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-24","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=24"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/24\/revisions"}],"predecessor-version":[{"id":79233,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/24\/revisions\/79233"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}