This is a 403 with a specific flavour: the server understood the request, identified something about the client it did not like, and refused before any authentication was considered. It is usually about where the request came from, not who sent it.
That distinction is the useful one. A 401 means the server does not know who you are and invites you to identify yourself. This 403 means the server has decided, on the basis of something other than your identity, that this request will not be served, and no login will change that.
In practice the something is almost always the source address, which is why the error tends to follow a network rather than an account.
Table of contents
- Why it is nearly always about the address
- What to try as the person hitting it
- If you own the server: finding which rule fired
- The permissions case, which is the other half
- Reducing how often this happens to you
- How this fits the rest of the stack
- FAQ
Why it is nearly always about the address
The classic version of this error appears when you are on a particular network and disappears when you change networks. Same account, same browser, same device, different address, different outcome.
That pattern means the server is blocking a range rather than a person, and the usual reasons are:
- A shared address with a bad reputation. Carrier-grade NAT, a VPN exit node, a corporate gateway or a datacentre range where someone else on the same address behaved badly.
- Automated abuse detection. Rate limits, scraping detection or scanner fingerprinting triggered by traffic that was not yours.
- Geographic restrictions. Content licensed or regulated by region, or a service that blocks countries it does not operate in.
- Datacentre ranges blocked wholesale. Many services refuse traffic from cloud provider ranges because most of it is automated, which catches anyone browsing through a VPS or a cloud desktop.
The tell that confirms it: the same request from mobile data succeeds while the same request from your usual connection fails. That is a range block, and no amount of clearing cookies will address it.
# What address is the server actually seeing?
curl -s https://ifconfig.me; echo
# Does the request succeed at all, and with what headers?
curl -sI https://example.com/the/path
What to try as the person hitting it
In order of likelihood, and the first two cover most cases.
- Change network. Mobile data, a different connection, or turning a VPN off. If the block is address-based this resolves it immediately and confirms the diagnosis.
- Turn off the VPN or proxy. Commercial VPN exit addresses are heavily blocked precisely because they are shared with a lot of automated traffic.
- Try a private window. Rules out an extension adding headers or a stale cookie the server dislikes.
- Check whether it is one path or the whole site. One path pointing at a permission rule; the whole site pointing at an address block.
- Wait. Automated blocks frequently expire on their own, typically within hours.
If it persists and you have a legitimate need, contacting the site with your address and a timestamp is the realistic route. There is rarely a self-service unblock, because a self-service unblock would be trivially abusable.
One thing not to do: repeatedly retrying. Automated blocking systems commonly extend the ban on continued attempts, so hammering the endpoint turns a temporary block into a longer one.
If you own the server: finding which rule fired
From the other side, the job is identifying which layer produced the refusal, because several layers can generate a 403 and they log in different places.
Check them in order, outermost first:
- The CDN or proxy. If a firewall rule or bot management triggered, the request never reached your origin and nothing appears in your access log. The proxy dashboard is the only place the event exists.
- The web server. A deny rule, a directory without an index and autoindex disabled, or a location block restricted by address.
- Automated banning tools. Intrusion prevention systems that ban addresses after failed attempts.
- The application. An authorisation check returning 403 deliberately.
- Filesystem permissions. The web server process cannot read the file, which produces a 403 rather than a 404.
# Is the request even reaching the origin?
sudo grep ' 403 ' /var/log/nginx/access.log | tail -20
# What did the web server think was wrong?
sudo tail -50 /var/log/nginx/error.log
# Any recent automated bans?
sudo fail2ban-client status
sudo iptables -L INPUT -n | head -30
The first check is the most valuable. An empty access log for a request the user says they made proves the refusal happened above your server, which redirects the entire investigation.
The permissions case, which is the other half
When the 403 is not address-based, it is usually the web server being unable to read what it was asked to serve.
The process needs read permission on the file and execute permission on every directory in the path leading to it. A single directory missing execute produces a 403 on everything beneath it, which is why the symptom often looks broader than the change that caused it.
# Walk the path and show permissions at each level.
namei -l /var/www/example.com/public/index.html
# What user is the web server running as?
ps aux | grep -E 'nginx|apache|httpd' | head -3
A sane baseline is directories at 755 and files at 644, owned by your deploy user with the web server’s group able to read. Avoid 777 as a fix; it makes the symptom go away and leaves files writable by any process on the machine.
A special case worth knowing: on systems running SELinux, correct Unix permissions are not sufficient. The security context also has to allow it, and the error is identical, which makes it a memorable hour if you have not met it before.
Reducing how often this happens to you
From the owner’s side, most preventable 403s come from rules that were too broad or too permanent.
- Prefer a challenge to an outright block for ambiguous traffic. A real user passes it; a simple bot does not; nobody emails support.
- Set expiry on automated bans. Permanent bans accumulate and eventually block a customer whose provider recycled an address.
- Rate limit per endpoint rather than globally, so a busy customer on a shared corporate address is not treated as an attacker.
- Log the block reason somewhere you can search. A 403 you cannot attribute to a rule is one you cannot fix.
- Return something useful. A 403 body naming a reference identifier turns a support conversation from guesswork into a lookup.
That last point is worth doing even though it feels minor. A person hitting a wall with a reference code gets help in one message; a person hitting a blank refusal usually just leaves.
How this fits the rest of the stack
Access rules are one of the places where operational complexity quietly accumulates, and the amount of it scales with how many layers you run yourself, each with its own way of saying no and its own place to log it. The RunxBuild hosting calculator prices the simpler shape, where runtime logs sit next to the deploy that produced them and there are fewer separate systems that can refuse a request without telling you which one did.
Useful related references:
- Git Set URL Remote: Changing Where Your Repository Pushes
- How to Create a Node Backend: From
node app.jsto a Live URL Without the Tutorial Cuts - Dynamic URL: Why It Is Usually a Marketing-Team Phrase, and the Three Engineering Questions It Actually Contains
- Services on RunxBuild
FAQ
Why do I get this error on one network but not another?
Because the block is based on your source address rather than your account. Shared addresses from carrier NAT, VPN exit nodes, corporate gateways and datacentre ranges are commonly blocked after abuse from someone else using the same address. Switching to mobile data usually confirms it.
What is the difference between 401 and 403?
A 401 means the server does not know who you are and is inviting you to authenticate. A 403 means the server has decided this request will not be served regardless of identity. Logging in fixes a 401 and will not fix a 403.
How do I get my IP unblocked?
Usually by contacting the site with your address and an approximate timestamp, since self-service unblocking would be easy to abuse. Many automated blocks expire on their own within hours, and repeatedly retrying often extends them, so waiting is frequently more effective than persisting.
Why does my own site return 403 on some files?
Most often filesystem permissions. The web server process needs read access to the file and execute access on every directory above it, so one directory missing execute breaks everything beneath it. Use namei to walk the path. On systems with SELinux, the security context also has to allow access.
Can a CDN cause this error without my server knowing?
Yes, and it is common. If a firewall or bot management rule at the edge refuses the request, it never reaches your origin and no entry appears in your access log. An empty access log for a request a user reports making is strong evidence the refusal happened above your server.