एरर समाधान · सर्वर एरर

nginx 403 Forbidden: Diagnose by Error Log Message and Fix

Diagnose an nginx 403 Forbidden using the exact error log line: permissions, missing index, deny rules, SELinux, symlinks or an upstream. Includes a decision order.

Error message403 Forbidden nginx

लेखक: SiteDownCheck संपादकीय टीम · अपडेट: अक्टूबर 21, 2026 · 4 मिनट पढ़ने में

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 messageCauseFix
directory index of "/path/" is forbiddenNo index file, autoindex offDirectory index forbidden
open() "/path/file" failed (13: Permission denied)The worker user cannot read or traversePermission denied (13)
access forbidden by ruleAn allow or deny directive matchedEdit the access rules
Nothing in nginx's logThe 403 comes from another layerCheck 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

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-ray header and Cloudflare branding point to a firewall rule or country block at the CDN. See Cloudflare's error 1020 page.
  • A Server header 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

  1. Read the error log line for your request.
  2. Check which user nginx runs as and whether it can read the path.
  3. Confirm the index file or the intended try_files behavior.
  4. Search for allow/deny, auth_request, satisfy and limit_except.
  5. On SELinux systems, check labels.
  6. 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.

अगले कदम

सामान्य प्रश्न

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.

यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.