Reverse proxy - Apache

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 Apache, 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.

Make sure that you change the Jenkins httpListenAddress from its default of 0.0.0.0 to 127.0.0.1 or any Apache-level restrictions can be easily bypassed by accessing the Jenkins port directly.

There are several different alternatives to configure Jenkins with Apache. Choose the technique that best meets your needs:

This 6 minute tutorial from Darin Pope configures Apache httpd on Alma Linux as a reverse proxy with mod_proxy.

Configure Apache HTTP server as a reverse proxy

mod_proxy

mod_proxy works by making Apache perform "reverse proxy" — when a request arrives for certain URLs, Apache becomes a proxy and forwards that request to Jenkins, then forwards the response from Jenkins back to the client.

The following Apache modules must be installed :

a2enmod proxy
a2enmod proxy_http
a2enmod headers
# Required for websocket
a2enmod proxy_wstunnel
a2enmod rewrite

A typical set up for mod_proxy would look like this:

ProxyPass         /jenkins  http://localhost:8081/jenkins nocanon
ProxyPassReverse  /jenkins  http://localhost:8081/jenkins
ProxyRequests     Off
AllowEncodedSlashes NoDecode

# Required for Jenkins websocket agents
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/jenkins/?(.*) "ws://localhost:8081/jenkins/$1" [P,L]

# Local reverse proxy authorization override
# Most unix distribution deny proxy by default
# See /etc/apache2/mods-enabled/proxy.conf in Ubuntu
<Proxy http://localhost:8081/jenkins*>
  Order deny,allow
  Allow from all
</Proxy>

This assumes that you run Jenkins on port 8081.

Context path provides more details on reverse proxy requires for the Jenkins context path.

When running on a dedicated server and you are using / as context, make sure you add a slash at the end of all URLs in proxy params in apache. Otherwise you might run into proxy errors. So

ProxyPass / http://localhost:8080/ nocanon

instead of

ProxyPass / http://localhost:8080 nocanon     # wont work

Note that this does not apply to the ProxyPassMatch directive, which behaves differently than ProxyPass. Below is an example of ProxyPassMatch to proxy all URLs other than /.well-known (a URL required by letsencrypt):

ProxyPassMatch  ^/(?\!.well-known)  http://localhost:8080 nocanon

The ProxyRequests Off prevents Apache from functioning as a forward proxy server (except for ProxyPass), it is advised to include it unless the server should function as a proxy.

Both the nocanon option to ProxyPass, and AllowEncodedSlashes NoDecode, are required for certain Jenkins features to work.

If you are running Apache on a Security-Enhanced Linux (SE-Linux) machine it is essential to make SE-Linux do the right thing by issuing as root

setsebool -P httpd_can_network_connect true

If this is not issued Apache will not be allowed to forward proxy requests to Jenkins and only an error message will be displayed.

Because Jenkins already compress its output, you can not use the normal proxy-html filter to modify urls:

SetOutputFilter proxy-html

Instead you can use the following:

SetOutputFilter INFLATE;proxy-html;DEFLATE
ProxyHTMLURLMap http://your_server:8080/jenkins /jenkins

But since Jenkins seems to be well behaved it’s even better to just not use SetOutputFilter and ProxyHTMLURLMap.

If there are problems with Jenkins sometimes servicing random garbage pages, then the following may help:

SetEnv proxy-nokeepalive 1

Some plug-ins determine URLs from client requests from Host header, so if you experience some problems with wrong URLs, you can try to switch on ProxyPreserveHost directive, which is switched off by default:

ProxyPreserveHost On

mod_proxy with HTTPS

You can add an additional ProxyPassReverse directive to redirect non-SSL URLs generated by Jenkins to the SSL side. Assuming that your webserver is your.host.com, placing the following within the SSL virtual host definition will do the trick:

ProxyRequests     Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode

<Proxy http://localhost:8081/jenkins*>
  Order deny,allow
  Allow from all
</Proxy>

ProxyPass         /jenkins  http://localhost:8081/jenkins nocanon
ProxyPassReverse  /jenkins  http://localhost:8081/jenkins
ProxyPassReverse  /jenkins  http://your.host.com/jenkins

