Skip to end of metadata
Go to start of metadata

Running Jenkins from a subdomain (like http://jenkins.domain.tld)

Due to people are often struggling getting Jenkins to work behind an NGINX reverse proxy setup I've decided to share my currently running config.

Hope this could be of any help to someone.

server {
    listen 80;
    server_name jenkins.domain.tld;
    return 301 https://$host$request_uri;
}

server {

    listen 80;
    server_name jenkins.domain.tld;
    
    location / {

      proxy_set_header        Host $host:$server_port;
      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;

      # Fix the "It appears that your reverse proxy set up is broken" error.
      proxy_pass          http://127.0.0.1:8080;
      proxy_read_timeout  90;

      proxy_redirect      http://127.0.0.1:8080 https://jenkins.domain.tld;
 
	  # Required for new HTTP-based CLI
      proxy_http_version 1.1;
	  proxy_request_buffering off;
      # workaround for https://issues.jenkins-ci.org/browse/JENKINS-45651
      add_header 'X-SSH-Endpoint' 'jenkins.domain.tld:50022' always;




    }
  }

Running from a subdomain with SSL

upstream jenkins {
  server 127.0.0.1:8080 fail_timeout=0;
}

server {
  listen 80;
  server_name jenkins.domain.tld;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  server_name jenkins.domain.tld;

  ssl_certificate /etc/nginx/ssl/server.crt;
  ssl_certificate_key /etc/nginx/ssl/server.key;

  location / {
    proxy_set_header        Host $host:$server_port;
    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_redirect http:// https://;
    proxy_pass              http://jenkins;
	# Required for new HTTP-based CLI
    proxy_http_version 1.1;
	proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # workaround for https://issues.jenkins-ci.org/browse/JENKINS-45651
    add_header 'X-SSH-Endpoint' 'jenkins.domain.tld:50022' always;
  }
}

Running Jenkins from a folder with TLS encryption (like https://domain.tld/jenkins/)

However, you may want to access Jenkins from a folder on your main web server. This allows you to use the same TLS/SSL certificate as for your top level domain, whereas a sub-domain like jenkins.domain.tld may require a new TLS/SSL certificate (that seems to depend on your certificate provider). You can configure nginx as a reverse proxy to translate requests coming in from the WAN as https://domain.tld/jenkins/ to LAN requests to http://10.0.0.100:8080/jenkins.

Note that this example uses the same settings as currently listed on the wiki article at https://wiki.jenkins-ci.org/display/JENKINS/Running+Hudson+behind+Nginx, but with different values for the proxy_pass and proxy_redirect directives.

server {


    # All your server and TLS/certificate settings are up here somewhere
    [...]


    # Nginx configuration specific to Jenkins
    # Note that regex takes precedence, so use of "^~" ensures earlier evaluation
    location ^~ /jenkins/ {

        # Convert inbound WAN requests for https://domain.tld/jenkins/ to 
        # local network requests for http://10.0.0.100:8080/jenkins/
        proxy_pass http://10.0.0.100:8080/jenkins/;
        
	# Rewrite HTTPS requests from WAN to HTTP requests on LAN
        proxy_redirect http:// https://;

        # The following settings from https://wiki.jenkins-ci.org/display/JENKINS/Running+Hudson+behind+Nginx
        sendfile off;

        proxy_set_header   Host             $host:$server_port;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        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_temp_file_write_size 64k;
 
	    # Required for new HTTP-based CLI
        proxy_http_version 1.1;
	    proxy_request_buffering off;
        proxy_buffering off; # Required for HTTP-based CLI to work over SSL
  }

In addition, you must ensure that Jenkins is configured to listen for requests to the /jenkins/ folder (e.g. http://10.0.0.100:8080/jenkins/ instead of http://10.0.0.100:8080/). Do that by adding the parameter --prefix=/jenkins to the Jenkins default start-up configuration file. On my system (Ubuntu 12.04 LTS) the configuration file is /etc/default/jenkins. For example, here's the full JENKINS_ARG parameter list (the only part I added was --prefix=/jenkins):

JENKINS_ARGS="--webroot=/var/cache/jenkins/war --httpPort=$HTTP_PORT --ajp13Port=$AJP_PORT --prefix=/jenkins"

Once configured, you should also set the URL used by the Jenkins UI at Jenkins > Manage Jenkins > Jenkins Location > Jenkins URL to something like:  "https://domain.tld/jenkins/. 

Being compatible with CSRF protection

This section applies to Jenkins 1.x only. Jenkins 2 uses an nginx-compatible crumb header name by default.

If you enable "Prevent Cross Site Request Forgery exploits" in the Configure Global Security page, you'll need special care for Jenkins to work behind a proxy. You'll need to enable the Enable proxy compatibility checkbox. And you'll need to add to your nginx configuration the following fragment:

http {
  ignore_invalid_headers off;
}

This is required because Jenkins uses a custom HTTP header named .crumb. See bug https://issues.jenkins-ci.org/browse/JENKINS-12875 for details.

  • No labels

12 Comments

  1. The first suggestion doesn't do anything about the warning: "It appears that your reverse proxy set up is broken." Any idea on how to fix that?

    1. +1 same problem. 

      1. I had the same problem, too. Until I noticed that Manage Jenkins->Jenkins URL was still pointing to the :8080 address. Fixing that made the reverse proxy warning go away. Do you have the same issue?

  2. Can someone confirm that working location directive is:

    location ~* ^/
    
  3. To get rid of "It appears that your reverse proxy set up is broken." I experimented with

    set $ref $http_referer;
    if ($ref ~* '^https?://jenkins.domain.tld(/.*)$') {
    set $ref http://127.0.0.1:8080$1;
    }
    proxy_set_header Referer $ref;
    

    and got it solved but then I found that more proper solution might be;

    proxy_set_header X-Forwarded-Host $host;
    
  4. How can I configure NGINX ( NGINX was installed with GitLab ) to proxy pass *http://127.0.0.1/jenkins* to *http://127.0.0.1:8080*?

    I have no prefix configured for jenkins.

    The config below does not work.  

    A request for  http://127.0.0.1/jenkins will go to http://127.0.0.1

    A request for  http://127.0.0.1/xyz or anything else that does not exist also go to http://127.0.0.1

    # File: nginx-jenkins.conf
    # Step 1 - Add following line to gitlab.rb
    #    nginx['custom_nginx_config'] = "include /var/opt/gitlab/nginx/conf/nginx-jenkins.conf;"
    #
    # Step2 - Run
    #    sudo gitlab-ctl reconfigure 
    # How can I configure NGINX to redirect
    # http://172.17.144.123/jenkins 
    #   to 
    # http://172.17.144.123:8081/jenkins 
    #
    
    server {
       listen 80;
       location /jenkins/ {
    
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_pass http://127.0.0.1:8081;
       }
    }
    

    Thanks in advance for any assistance,

    -Ed

    1. My problem appears to be the gitlab-http.conf for NGINX is pre-empting my nginx-jenkins.conf.

      The proxy_pass works if I comment-out the "#include gitlab-http.conf" statement.

      The gitlab-http.conf file is 150 lines.  I am not sure what to look for.

        include /var/opt/gitlab/nginx/conf/gitlab-http.conf;
        include /var/opt/gitlab/nginx/conf/nginx-jenkins.conf;
      }

      http {
      
       ....
      
        include /opt/gitlab/embedded/conf/mime.types;
      
        # Something in gitlab-http.conf prevents nginx-jenkins.conf proxy pass from working
        #include /var/opt/gitlab/nginx/conf/gitlab-http.conf;
      
        include /var/opt/gitlab/nginx/conf/nginx-jenkins.conf;
      
      }
      
  5. This seems to be covering the same content as the page at https://wiki.jenkins-ci.org/display/JENKINS/Running+Jenkins+behind+Nginx, except that page is more comprehensive as it handles serving static files directly through Nginx. It's probably a good idea to merge the two pages together.

  6. There should be instuctions for running jenkins on a URL like http://mydomain/someurl/jenkins.

    This does not work out of the box, as jenkins expects itself to run at /jenkins, or something similar.

     

    1. This worked for me.

      upstream jenkins {
        server 127.0.0.1:8080 fail_timeout=0;
      }
      server {

          # SSL configuration
          #
          # listen 443 ssl default_server;
          # listen [::]:443 ssl default_server;
          #
          # Note: You should disable gzip for SSL traffic.
          # See: https://bugs.debian.org/773332
          #
          # Read up on ssl_ciphers to ensure a secure configuration.
          # See: https://bugs.debian.org/765782
          #
          # Self signed certs generated by the ssl-cert package
          # Don't use them in a production server!
          #
          # include snippets/snakeoil.conf;

          root /var/www/html;

          # Add index.php to the list if you are using PHP
          index index.html index.htm index.nginx-debian.html;

          server_name x.x.com;

          location / {
              # First attempt to serve request as file, then
              # as directory, then fall back to displaying a 404.
              try_files $uri $uri/ =404;
          }
      location /jenkins {
      proxy_set_header        Host $host:$server_port;
          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_redirect http:// https://;
          proxy_pass              http://jenkins;
          # Required for new HTTP-based CLI
          proxy_http_version 1.1;
          proxy_request_buffering off;
          proxy_buffering off; # Required for HTTP-based CLI to work over SSL
          # workaround for https://issues.jenkins-ci.org/browse/JENKINS-45651
          add_header 'X-SSH-Endpoint' 'x.x..com:50022' always;

       

      edit /etc/sysconfig/jenkins, change this line (last line) JENKINS_ARGS="" to JENKINS_ARGS="--prefix=/jenkins" (double hyphen)

      invoke sudo service jenkins restart


  7. I'm trying to trigger a webhook from Bitbucket after I push code changes. Each time I get an authorization 401 Header error:

    The BODY response is:

    <html>
    <head><title>401 Authorization Required</title></head>
    <body bgcolor="white">
    <center><h1>401 Authorization Required</h1></center>
    <hr><center>nginx/1.14.0</center>
    </body>
    </html>

    What do I need to do in my default.conf file to accept the internal request that Bitbucket webhook makes and execute my build in jenkins? 

    In additon, If I don't use NGINX reverse proxy my webhooks work perfectly, I'm struggling with this. Help me please.

     

    I'm working with Docker and Nginx and Jenkins services. This is my defult.conf file:

     

    server {
    listen 80;
    server_name localhost;

    #charset koi8-r;
    #access_log /var/log/nginx/host.access.log main;

    location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    }

    location /jenkins {

    auth_basic $host;
    auth_basic_user_file /etc/apache2/.htpasswd;


    proxy_set_header Host $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-Host $host:$server_port;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Authorization "";

    proxy_max_temp_file_size 0;

    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;

    # Set maximum upload size
    client_max_body_size 10m;
    client_body_buffer_size 128k;

    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_request_buffering off;

    # Sendfile provides no advantages when operating as a proxy
    sendfile off;
    }

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root /usr/share/nginx/html;
    }
    }
    1. I've just realized that the problem is related with the auth_basic_user_file


      auth_basic_user_file /etc/apache2/.htpasswd;

      It is indeed not possible to pass the username and password via query parameters in standard HTTP auth. Instead, you use a special URL format, like this: http://nginx_username:nginx_password@your_server.com/jenkins/bitbucket-hook/ -- this sends the credentials in the standard HTTP "Authorization" header.
      This should alse be documented