Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Session expired and XSRF errors when deploying Jira with two replicas on AKS with ILB

MD NISHAD HUSSAIN
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
August 13, 2025

Hello Atlassian Support,

I have deployed Jira Data Center on Azure Kubernetes Service (AKS) using an Internal Load Balancer (ILB) and mapped it with a DNS entry.

When I deploy Jira with only one replica, everything works fine — I can log in to the system admin page and navigate to all settings without any issues.

However, when I deploy Jira with two replicas, I face persistent issues where the system throws session expired errors and shows XSRF token validation errors on almost every page.

This makes Jira unusable in a multi-replica deployment scenario.

I am sharing our NGINX site configuration and Jira server.xml file for review to help troubleshoot the session expired / XSRF token issue when Jira is deployed with two replicas.

Please note: These files have been sanitized to remove sensitive information. The following placeholders have been used:

<JIRA_SERVER_FQDN> → Actual Jira server DNS name

<JIRA_BACKEND_IP> → Internal IP of Jira backend service in AKS

<CERTIFICATE_FILE> → SSL certificate file name/path

<PRIVATE_KEY_FILE> → SSL private key file name/path

The file structure, directives, and settings are otherwise unchanged to ensure accurate troubleshooting.

Let me know if you need any more details, the original (secure) values can be provided privately if absolutely necessary.

Below are the file config :

nginx.conf / Jira site config (sanitized)

server {
listen 443 ssl;
server_name <JIRA_SERVER_FQDN>; # Masked hostname

# SSL configuration
ssl_certificate /etc/nginx/ssl/<CERTIFICATE_FILE>;
ssl_certificate_key /etc/nginx/ssl/<PRIVATE_KEY_FILE>;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:...'; # Truncated for brevity
ssl_prefer_server_ciphers on;

# Security headers (Optional but recommended)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "1; mode=block";

client_max_body_size 100M;

location / {
# app_protect_enable on;
proxy_pass http://<JIRA_BACKEND_IP>:8080; # Masked internal IP
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-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
}

server {
listen 80;
server_name <JIRA_SERVER_FQDN>; # Masked hostname
return 301 https://$host$request_uri;
}


Screenshot 2025-08-13 224938.pngScreenshot 2025-08-13 224831.pngserver.xml (sanitized)

<?xml version="1.0" encoding="utf-8"?>

<Server port="8005" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/>
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>

<Service name="Catalina">

<Connector port="8080"
maxThreads="100"
minSpareThreads="10"
connectionTimeout="20000"
enableLookups="false"
protocol="HTTP/1.1"
redirectPort="8443"
acceptCount="10"
secure="true"
scheme="https"
proxyName="<JIRA_SERVER_FQDN>" <!-- Masked hostname -->
proxyPort="443"
relaxedPathChars="[]|"
relaxedQueryChars="[]|{}^`\&quot;&lt;&gt;"
bindOnInit="false"
maxHttpHeaderSize="8192"
useBodyEncodingForURI="true"
disableUploadTimeout="true" />

<Engine name="Catalina" defaultHost="localhost">

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

<Context path="" docBase="${catalina.home}/atlassian-jira"
reloadable="false" useHttpOnly="true">
<Resource name="UserTransaction"
auth="Container"
type="javax.transaction.UserTransaction"
factory="org.objectweb.jotm.UserTransactionFactory"
jotm.timeout="60"/>
<Manager pathname=""/>
<JarScanner scanManifest="false"/>
<Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="120" />
</Context>

</Host>

<Valve className="org.apache.catalina.valves.AccessLogValve"
pattern="%a %{jira.request.id}r %{jira.request.username}r %t &quot;%m %U%q %H&quot; %s %b %D &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot; &quot;%{jira.request.assession.id}r&quot;"
requestAttributesEnabled="false"
maxDays="-1"/>

</Engine>

</Service>

</Server>

I have also attached the screenshot for your reference.

Could you please help me resolve this issue?

Thank you for your help.

1 answer

0 votes
Yevhen
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
August 13, 2025

You need to configure session affinity aka sticky sessions on your LoadBalancer which is pre-requisite of running datacenter apps (not only on kube)

MD NISHAD HUSSAIN
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
August 13, 2025

Thanks for confirming that sticky sessions are required.

Could you please guide me on the correct configuration for our setup?

We are running Jira Data Center on AKS with an Internal Load Balancer in front of NGINX.

Specifically:

Should sticky sessions be configured on the Azure ILB, in NGINX, or both?

What’s the Jira-recommended NGINX config snippet for handling JSESSIONID-based sticky sessions?

Are there any Jira application settings or cluster.properties changes needed to complement this?

This will help ensure we configure it exactly as per best practices for Jira on Kubernetes.

Yevhen
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
August 13, 2025

If you have nginx ingress controller, and you dpeloy using official Helm charts, then it should work out of the box.

MD NISHAD HUSSAIN
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
August 14, 2025

Thanks for your response @Yevhen 
Just to clarify our architecture: we are not using the Kubernetes NGINX Ingress Controller. Instead, our setup consists of:

  • An Azure Internal Load Balancer (Layer 4) in front of an external NGINX reverse proxy
  • Two Jira pods (multi-replica) behind Kubernetes services (internal + ILB)

Given the ILB operates at Layer 4 (TCP) and does not terminate HTTP, how do you recommend we configure session affinity (sticky sessions) in this architecture?

Specifically:

Should we rely on Azure ILB’s source IP affinity at Layer 4, or configure cookie-based sticky sessions at the external NGINX reverse proxy instead?

If NGINX is the appropriate layer, could you please provide Jira Data Center’s recommended NGINX reverse proxy configuration for sticky sessions?

We want to ensure our setup meets Jira’s official best practices for Data Center deployments in Kubernetes with an Azure Internal Load Balancer (ILB).

Yevhen
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
August 14, 2025

I'd say, Azure LB needs to use sticky cookies and send requests to the same backend Jira pods.

MD NISHAD HUSSAIN
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
August 14, 2025

Regarding your suggestion that the Azure Load Balancer should use sticky cookies:

In our environment, we are using an Azure Internal Load Balancer (ILB), which operates at Layer 4 (TCP). Based on Microsoft’s documentation, the ILB:

Supports session persistence (session affinity/sticky sessions) only via client source IP.

Does not support cookie-based session affinity, because it cannot inspect HTTP traffic or cookies.

Therefore, in our architecture:

IP-based stickiness is handled at the ILB layer (ensuring a given client IP is sent to the same NGINX reverse proxy instance).

Cookie-based stickiness (required for Jira’s JSESSIONID sessions) will be configured at the NGINX reverse proxy level, which operates at Layer 7 and can read HTTP cookies.

If cookie-based stickiness at the load balancer level was required, we would need a Layer 7 load balancer such as Azure Application Gateway — but our setup uses ILB + NGINX.

Could you please confirm that implementing JSESSIONID-based sticky sessions in NGINX is aligned with Jira Data Center best practices?

Thanks.

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
SERVER
PRODUCT PLAN
STANDARD
TAGS
AUG Leaders

Atlassian Community Events