jenkins.io icon indicating copy to clipboard operation
jenkins.io copied to clipboard

Example nginx config should only set WebSocket headers on WebSocket URLs

Open mst-ableton opened this issue 3 years ago • 2 comments

Describe your use-case which is not covered by existing documentation.

The nginx configuration provided at https://www.jenkins.io/doc/book/system-administration/reverse-proxy-configuration-nginx/ sets up keepalives for a Jenkins upstream server, but also configures nginx to render keepalives useless.

This is because the following WebSocket headers are set on all requests (location /) instead of just for WebSocket URLs:

      proxy_set_header   Connection        $connection_upgrade;
      proxy_set_header   Upgrade           $http_upgrade;

$connection_upgrade is set earlier by a map:

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

which sets Connection to the string "upgrade" if the Upgrade header is present, and "close" if it is not present. As non-WebSocket clients (such as a regular web visitors from a browser) do not set Upgrade, all non-WebSocket traffic will have the Connection header set to close when contacting Jenkins. This can be confirmed by pointing nginx at a webserver which dumps headers instead of a Jenkins upstream.

Keepalives only work when Connection: close is not sent to the upstream server, meaning the configuration presented effectively disables keepalives for all non-WebSocket traffic, regardless of how many are specified in the upstream section.

Further, because proxy_set_header overrides client headers but does not override previous proxy_set_header directives, the line:

proxy_set_header Connection ""; # Clear for keepalive

doesn't actually do anything since it comes after the previous proxy_set_header directive.

Note that the nginx docs set the WebSocket headers for a subdirectory, not for location /. This is confirmed with Michael Hampton's comment in this StackOverflow Question:

You aren't going to send normal connections to your websocket! You should only send websocket connections to your websocket URL.

I tried but failed to set the WebSocket headers on only the /wsagents/ URL. Are there other URLs which need to have the headers for this to work?

Reference any relevant documentation, other materials or issues/pull requests that can be used for inspiration.

  • https://www.jenkins.io/doc/book/system-administration/reverse-proxy-configuration-nginx/
  • https://stackoverflow.com/a/46772133
  • https://www.nginx.com/blog/websocket-nginx/
  • https://serverfault.com/questions/1025894/nginx-proxy-websocket-is-it-required-to-close-the-connection-to-backend-after-u

mst-ableton avatar Feb 08 '22 15:02 mst-ableton

@mst-ableton thanks for opening this issue. I've moved it from https://github.com/jenkins-infra/helpdesk to https://github.com/jenkins-infra/jenkins.io as it's a documentation issue not related to Jenkins Infrastructure.

lemeurherve avatar Feb 08 '22 16:02 lemeurherve

(I should also mention: thanks for everyone's work on Jenkins! It's a lot to keep a project of this magnitude running smoothly.)

mst-ableton avatar Feb 09 '22 14:02 mst-ableton