Yet another option is to rewrite the Location headers that contain non-ssl URL’s generated by Jenkins. If you want to access Jenkins from https://www.example.com/jenkins, placing the following within the SSL virtual host definition also works:

ProxyRequests     Off
ProxyPreserveHost On
ProxyPass /jenkins/ http://localhost:8081/jenkins/ nocanon
AllowEncodedSlashes NoDecode

<Location /jenkins/>
  ProxyPassReverse /
  Order deny,allow
  Allow from all
</Location>

Header edit Location ^http://www.example.com/jenkins/ https://www.example.com/jenkins/

But it may also work fine to just use simple forwarding as above (the first HTTPS snippet), and add

RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"

in the HTTPS site configuration, as the Docker demo (below) does. (X-Forwarded-Port is not interpreted by Jenkins prior to JENKINS-23294 so it may also be desirable to configure the servlet container to specify the originating port.)

NameVirtualHost *:80
NameVirtualHost *:443

<VirtualHost *:80>
    ServerAdmin  webmaster@localhost
    Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/cert.pem
    ServerAdmin  webmaster@localhost
    ProxyRequests     Off
    ProxyPreserveHost On
    AllowEncodedSlashes NoDecode
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>
    ProxyPass         /  http://localhost:8080/ nocanon
    ProxyPassReverse  /  http://localhost:8080/
    ProxyPassReverse  /  http://www.example.com/
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"

    # Required for Jenkins websocket agents
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/?(.*) "ws://localhost:8080/$1" [P,L]
</VirtualHost>

mod_rewrite

The Apache mod_rewrite module can be used to configure an Apache reverse proxy for Jenkins.

The following Apache modules must be installed :

a2enmod rewrite
a2enmod proxy
a2enmod proxy_http
# Required for Jenkins websocket agents
a2enmod proxy_wstunnel

A typical mod_rewrite configuration would look like this:

# Required for Jenkins websocket agents
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/jenkins/?(.*) "ws://localhost:8081/jenkins/$1" [P,L]

# Use last flag because no more rewrite can be applied after proxy pass
# NE makes sure slashes are not re-encoded.
# Apache does not re-encode spaces though, we ask Apache to encode it again with the B flag
# BNP tells apache to use %20 instead of + to re-encode the space
RewriteRule       ^/jenkins(.*)$  http://localhost:8081/jenkins$1 [P,L,NE,B=\,BNP]

ProxyPassReverse  /jenkins        http://localhost:8081/jenkins
ProxyRequests     Off

AllowEncodedSlashes NoDecode

# Local reverse proxy authorization override
# Most unix distribution deny proxy by default
# See /etc/apache2/mods-enabled/proxy.conf in Ubuntu
<Proxy http://localhost:8081/jenkins*>
  Order deny,allow
  Allow from all
</Proxy>

# If using HTTPS, add the following directives
# RequestHeader set X-Forwarded-Proto "https"
# RequestHeader set X-Forwarded-Port "443"

This assumes that you run Jenkins on port 8081. The context path of Jenkins must be the same between Apache and Jenkins. Jenkins can’t run on http://example.com:8081/ci and be reverse proxied at http://example.com/jenkins . Context path provides more details on reverse proxy requires for the Jenkins context path.

The ProxyRequests Off prevents Apache from functioning as a forward proxy server (except for ProxyPass), it is advised to include it unless the server should function as a proxy.

mod_proxy_unix_sockets

Apache can be configured to proxy requests to Jenkins over a Unix domain socket instead of a TCP port. This approach enhances security by eliminating network exposure of Jenkins, and is particularly useful when Jenkins and Apache run on the same host.

To avoid repetitive use of sudo in the commands below, switch to a root shell first by running:

sudo -i
bash

Debian-Based Systems

# Enable the modules using `a2enmod`
a2enmod proxy
a2enmod proxy_http

# Restart Apache to apply changes
systemctl restart httpd

# Allow HTTP and HTTPS traffic through the firewall
ufw allow http
ufw allow https
ufw reload
ufw status

# Edit the Jenkins systemd service to disable TCP and enable a Unix socket
systemctl edit jenkins

# Add the following override
[Service]
ExecStart=
# Set the new ExecStart with Unix socket
ExecStart=/usr/bin/jenkins --pluginroot=/var/cache/jenkins/plugins --httpPort=-1 --httpUnixDomainPath=/var/run/jenkins/jenkins.socket

