Moving from IIS to nginx

So I have a confession. I have been using IIS to route traffic to my node instances. This is a legacy thing and has actually been perfectly fine up to now. However, I want to use websockets in a project I am working on. #aras18. The version of IIS I am using does not seem to support it and I am not that interested in fighting with it. So to nginx.

So I downloaded the latest version (at time of writing 1.13.11)

Now the main functionality that IIS was doing for me was just acting as a reverse proxy. Accepting 80 and 443 requests and routing to various node instances based on the HTTP_HOST. Lets start with that.

Configuration

On windows the nginx.conf file is located in the install directory under \conf. In the nginx beginner's guide proxy section it goes through how to set up a basic proxy.

Reverse Proxy

It's the second bit of config that we are interested in

http {
  server {
    location / {
      proxy_pass http://localhost:8080;
    }

    location /images/ {
      root /data;
    }
  }
}

This creates a server that proxies requests to a server listening on the localhost on port 8080.

What we want though is a multiple servers that listens on the same port and route based on the http_host. We also need it to be over ssl.

http {
  server {
    listen 443 ssl;
    server_name aigeec.com;
    server_name www.aigeec.com;
    ssl_certificate /path/to/cert;
    ssl_certificate_key /path/to/key;
    location / {        
      proxy_set_header Host $http_host;
      proxy_pass http://127.0.0.1:3000;
    }
  }
}

The above config will listen on the default ssl port 443 and route if the host on the request matches either aigeec.com or www.aigeec.com. It will the route to location specified.

The equivalent in IIS for this would have been something like:

<rule name="aigeec" stopProcessing="true">
  <match url="(.*)" />
  <action type="Rewrite" url="http://127.0.0.1:3000/{R:1}" appendQueryString="true" />
  <conditions>
    <add input="{HTTP_HOST}" pattern="(www.)?aigeec.com" />
  </conditions>
</rule>

There would be additional config to bind the http/https aigeec.com traffic to this particular application.

Websockets

The main point of switching was to support websockets. Nginx facilitates proxying websockets. To turn a connection between a client and server from HTTP/1.1 into WebSocket, the protocol switch mechanism available in HTTP/1.1 is used. There is additional configuration to allow the upgrading of the connection which facilitates the websocket connection. We do this by passing on the Upgrade and Connection headers

This bit just sets up a variable to to use later in the config. Here's the documentation for map

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

We add this to send on the headers to the server being proxied.

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

Here is the full config:

  map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
  }
  
  server {
    listen 443 ssl;
    server_name aigeec.com;
    server_name www.aigeec.com;
    ssl_certificate /path/to/cert;
    ssl_certificate_key /path/to/key;
    location / {
      proxy_set_header Host $http_host;
      proxy_pass http://127.0.0.1:3000;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
    }
  }

Note that the connection is closed after 1 minute if nothing has been sent from the server. You can increase this timeout or you can send a ping from the proxied server to keep the connection open.