When Jenkins is authenticated by Keycloak (OIDC) and sits behind NGINX, “session timeout” is not a single knob. You can be forced to re-login because of Jenkins, Keycloak, or an SSO gateway layer (if you have one).
This post stays practical and conservative:
- Diagnose the timeout layer by configuration (fast inference)
- Apply minimal changes only (no unnecessary tuning)
- Target a clear homelab goal: idle ~6 hours
Goal (homelab example):
If Jenkins is left idle, I want to stay logged in for about 6 hours.
We’ll focus on configuration-based diagnosis and fixes. (We’re intentionally not doing “confirm by logs/events” in this version.)
Lab context (example)
- Jenkins:
https://jenkins.maksonlee.com - NGINX reverse proxy (TLS termination) → Jenkins on
127.0.0.1:8080 - Jenkins authentication: OpenID Connect Authentication plugin → Keycloak
- Keycloak realm:
maksonlee.com - Keycloak install path:
/opt/keycloak
What “session timeout” usually means
Most systems have two different timers:
- Idle timeout (no activity)
Expires after no meaningful interaction for a period.
- Max / absolute timeout (hard limit)
Expires after a fixed maximum lifetime even if you keep using the app.
This post targets idle timeouts, because “I left it alone and it logged me out” is the most common homelab complaint.
The 3 layers that can log you out
- Jenkins HTTP session (Jenkins’ own cookie/session, e.g.,
JSESSIONID) - NGINX/gateway (only if it enforces auth or owns an auth cookie)
- Keycloak SSO session (realm SSO idle/max + token lifetimes)
Your effective idle duration becomes the shortest idle timer among these layers.
Part 1 — Diagnose by configuration (fast inference)
- NGINX: confirm it’s reverse proxy only (not an auth gateway)
If NGINX only does proxy_pass, it typically does not own login state. It forwards cookies.
Check for auth gateway features or cookie rewriting
Run on the NGINX host:
sudo nginx -T 2>/dev/null | grep -nEi \
'auth_request|oauth2|oidc|openid|lua|proxy_cookie|proxy_cookie_path|proxy_cookie_domain'- If this returns nothing, NGINX is not acting as an auth gateway.
- If you see
auth_request/ oauth2-proxy / cookie rewriting, NGINX can be the timeout layer (out of scope for this simplified guide).
Check which cookie is set
curl -skI https://jenkins.maksonlee.com/ | grep -iE 'set-cookie|location|server'If you see only Jenkins cookies (e.g., JSESSIONID) and no extra gateway cookie, NGINX is unlikely to be the cause.
- Jenkins: confirm where to configure session timeout (systemd era)
On modern Debian/Ubuntu Jenkins packages, Jenkins runs as a systemd service and is typically controlled by the systemd unit and drop-in overrides (not /etc/default/jenkins at runtime).
Confirm Jenkins is managed by systemd
systemctl status jenkins --no-pager
systemctl cat jenkinsCheck whether JENKINS_OPTS is currently defined in systemd
sudo systemctl show jenkins -p Environment --no-pager \
| sed 's/^Environment=//' | tr ' ' '\n' | grep '^JENKINS_'If you do not see JENKINS_OPTS=..., that’s normal — we’ll add it.
Verify Jenkins supports --sessionTimeout
java -jar /usr/share/java/jenkins.war --help | grep -E 'sessionTimeout|sessionEviction'For our goal, we only change --sessionTimeout (idle timeout).
We avoid changing eviction/cleanup settings unless proven necessary.
- Keycloak: check realm SSO idle timeout (often the real limiting factor)
To read or update realm config with kcadm.sh, you must have an authenticated admin session. Tokens expire; if you see expired, just login again.
- Login (or re-login when expired)
Run on the Keycloak server:
export KC_URL="http://127.0.0.1:8080" # or https://keycloak.maksonlee.com
export KC_ADMIN_REALM="master"
export KC_ADMIN_USER="admin"
read -s -p "Keycloak admin password: " KC_ADMIN_PASS; echo
/opt/keycloak/bin/kcadm.sh config credentials \
--server "$KC_URL" \
--realm "$KC_ADMIN_REALM" \
--user "$KC_ADMIN_USER" \
--password "$KC_ADMIN_PASS"- Read realm idle/max settings
Keycloak realm settings that matter for idle logouts:
ssoSessionIdleTimeout(seconds): SSO idle session timeoutssoSessionMaxLifespan(seconds): max/absolute lifetime (we won’t change this in the minimal fix)
/opt/keycloak/bin/kcadm.sh get realms/maksonlee.com | jq '{
ssoSessionIdleTimeout,
ssoSessionMaxLifespan,
ssoSessionIdleTimeoutRememberMe,
ssoSessionMaxLifespanRememberMe,
accessTokenLifespan
}'If ssoSessionIdleTimeout is short (for example 1800 seconds = 30 minutes), it can force re-login even if Jenkins is configured for longer.
Part 2 — Minimal fix for “idle ~6 hours” (no unnecessary changes)
6 hours equals:
- 21600 seconds (Keycloak uses seconds)
- 360 minutes (Jenkins
--sessionTimeoutuses minutes)
To reach idle ~6 hours with minimal changes, we adjust:
- Jenkins:
--sessionTimeout=360 - Keycloak:
ssoSessionIdleTimeout=21600
We intentionally do not change:
- Keycloak
ssoSessionMaxLifespan(max/absolute) - Jenkins
--sessionEviction(cleanup/eviction) - NGINX configuration (proxy-only)
- Jenkins: set session timeout via systemd override (JENKINS_OPTS)
- Create/update the systemd drop-in override
sudo systemctl edit jenkinsAdd:
[Service]
Environment="JENKINS_OPTS=--sessionTimeout=360"If you already have an override that sets listen address, keep it and add this line alongside it.
Example:
[Service]
Environment="JENKINS_LISTEN_ADDRESS=127.0.0.1"
Environment="JENKINS_OPTS=--sessionTimeout=360"- Restart Jenkins
sudo systemctl restart jenkins- Confirm Jenkins is running with the flag
PID=$(systemctl show -p MainPID --value jenkins)
sudo tr '\0' ' ' < /proc/$PID/cmdline | tr -s ' ' \
| grep -E -- '--sessionTimeout=360' && echo OK || echo NOT_SETYou should see something like:
... jenkins.war ... --sessionTimeout=360
OK- Confirm systemd environment includes JENKINS_OPTS
sudo systemctl show jenkins -p Environment --no-pager | sed 's/^Environment=//'- Keycloak: set realm SSO idle to 6 hours (21600s)
On the Keycloak server:
/opt/keycloak/bin/kcadm.sh update realms/maksonlee.com \
-s ssoSessionIdleTimeout=21600Verify:
/opt/keycloak/bin/kcadm.sh get realms/maksonlee.com | jq '{
ssoSessionIdleTimeout,
ssoSessionMaxLifespan
}'We intentionally leave ssoSessionMaxLifespan unchanged.
If you keep using Jenkins continuously beyond the max lifespan, you may still be required to re-login. This guide targets idle logouts first.
Did this guide save you time?
Support this site