Why Nginx Returned 403 After Jenkins Deployment and How to Fix It
This article walks through a real‑world deployment failure where Nginx served a 403 error after Jenkins‑driven releases, explains the root causes such as file‑permission mismatches and Tomcat 8's default umask, and provides step‑by‑step fixes to restore proper access.
Background
The release system consists of Jenkins invoking a deployment program (code‑named varian ) that builds a Docker image, pushes it to a registry, and updates a container cluster accessed through a load balancer.
The legacy varian was a mix of shell and Python scripts running on Jenkins (JDK 1.7) with many compatibility hacks, resulting in tangled code.
We decided to rewrite varian entirely in Python, modularize its functions, upgrade Jenkins to the latest version, and move JDK to 1.8. The new environment runs on Debian 8 with Python 3.4, JDK 1.8, and Jenkins 2.134.
System: Debian 8
Language: Python 3.4
JDK 1.8 + Jenkins 2.134
Fault Handling Process
Resolving Nginx 403 Errors
After Jenkins deployed a static HTML project, the web page loaded without CSS because the browser reported a 403 status for the CSS file.
Typical reasons for Nginx returning 403 include:
IP not in the configured whitelist.
Directory listing disabled while the request points to a directory.
File owned by a user/group that Nginx lacks read permission for.
Incorrect
indexdirective (e.g., referencing
index.shtmlwhen only
index.htmlexists).
Investigation showed the CSS file owned by
root:rootwith permissions
-rw-r-----, while Nginx runs as
www-data. The missing read permission for the www-data user caused the 403.
Understanding Linux File Permissions
Example output:
-rw-r----- 1 root root 7.9K Jul 24 12:34 csl.cssThe first ten characters define the file type and permission bits.
Characters 2‑4: owner permissions; 5‑7: group permissions; 8‑10: others.
Permissions are represented by
r(read = 4),
w(write = 2),
x(execute = 1).
In the example, the owner has read/write, the group has read, others have none.
Tomcat 8 UMASK Issue
Running the same Python script directly from the console produced correct file permissions, but executing it via Jenkins resulted in wrong permissions.
The discrepancy was due to the
umasksetting, which defines default permissions for newly created files. While both the root and Jenkins users had a umask of
0022, Tomcat 8 (the container running Jenkins) changed the default umask to
0027, stripping group read/write bits.
Changing Tomcat 8’s umask back to
0022resolved the permission problem.
Article originally published by the “运维咖啡吧” public account, author “37丫37”.
Efficient Ops
This public account is maintained by Xiaotianguo and friends, regularly publishing widely-read original technical articles. We focus on operations transformation and accompany you throughout your operations career, growing together happily.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.