Using NGINX as an Atlassian JIRA Reverse Proxy

I use JIRA in a cloud infrastructure where it’s obviously desirable to serve the contents over SSL, therefore I set up an NGINX as a JIRA reverse proxy for unencrypted requests to the JIRA backend service and handle the SSL on the front end with Let’s Encrypt. We need to let JIRA know that we are proxying it over HTTPS however by setting some values in server.xml first.

Notice that my Let’s Encrypt SSL certificates are in the /etc/letsencrypt/live/jira.doublesharp.com directory, but yours will be specific to the hostname you create them for. The certs are created via the letsencrypt command and use Nginx to process the validation request. Once created the generated PEM files can be used in your Nginx config. Note that you will need to comment out this line in the SSL config if they don’t yet exist, start Nginx to create the certs, uncomment the lines to enable SSL, and then restart Nginx once again (whew!).

JIRA Reverse Proxy Configuration

Configure JIRA to add proxyName, proxyPort, scheme, and secure parameters to the Tomcat Connector in server.xml.

<Connector port="8081" 
           maxThreads="150" 
           minSpareThreads="25" 
           connectionTimeout="20000" 
           enableLookups="false" 
           maxHttpHeaderSize="8192" 
           protocol="HTTP/1.1" 
           useBodyEncodingForURI="true" 
           redirectPort="8443" 
           acceptCount="100" 
           disableUploadTimeout="true" 
           bindOnInit="false" 
                    
           proxyName="jira.doublesharp.com" 
           proxyPort="443" 
           scheme="https" 
           secure="true" 
/>

Don’t forget to copy the database driver to $JIRA_INSTALL/lib.

Nginx Reverse Proxy Configuration

Note use of “jira.doublesharp.com” in config and change as needed. This configuration uses a subdomain specific certificate from Let’s Encrypt, but you could also use a Wildcard Certificate for your JIRA reverse proxy setup as well which can help to consolidate your key generation.

# Upstream JIRA server on port 8081. Use 127.0.0.1 and not localhost to force IPv4.
upstream jira {
  server       127.0.0.1:8081 fail_timeout=0;
}

# listen on HTTP2/SSL
server {
  listen       443 ssl http2;
  server_name  jira.doublesharp.com;

  # ssl certs from letsencrypt
  ssl_certificate /etc/letsencrypt/live/jira.doublesharp.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/jira.doublesharp.com/privkey.pem;

  location / {
    # allow uploads up to 10MB
    client_max_body_size 10m;
    # set proxy headers for cloudflare/jira
    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;
    # hand the request off to jira on non-ssl
    proxy_pass        http://jira;
  }
}

# redirect HTTP and handle let's encrypt requests
server {
  listen       80;
  server_name  jira.doublesharp.com;
  root         /var/lib/jira;
  
  # handle letsencrypt domain validation
  location ~ /.well-known {
    allow all;
  }

  # send everything else to HTTPS
  location / {
    return 302 https://jira.doublesharp.com;
  }
}

You may also like...

13 Responses

  1. Me says:

    You can run Jira without nginx under port 1080 as a normal user.

    • User Avatar Justin Silver says:

      Yep – you can actually run it on *any* high port (above 1024) as a non-root user. I wanted to use standard web ports for my setup and prefer to put everything behind a reverse proxy regardless.

  2. Vinícius Ferrão says:

    I’m having this issue:

    com.sun.jersey.spi.container.servlet.WebComponent.filterFormParameters A servlet request, to the URI https://jira.versatushpc.com.br/rest/activity-stream/1.0/preferences?_=1558562492226, contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using @FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.

    It appears to be certificate related, since on the dashboard the following message appears: gadget.common.error.500

    I’ve read something about adding the certificate to the Java Keystore, but it does not worked as expected.

  3. Ryan says:

    Does the Nginx Reverse Proxy Configuration need to be a special name for the document? Where would one place a Nginx Reverse Proxy Configuration?

    Does this require apache to be installed?

    • User Avatar Justin Silver says:

      The configuration needs to be done for both Nginx and JIRA. As the title implies this is a setup guide for Nginx, not Apache. Good luck!

  4. Kai Reichart says:

    Hi, thanks for the great article, you literally saved me hours of time!

    If anybody gets Error 502 Bad Gateway and your logs say “Permission denied…”, this worked for me:

    $ sudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M mynginx
    $ sudo semodule -i mynginx.pp
    

    Source: https://confluence.atlassian.com/bitbucketserverkb/13-permission-denied-while-connecting-to-upstream-while-configuring-ngnix-803374014.html

  5. Fatz says:

    Ran into an issue with attachments being limited to the default configured value for client max body size, which likely varies depending on your distribution.

    Adding the following line to the server block listening on 443 corrected the issue:

    client_max_body_size 20M;

    Hope this helps someone at least as much as this guide helped me.

    • User Avatar Justin Silver says:

      This is a good tip for proxying in general if you need to handle file uploads – the default is often pretty low for security. I’ve updated the post, thanks!

  6. Tim says:

    omfg this saved me man.. days of messing with this (I’m no server guy). Thank you soooo much.

  7. ed says:

    Me again! I dont understand your root location, what is the web serving looking for?

    root /var/lib/jira;

    Jira is installed in /opt/atlassian/jira for me but wouldnt it need to find a java file or something?

    • User Avatar Justin Silver says:

      That is the where I have Jira installed on my system, that tells Nginx where to find the static files so that it doesn’t go through the Jira process.

  8. ed says:

    Hi, looks interesting. Could you explain this: proxy_pass http://jira;
    Elsewhere I have seen http://localhost or http://127.0.0.1

    • User Avatar Justin Silver says:

      That is the upstream jira definition at the top of the config. You could specify multiple backend servers with weighting, etc here.

Leave a Reply

Your email address will not be published. Required fields are marked *