When implementing Nginx as a reverse proxy for Jenkins with HTTP Basic Authentication, developers often encounter issues passing the authenticated username to the backend service. The current approach of forwarding $http_authorization
directly creates complications since Jenkins expects the username in a different format.
Here's the corrected Nginx configuration that properly forwards authentication details:
location / {
auth_basic "Restricted";
auth_basic_user_file /usr/share/nginx/.htpasswd;
sendfile off;
proxy_pass http://192.168.178.102:8080;
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Forwarded-User $remote_user;
# Additional proxy settings
proxy_max_temp_file_size 0;
client_max_body_size 10m;
proxy_connect_timeout 90;
proxy_buffer_size 4k;
}
The critical changes include:
- Using
$remote_user
instead of$http_authorization
forX-Forwarded-User
- Properly forwarding the
Authorization
header - Maintaining all essential proxy headers for complete request tracking
For Jenkins to properly interpret these headers, you may need to configure the security realm. In config.xml
:
<securityRealm class="hudson.security.HudsonPrivateSecurityRealm">
<disableSignup>true</disableSignup>
<enableCaptcha>false</enableCaptcha>
</securityRealm>
<useSecurity>true</useSecurity>
If authentication still fails:
- Verify Nginx can read the .htpasswd file:
sudo nginx -t
- Check header presence in Jenkins logs
- Test with curl:
curl -I -u user:pass http://your-proxy
For Jenkins WebSocket connections, add these headers:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
When using Nginx as a reverse proxy for Jenkins with HTTP Basic Authentication, one common requirement is to pass the authenticated username to the backend Jenkins instance. While the authentication works at the Nginx level, Jenkins often needs to know which user is making the request for proper authorization and auditing.
The existing Nginx configuration handles basic authentication and proxy setup correctly:
location / {
auth_basic "Restricted";
auth_basic_user_file /usr/share/nginx/.htpasswd;
sendfile off;
proxy_pass http://192.168.178.102:8080;
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-User $http_authorization;
proxy_max_temp_file_size 0;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
The configuration attempts to forward the Authorization header using X-Forwarded-User $http_authorization
, but this has two issues:
- The raw Authorization header contains the Base64-encoded credentials, not just the username
- Jenkins might not automatically interpret the X-Forwarded-User header
We can improve this by extracting just the username from the Authorization header:
location / {
auth_basic "Restricted";
auth_basic_user_file /usr/share/nginx/.htpasswd;
# Map the Authorization header to extract just the username
set $auth_user "";
if ($http_authorization ~ "^Basic +([A-Za-z0-9+/=]+)") {
set $auth_b64 $1;
set $auth_user "";
# Decode Base64 and extract username (first part before colon)
auth_ldap_user_password=$(echo -n "$auth_b64" | base64 -d);
set $auth_user $1;
if ($auth_ldap_user_password ~ "^([^:]+):") {
set $auth_user $1;
}
}
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Forwarded-User $auth_user;
proxy_set_header X-Forwarded-Prefix /;
# Other proxy settings remain the same
proxy_pass http://192.168.178.102:8080;
# ... rest of proxy configuration
}
On the Jenkins side, you'll need to configure the security realm to trust the forwarded user header:
- Go to Jenkins > Manage Jenkins > Configure Global Security
- Under "Security Realm", select "Delegate to servlet container"
- Under "Authorization", select your preferred method (often "Matrix-based security")
- Install and configure the "Reverse Proxy Auth Plugin" if needed
For more complex scenarios, you can use Nginx with Lua to properly handle the authentication:
location / {
access_by_lua_block {
local auth = ngx.var.http_authorization
if auth then
local _, _, b64 = string.find(auth, "^Basic%s+(.+)$")
if b64 then
local decoded = ngx.decode_base64(b64)
local user = string.match(decoded, "^([^:]+)")
ngx.req.set_header("X-Forwarded-User", user)
end
end
}
proxy_pass http://jenkins_backend;
proxy_set_header X-Forwarded-User $http_x_forwarded_user;
}
When implementing this solution, consider these security aspects:
- Ensure your Nginx-Jenkins communication is over HTTPS or internal network
- Validate the X-Forwarded-User header in Jenkins if exposed to external networks
- Consider rate limiting to prevent brute force attacks
- Regularly audit your .htpasswd file for outdated credentials