SignalR behind nginx reverse proxy

23 Oct 2012

SignalR offers several transport options for building real-time, multi-user (not necessarily web) applications and those who want to use it in combination with nginx reverse proxy might leverage following configuration examples.

Configuring SignalR

Although SignalR (as of version 0.5.3) has only four configuration settings namely two of them might have some effect depending on underlying transport being used after initial handshaking. Both of these settings are dependent on nginx configuration in order to prevent receiving 504 (gateway timeout) response.

// determines time of a single long poll cycle (in case long polling transport is used)
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(...);
// determines time after which keep alive packet is sent if the connection is idle (in case e.g. SSE transport is used)
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(...);

Configuring nginx

There are numerous tutorials around the web regarding how to setup nginx as a reverse proxy, so I will stick only to important parts. Following directives should be set to higher values than SignalR settings. Keep in mind that the time amount difference should be at least fifteen seconds higher than SignalR since connection status checks are (by default) in ten second intervals.

keepalive_timeout <sec> <sec>;
send_timeout <sec>;

proxy_connect_timeout <sec>;
proxy_send_timeout <sec>;
proxy_read_timeout <sec>;

Another important directive is proxy_buffering which should be disabled in order to prevent nginx buffer asynchronous responses.

proxy_buffering off;

My setup involved ASP.NET MVC website which also hosted SignalR Hub served on Windows Server 2k8 and IIS 7.5. This website could be accessed either through nginx sub.foo.bar style URL or directly through IIS sub-1.foo.bar (for debugging purpose) therefore Host header in the following configuration was set to fixed value.

server {
        listen 80;

        server_name sub.foo.bar;

        location / {
                proxy_pass http://sub-1.foo.bar/;
                
                proxy_set_header Host "sub-1.foo.bar";
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}
blog comments powered by Disqus