# Put ThothII behind Nginx Choose exactly one authentication mode. Direct ThothII-managed OIDC and deprecated upstream authentication are mutually exclusive proxy contracts; never combine their locations or headers. ## Direct ThothII-managed OIDC Use this mode when `auth.yaml` has `mode: oidc`. Nginx terminates TLS and proxies every request to loopback `frontend`. ThothII owns OIDC login, callback validation, browser sessions, and authorization. No external `auth_request` or authentication gateway belongs in this server. The `location /` block below has a `proxy_pass` without a replacement URI, so public `/api/auth/oidc/login` and `/api/auth/oidc/callback` are forwarded unchanged. The configured `publicUrl` must match the browser origin. ```nginx server { listen 80; server_name thoth.example.invalid; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name thoth.example.invalid; ssl_certificate /etc/nginx/tls/thoth/fullchain.pem; ssl_certificate_key /etc/nginx/tls/thoth/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; location / { # No auth_request and no URI rewrite: ThothII receives OIDC paths unchanged. proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ""; proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_buffering off; proxy_cache off; proxy_read_timeout 3600s; add_header X-Accel-Buffering no always; } } ``` After reload, run Workspace Validate for static validation, `tht auth check` for live, non-interactive authentication diagnosis, and then Workspace Test for aggregate live validation. ## Deprecated upstream migration mode Use this section only while the installation explicitly uses deprecated `upstream` mode. Do not use it with `mode: oidc` or `mode: local`. In this mode an external authentication gateway owns login, and Nginx applies `auth_request` before forwarding normalized private identity headers. Forwarding identity headers alone does not authenticate a user. The authentication gateway returns 2xx only after validating its own credential or session. ```nginx server { listen 443 ssl; server_name thoth.example.invalid; ssl_certificate /etc/nginx/tls/thoth/fullchain.pem; ssl_certificate_key /etc/nginx/tls/thoth/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; location = /_authenticate { internal; proxy_pass http://auth-gateway:4180/verify; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Original-Method $request_method; proxy_set_header X-Authenticated-User ""; proxy_set_header X-Thoth-Principal-Issuer ""; proxy_set_header X-Thoth-Principal-Subject ""; proxy_set_header X-Thoth-Principal-Display-Name ""; proxy_set_header X-Thoth-Is-Admin ""; proxy_set_header X-Thoth-Trusted-Principal-Issuer ""; proxy_set_header X-Thoth-Trusted-Principal-Subject ""; proxy_set_header X-Thoth-Trusted-Principal-Display-Name ""; proxy_set_header X-Thoth-Trusted-Is-Admin ""; } location / { auth_request /_authenticate; auth_request_set $thoth_principal_issuer $upstream_http_x_thoth_principal_issuer; auth_request_set $thoth_principal_subject $upstream_http_x_thoth_principal_subject; auth_request_set $thoth_principal_display_name $upstream_http_x_thoth_principal_display_name; auth_request_set $thoth_is_admin $upstream_http_x_thoth_is_admin; proxy_set_header X-Authenticated-User ""; proxy_set_header X-Thoth-Principal-Issuer ""; proxy_set_header X-Thoth-Principal-Subject ""; proxy_set_header X-Thoth-Principal-Display-Name ""; proxy_set_header X-Thoth-Is-Admin ""; proxy_set_header X-Thoth-Trusted-Principal-Issuer $thoth_principal_issuer; proxy_set_header X-Thoth-Trusted-Principal-Subject $thoth_principal_subject; proxy_set_header X-Thoth-Trusted-Principal-Display-Name $thoth_principal_display_name; proxy_set_header X-Thoth-Trusted-Is-Admin $thoth_is_admin; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ""; proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_buffering off; proxy_cache off; proxy_read_timeout 3600s; add_header X-Accel-Buffering no always; } } ``` ## Trust boundary Nginx is the only public listener and proxies only to loopback `frontend`, never directly to `core`. Keep private keys outside the ThothII tree. Do not log cookies, authorization headers, OIDC callback query values, authentication bodies, or trusted identity headers. ## Validate and reload Keep the public firewall closed while validating: ```sh curl --fail http://127.0.0.1:8080/health sudo nginx -t sudo systemctl reload nginx ``` ## Test authentication and SSE For direct OIDC, verify login redirects to the configured provider, callback traffic reaches ThothII unchanged, forged identity headers grant nothing, and SSE is unbuffered. For deprecated upstream mode, additionally verify the external gateway rejects unauthenticated traffic and only its 2xx response can create trusted identity headers.