In situations where you have existing web sites on your server, you may find it useful to run Jenkins (or the servlet container that Jenkins runs in) behind Nginx, so that you can bind Jenkins to the part of a bigger website that you may have. This section discusses some of the approaches for doing this.
When a request arrives for certain URLs, Nginx becomes a proxy and forwards that request to Jenkins, then it forwards the response back to the client.
This 9 minute video tutorial from Darin Pope configures Nginx as a reverse proxy.
The Nginx configuration fragment below provides an example Nginx reverse proxy configuration. It assumes the Jenkins controller and the Nginx reverse proxy are running on the same computer.
upstream jenkins {
keepalive 32; # keepalive connections
server 127.0.0.1:8080; # jenkins ip and port
}
# Required for Jenkins websocket agents and HTTP keepalive support.
# Setting '' to '' clears the Connection header for non-WebSocket traffic,
# allowing upstream keepalive connections (e.g., keepalive 32) to function.
# References:
# - https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive
# - https://nginx.org/en/docs/http/websocket.html
map $http_upgrade $connection_upgrade {
default upgrade;
'' '';
}
server {
listen 80; # Listen on port 80 for IPv4 requests
server_name jenkins.example.com; # replace 'jenkins.example.com' with your server domain name
# this is the jenkins web root directory
# (mentioned in the output of "systemctl cat jenkins")
root /var/run/jenkins/war/;
access_log /var/log/nginx/jenkins.access.log;
error_log /var/log/nginx/jenkins.error.log;
# pass through headers from Jenkins that Nginx considers invalid
ignore_invalid_headers off;
location ~ "^\/static\/[0-9a-fA-F]{8}\/(.*)$" {
# rewrite all static files into requests to the root
# E.g /static/12345678/css/something.css will become /css/something.css
rewrite "^\/static\/[0-9a-fA-F]{8}\/(.*)" /$1 last;
}
location /userContent {
# have nginx handle all the static requests to userContent folder
# note : This is the $JENKINS_HOME dir
root /var/lib/jenkins/;
if (!-f $request_filename){
# this file does not exist, might be a directory or a /**view** url
rewrite (.*) /$1 last;
break;
}
sendfile on;
}
location / {
sendfile off;
proxy_pass http://jenkins;
proxy_redirect default;
proxy_http_version 1.1;
# Required for Jenkins websocket agents
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
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-Proto $scheme;
proxy_max_temp_file_size 0;
#this is the maximum upload size
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_request_buffering off; # Required for HTTP CLI commands
}
}
This assumes that you run Jenkins on port 8080. Remember to create the folder /var/log/nginx/jenkins.
The $connection_upgrade map sets the Connection header to upgrade for WebSocket requests, while clearing the header (setting it to "") for non-WebSocket traffic.
Clearing the Connection header is required to preserve upstream HTTP keepalive connections (such as keepalive 32;), as documented in the NGINX upstream keepalive documentation and NGINX WebSocket proxying documentation.
|
Make sure you do not end the proxy_pass value with a slash, as it will cause problems like those described in this discussion.
The context path is the prefix of a URL path.
The Jenkins controller and the reverse proxy must use the same context path.
For example, if the Jenkins controller URL is https://www.example.com/jenkins/ then the --prefix=/jenkins argument must be included in the Jenkins controller command line arguments.
Set the context path when using the Linux packages by running systemctl edit jenkins and adding the following:
[Service]
Environment="JENKINS_PREFIX=/jenkins"
Set the context path on Windows controllers by including the --prefix command line argument in the jenkins.xml file in the installation directory.
Ensure that Jenkins is running at the context path where your reverse proxy is serving Jenkins. You will have the least pain if you keep to this principle.
The --prefix command line argument is not needed if the context path is empty.
For example, the URL https://jenkins.example.com/ has an empty context path.
If you are having problems with some paths (eg folders) with Blue Ocean, you may need to add the following snippet to your proxy configuration:
if ($request_uri ~* "/blue(/.*)") {
proxy_pass http://YOUR_SERVER_IP:YOUR_JENKINS_PORT/blue$1;
break;
}
To give Nginx permission to read Jenkins web root folder, add the nginx user to
the Jenkins group:
usermod -aG jenkins nginx
If the last command failed because the nginx user is not defined in the system,
then you can try adding the www-data user to the Jenkins group:
usermod -aG jenkins www-data
If you are experiencing timeouts when attempting to run long CLI
commands through a proxy in Jenkins, you can increase the
proxy_read_timeout setting as necessary.
Older versions of Jenkins may not respect the proxy_read_timeout setting.
If you are experiencing the following error when attempting to run long
CLI commands in Jenkins and Jenkins is running behind Nginx, it
is probably due to Nginx timing out the CLI connection.
You can increase the proxy_read_timeout setting as necessary so the command will
complete successfully.
WARNING: null
hudson.cli.DiagnosedStreamCorruptionException
Read back: 0x00 0x00 0x00 0x1e 0x07
'Started reverse-proxy-test #68'
0x00 0x00 0x00 0x01 0x07 0x0a
Read ahead:
Diagnosis problem:
java.io.IOException: Premature EOF
at sun.net.www.http.ChunkedInputStream.readAheadBlocking(ChunkedInputStream.java:565)
...
at hudson.cli.FlightRecorderInputStream.analyzeCrash(FlightRecorderInputStream.java:82)
at hudson.cli.PlainCLIProtocol$EitherSide$Reader.run(PlainCLIProtocol.java:153)
Caused by: java.io.IOException: Premature EOF
at sun.net.www.http.ChunkedInputStream.readAheadBlocking(ChunkedInputStream.java:565)
...
at java.io.DataInputStream.readInt(DataInputStream.java:387)
at hudson.cli.PlainCLIProtocol$EitherSide$Reader.run(PlainCLIProtocol.java:111)
Nginx can proxy requests to Jenkins over a Unix domain socket instead of a TCP port. This disables Jenkins' HTTP TCP listener and is useful when Jenkins and Nginx run on the same host. Other listeners, such as a separately configured HTTPS or inbound-agent TCP listener, remain enabled and must be configured separately.
This section applies to Jenkins Linux package installations managed by systemd, which provide the JENKINS_UNIX_DOMAIN_PATH setting and the /run/jenkins runtime directory.
Other installation types can enable the same feature by passing --httpPort=-1 --httpUnixDomainPath=<path> to Jenkins at startup.
|
Edit the Jenkins systemd service:
systemctl edit jenkins
Add the following override to disable the TCP listener and enable the Unix socket:
[Service]
Environment="JENKINS_PORT=-1"
Environment="JENKINS_UNIX_DOMAIN_PATH=/run/jenkins/jenkins.socket"
UMask=0007
UMask=0007 (or UMask=0002) is required.
Jenkins creates the socket using the service umask, and with the usual default of 0022 the socket is not group-writable, so Nginx fails with Permission denied when connecting.
UMask applies to every file the Jenkins service creates, not only the socket.
0007 removes all access for other users and gives the Jenkins service group read and write access, so do not add Nginx to the jenkins group.
Use the dedicated group described in Permissions instead.
Use the same configuration as the TCP example above, changing only the server directive in the upstream block as follows:
upstream jenkins {
keepalive 32; # keepalive connections
server unix:/run/jenkins/jenkins.socket; # jenkins unix domain socket
}
The map, server, and location / blocks should stay unchanged.
If you do not grant Nginx read access to the Jenkins web root and JENKINS_HOME, remove the root directive, the entire /static/ location block (including its rewrite), and the /userContent location so that Jenkins serves those files through the socket.
The packages create /run/jenkins with mode 0770, owned by the jenkins user and group.
To give Nginx access to the socket without granting it access to Jenkins data, create a dedicated group that owns only this directory.
The setgid bit (2) makes the socket inherit the directory’s group.
groupadd --system jenkins-socket
echo 'D /run/jenkins 2750 jenkins jenkins-socket -' > /etc/tmpfiles.d/jenkins.conf
systemd-tmpfiles --create /etc/tmpfiles.d/jenkins.conf
systemctl restart jenkins
The file in /etc/tmpfiles.d/ overrides the one shipped with the package, so the setting persists across reboots.
systemd-tmpfiles --create also applies the new group and mode to the existing /run/jenkins directory, because a D line adjusts the mode and ownership of a directory that already exists.
Add the Nginx service user to the jenkins-socket group, then restart Nginx so the new group membership takes effect.
On Debian and Ubuntu, Nginx runs as www-data:
usermod -aG jenkins-socket www-data
systemctl restart nginx
On Red Hat Enterprise Linux and derivatives (such as AlmaLinux, Rocky Linux, and Fedora), Nginx runs as nginx:
usermod -aG jenkins-socket nginx
systemctl restart nginx
Verify that the directory and the socket have the expected group and permissions:
ls -ld /run/jenkins
# drwxr-s--- ... jenkins jenkins-socket ... /run/jenkins
ls -l /run/jenkins/jenkins.socket
# srwxrwx--- 1 jenkins jenkins-socket 0 ... /run/jenkins/jenkins.socket
On systems with SELinux in enforcing mode, the policy may block Nginx from connecting to the socket even when file permissions are correct.
If Nginx logs Permission denied with correct permissions, check for denials with ausearch -m avc -ts recent and create a local policy module with audit2allow if needed.
|
Please submit your feedback about this page through this quick form.
Alternatively, if you don't wish to complete the quick form, you can simply indicate if you found this page helpful?
See existing feedback here.