A 403 from nginx means the server understood the request and refused to serve it. The page itself says almost nothing: "403 Forbidden" and nginx. The error log says everything, because nginx records a different message for each reason. Start there rather than guessing.
sudo tail -n 30 /var/log/nginx/error.log
Find the line for your request and match it to a case below. For the HTTP status in general, see the HTTP 403 reference और HTTP 403 Forbidden fix.
Decision table
| Log message | Cause | Fix |
|---|---|---|
directory index of "/path/" is forbidden | No index file, autoindex off | Directory index forbidden |
open() "/path/file" failed (13: Permission denied) | The worker user cannot read or traverse | Permission denied (13) |
access forbidden by rule | An allow or deny directive matched | Edit the access rules |
| Nothing in nginx's log | The 403 comes from another layer | Check upstream, CDN, WAF |
The first two have their own pages with full detail. Here is a brief version and the rest.
Case 1: file permissions and ownership
nginx workers run as the user in the user directive of nginx.conf (often www-data or nginx). That user needs read on the file and execute on every parent directory.
ps -o user= -C nginx | sort -u
namei -l /var/www/example.com/public/index.html
A home directory at mode 700 is the classic blocker for sites under /home/user/public_html. Fix by granting traverse permission to the nginx group, or move the site to /var/www. Do not run nginx as root, and do not use 777.
Case 2: no index file
A request for / with no index.html or index.php yields directory index ... is forbidden. Add the file, fix root, or add an index directive. See nginx directory index forbidden.
Case 3: allow and deny rules
access forbidden by rule, client: 198.51.100.4, request: "GET /admin/ HTTP/1.1"
Search the config for access rules and check their order. nginx evaluates allow and deny in sequence and stops at the first match:
location /admin/ {
allow 203.0.113.0/24;
deny all;
}
If your own IP changed or you are behind a proxy, nginx sees the proxy's address. Behind a CDN or load balancer, configure the real IP module (set_real_ip_from and real_ip_header) so rules apply to the client address, not the proxy. The CDN डिटेक्टर tells you whether a CDN sits in front.
Case 4: SELinux
On RHEL, Rocky, Alma and Fedora, the file label must allow web access. Permissions look right, yet nginx logs permission denied:
ls -Zd /srv/site
sudo ausearch -m avc -ts recent
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/site(/.*)?"
sudo restorecon -Rv /srv/site
Case 5: symlinks and disable_symlinks
If the config contains disable_symlinks on (or if_not_owner), nginx will refuse to follow symlinks, a common setup for atomic deploys using a current link. Either remove the directive or adjust it, for example disable_symlinks if_not_owner from=$document_root;, and make sure ownership of link and target agree.
Case 6: the 403 comes from somewhere else
If nginx logs nothing for the request, check who answered. Look at response headers with the HTTP Header Checker:
- A
cf-rayheader and Cloudflare branding point to a firewall rule or country block at the CDN. See Cloudflare's error 1020 page. - A
Serverheader from a different product means an upstream app or WAF sent it. nginx can proxy a backend's 403 untouched. - A hosting provider may block IPs or user agents ahead of your server.
Test directly against the origin with curl -I --resolve example.com:443:ORIGIN_IP https://example.com/ and compare.
Case 7: application-level 403
If nginx proxies to PHP-FPM, Node or Python and the backend returns 403, nginx just passes it through. The app log (Laravel, Django, WordPress security plugins, ModSecurity) will explain. Also check fastcgi_param SCRIPT_FILENAME; a wrong path leads to "Primary script unknown" and a 404, not a 403.
Triage order
- Read the error log line for your request.
- Check which user nginx runs as and whether it can read the path.
- Confirm the index file or the intended
try_filesbehavior. - Search for
allow/deny,auth_request,satisfyandlimit_except. - On SELinux systems, check labels.
- If nginx logs nothing, find the layer that does.
How to verify
Request the page with curl -I and confirm 200. Test both the failing URL and one that already worked, and run the HTTP स्टेटस चेकर from outside your network, since an IP allow list may behave differently there. Put the page under an अपटाइम मॉनिटर so a permission change after the next deploy alerts you.
अगले कदम
- Read nginx directory index forbidden.
- Fix nginx permission denied (13).
- See the Apache version: Apache Forbidden: no permission to access.
- Review HTTP 403 Forbidden fix.
सामान्य प्रश्न
What is the difference between 401 and 403?
401 asks you to authenticate; 403 refuses even if you are known or when no login would help. nginx basic auth failures return 401.
Why does nginx return 403 instead of 404 for some paths?
When the path is a directory it cannot list, or access rules deny a location regardless of whether the file exists. A true missing file gives 404.
Does robots.txt cause a 403?
No. Robots rules advise crawlers and never block requests. A 403 on robots.txt itself usually points to permissions or a firewall.
Can I fix this with chmod 777?
You should not. It hides the cause and makes files writable by every local user. Grant exactly the read and traverse permissions nginx needs.
Get notified when this fix updates
Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.
यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.