# Reload and restart Jenkins
systemctl daemon-reload
systemctl restart jenkins

# Verify the socket exists
ls -l /var/run/jenkins/jenkins.socket

# Ensure Apache can access the socket
sudo chown jenkins:jenkins /var/run/jenkins/jenkins.socket
sudo chmod 700 /var/run/jenkins/jenkins.socket

# Create a new virtual host to proxy requests to the Unix socket
nano /etc/apache2/sites-available/jenkins.conf

# Add the following
<VirtualHost *:80>
    ServerName localhost

    # Proxy to Unix domain socket
    ProxyPass / unix:/var/run/jenkins/jenkins.socket|http://localhost/
    ProxyPassReverse / unix:/var/run/jenkins/jenkins.socket|http://localhost/

    # Preserve host header
    ProxyPreserveHost On

    # Logging
    ErrorLog ${APACHE_LOG_DIR}/jenkins_error.log
    CustomLog ${APACHE_LOG_DIR}/jenkins_access.log combined
</VirtualHost>

# Enable the site and restart Apache
a2ensite jenkins.conf
systemctl restart apache2

# If Apache needs to share socket access with Jenkins, update its user/group
nano /etc/apache2/envvars
# Modify:
export APACHE_RUN_USER=jenkins
export APACHE_RUN_GROUP=jenkins

# Restart Apache
systemctl restart apache2
bash

RHEL-Based Systems

The following video from Darin Pope provides a 16 minute tutorial on configuring Unix domain sockets with Apache HTTP Server and Jenkins running on AlmaLinux.

Configure Using Unix Domain Sockets With Apache HTTP Server and Jenkins
# Ensure the modules are loaded by editing the module configuration
dnf install httpd -y  # Install Apache if not already present

# Allow HTTP and HTTPS traffic through the firewall
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --zone=public --add-service=https --permanent
firewall-cmd --reload

# Edit the Jenkins systemd service to disable TCP and enable a Unix socket
systemctl edit jenkins

# Add the following override
[Service]
ExecStart=/usr/lib/jenkins/jenkins --pluginroot=/var/cache/jenkins/plugins --httpPort=-1 --httpUnixDomainPath=/var/run/jenkins/jenkins.socket

# Reload and restart Jenkins
systemctl daemon-reload
systemctl restart jenkins

# Verify the socket exists
ls -l /var/run/jenkins/jenkins.socket

# Ensure Apache can access the socket
sudo chown jenkins:jenkins /var/run/jenkins
sudo chmod 700 /var/run/jenkins
systemctl restart jenkins

# Create a new virtual host to proxy requests to the Unix socket
mv welcome.conf welcome.old
vi /etc/httpd/conf.d/jenkins.conf

# Add the following
User jenkins
Group jenkins
ProxyPass / unix:/var/run/jenkins/jenkins.socket|http://localhost/ nocanon
ProxyPassReverse / unix:/var/run/jenkins/jenkins.socket|http://localhost/

# To allow SE linux to traffic allow to the socket
chcon -t httpd_sys_rw_content_t /var/run/jenkins/jenkins.socket

# Restart Apache
systemctl restart apache2
bash

Once you have finished your configuration, access http://localhost/ in a browser. If you encounter any issues, check the logs for any errors with the corresponding commands:

tail -f /var/log/apache2/jenkins_error.log  #Debian
tail -f /var/log/apache2/jenkins_access.log #Debian
bash
tail -f /var/log/httpd/jenkins_error.log  #RHEL
tail -f /var/log/httpd/jenkins_access.log #RHEL
bash

Context path

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.

Proxying CLI commands with the HTTP(S) transport

Using the plain CLI protocol with the HTTP(S) transport to access Jenkins through an Apache reverse proxy does not work. See JENKINS-47279 - Full-duplex HTTP(S) transport with plain CLI protocol does not work with Apache reverse proxy for more details. As a workaround, you can use the CLI over SSH.

If using Apache check that nocanon is set on ProxyPass and that AllowEncodedSlashes is set.

AllowEncodedSlashes is not inherited in Apache configs, so this directive must be placed inside the VirtualHost definition.



Was this page helpful?

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.