Tutorials

HTTP Status Codes: A Practical Guide to Common Errors

Interpret HTTP status codes correctly: the difference between 301 and 302, why 403 differs from 401, and why 503 is usually not your server's fault.

Tutorials

You've opened the server log and the status column is full of numbers, none of which are "200". A client calls saying "the site is down", but the site is up; their browser just got a 403 and you're hunting for a PHP problem. This article is for that exact moment: figuring out what the HTTP status code is actually telling you, and which ones you should fix in code versus in Nginx or DNS.

First, see the status code instead of guessing

Before any analysis, get the raw server response. The browser hides a lot; curl doesn't:

curl -sSI https://example.com/old-page | head -n 20
curl -sS -o /dev/null -w "%{http_code} %{time_total}s %{redirect_url}\n" https://example.com/

The -I flag fetches only the headers, and if you add -L it follows the redirect chain, which is where you realize you've hit three 301s in a row. The -w output also prints the final code and total time. If the number you see differs from what you saw in the browser, a CDN or intermediate cache has probably altered the response, and you should also check the cf-cache-status or x-cache header.

To see statuses at scale, count the access log directly:

awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

If the ninth column of your log isn't the status code, the log format is custom and you should first check log_format in Nginx. This count tells you in ten seconds whether the problem is systemic or tied to a specific path.

301 vs. 302: which one to put in your code

Both are permanent redirects and both pass SEO weight. Their real difference lies in browser caching and the request method. 301 means "this address has changed forever" and browsers are allowed to cache the response; 302 means "for now, don't go here, go there" and isn't cached. In practice, you see the difference when you've set a wrong redirect and want to revert it: with 301, users who've already visited the site keep going to the wrong destination until they clear their browser cache. With 302, you don't have that pain.

My choice: for a permanent URL structure change, use 301. For testing, for temporary campaign redirects, and for anything that might change by tomorrow, use 302. If you're unsure, use 302; its cost is one extra header per request, nothing more.

A technical point that trips up many people: with 301 and 302, the browser may convert a POST method to GET. If you redirect a form with 301, the request body is lost. To preserve the method, you need to send 307 or 308. This is where people go wrong: they send a payment form with 301 to a thank-you page and then find the POST data never arrived, while the log shows only a healthy 301.

In Nginx, write redirects with return, not rewrite; it's more readable and prevents redirect loops:

location = /old-page { return 301 /new-page; }
location = /promo     { return 302 https://example.com/campaign; }

401 and 403: two completely different errors that get confused

401 means "you haven't proven your identity". 403 means "I know who you are, but you're not allowed". This distinction is critical in troubleshooting, because the fix paths diverge. If the log is full of 401s, the problem is authentication: an expired token, a missing cookie, or an Authorization header stripped by an intermediate proxy. If it's full of 403s, the user is logged in and the problem is at the permission level.

A recurring pattern I see often: static files on the site return 403 but the homepage is fine. The cause is almost always file permissions on disk, not application code:

namei -l /var/www/example.com/wp-content/uploads/2024/05/image.jpg

namei -l shows the entire path from the root, and right there you can see an intermediate directory has 700 permissions and Nginx, running as the www-data user, can't enter it. This is where people go wrong: instead of fixing that directory's permissions, they run chmod -R 777 across the board. The result is the error disappears for a few hours and then comes back, because the next upload script sets the correct permissions again. The correct permissions are 755 for directories and 644 for files.

On the application side, return 403 deliberately and with a clear message. The difference between "403" and "404" matters to the end user: if a page exists but the user isn't allowed, returning 404 just creates confusion and leaves no trace in the log either.

503: why it's almost never your server's fault

503 means the server temporarily can't process the request and the problem is on the infrastructure side, not with the user's request. You see this code more than anywhere else on CDNs and load balancers, when the backend isn't responding or capacity is exhausted. Its difference from 500 is precisely that "temporary" quality: 500 means the application errored, 503 means the application didn't even get a chance to respond.

If your own site returns 503 and there's no CDN in front of it, it usually means the PHP-FPM workers are exhausted. Confirm it with these two commands:

systemctl status php8.2-fpm --no-pager
grep -E "pm.max_children|pm.max_requests" /etc/php/8.2/fpm/pool.d/www.conf

If you see the line server reached pm.max_children setting, consider raising it in the FPM log, that's the problem. Raising pm.max_children works, but it isn't free: each worker takes memory, and if you raise the number recklessly, the server hits swap and everything gets slower. Calculate the right number from available memory, not from guesswork. If you're on Linux hosting and hitting the resource ceiling, this is the point where you should consider upgrading your plan.

To monitor this situation, set alerts on the status code, not on "the site didn't open". The guide on monitoring website uptime covers exactly this: how to get alerts without every brief restart generating a false alarm.

Quick decision table

CodeShort meaningWhere to look first
301Moved permanentlyRedirect rules in Nginx or the SEO plugin
302Moved temporarilySame, but don't check the browser cache
401UnauthorizedCookie, token, Authorization header
403ForbiddenFile and directory permissions, deny rules
404Not foundFile path, rewrite rules
503Service unavailableFPM workers, capacity, CDN

A common trap in the table above: don't confuse 404 with 410. 410 means the resource is gone forever and won't come back; use that for deleted product pages, not 404. The difference is that 410 tells the crawler not to come looking for it again.

If you want to understand how much these codes affect real speed, you first need to know which requests are slow. The guide on website speed testing explains how to interpret the results and helps you tell the difference between a slow 301 and a genuine 503. For WordPress sites, WordPress speed optimization is a better starting point, since half of these codes come from redirect plugins.

Frequently asked questions

How much does the 301 vs. 302 difference matter for SEO?

Both pass page weight, so there's no significant difference in ranking. The main difference is in browser cache behavior: 301 is cached and harder to revert, 302 isn't. If you're sure the change is permanent, use 301; otherwise, 302.

Why does my site return 403 but I can open it myself?

Because you're logged in with an admin account and everyone else is sending requests without it. This almost always means the access rule or file permissions aren't set correctly for guest users. Test with an incognito window or curl without cookies to see the same error.

Should I report a 503 error to my hosting or fix it myself?

If a CDN is in front of the site and the 503 is coming from it, first check the backend status. If the backend is healthy, the problem is on the CDN side. If the backend isn't responding and FPM workers are maxed out, it's a resource problem and you should either fix the settings or upgrade your plan.

Status code 200 but a blank page; is that also an error?

Yes, and it's the worst kind, because no monitoring tool catches it. The server says everything is fine and the user sees a white page. For this case you need to check the response content too, not just the code; a simple script that checks the response body length is enough.

Next step: run that one awk command on your access log right now. If more than five percent of your requests are 403 or 503, that's your site's real problem, not whatever you've been chasing so far.

ServerNet Support

ServerNet engineering & editorial team — specialists in infrastructure, networking and web hosting.

WordPress Hosting
Share:

Comments 0

No comments yet — be the first!

Leave a comment

Related service

WordPress Hosting

A purpose-built WordPress stack on LiteSpeed Enterprise and NVMe — auto-install, secure updates, staging and caching that keeps you on top of Google.