By crockpotveggies


2012-08-24 01:23:38 8 Comments

I'm so lost and new to building NGINX on my own but I want to be able to enable secure websockets without having an additional layer.

I don't want to enable SSL on the websocket server itself but instead I want to use NGINX to add an SSL layer to the whole thing.

Every web page out there says I can't do it, but I know I can! Thanks to whoever (myself) can show me how!

7 comments

@john Smith 2018-10-06 14:31:04

Using nginx/1.14.0

i have a websocket-server running on port 8097 and users connect from to wss on port 8098, nginx just decrypts the content and forwards it to the websocket server

So i have this config file (in my case /etc/nginx/conf.d/default.conf)

server {
    listen   8098;
        ssl on;
        ssl_certificate      /etc/ssl/certs/combined.pem;
        ssl_certificate_key  /root/domain.key;
    location / {

        proxy_pass http://hostname:8097;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400;

    }
}

@btiernay 2015-11-06 22:02:02

A good, concise article by Pankaj Malhotra discusses how to do this with NGINX and is available here.

The basic NGINX configuration is reproduced below:

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

upstream appserver {
    server 192.168.100.10:9222; # appserver_ip:ws_port
}

server {
    listen 8888; // client_wss_port

    ssl on;
    ssl_certificate /path/to/crt;
    ssl_certificate_key /path/to/key;


    location / {
        proxy_pass http://appserver;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

@crockpotveggies 2015-11-06 23:58:05

Do the modern versions of NGINX also address the timeout issues?

@Altair CA 2017-10-10 20:26:45

for .net core 2.0 Nginx with SSL

location / {
    # redirect all HTTP traffic to localhost:8080
    proxy_pass http://localhost:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # WebSocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
}

This worked for me

@magoomby 2017-08-02 09:11:22

For me it came down to the proxy_pass location setting. In needed to change the http://nodeserver to https://nodeserver, and have a valid SSL certificate setup on the node server side of things. That way when I introduce an external node server, I only have to change the IP and everything else remains the same config.

I hope this helps someone along the way... I was staring at the problem the whole time... sigh...

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
upstream nodeserver {
        server 127.0.0.1:8080;
}
server {
        listen 443 default_server ssl http2;
        listen [::]:443 default_server ssl http2 ipv6only=on;
        server_name mysite.com;
        ssl_certificate ssl/site.crt;
        ssl_certificate_key ssl/site.key;
        location /horizon {
                proxy_pass https://nodeserver;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
                proxy_http_version 1.1;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_intercept_errors on;
                proxy_redirect off;
                proxy_cache_bypass $http_upgrade;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-NginX-Proxy true;
                proxy_ssl_session_reuse off;
            }
}

@njuguoyi 2018-10-27 10:11:36

I tried localtion /horizon, but it's not working. Only localtion / or location /websockify works. Don't know why...

@Harlan T Wood 2016-08-30 00:07:13

This worked for me:

location / {
    # redirect all HTTP traffic to localhost:8080
    proxy_pass http://localhost:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # WebSocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

-- borrowed from: https://github.com/nicokaiser/nginx-websocket-proxy/blob/df67cd92f71bfcb513b343beaa89cb33ab09fb05/simple-wss.conf

@Mario Tacke 2016-09-16 18:26:10

I had trouble getting TeamCity's web sockets to work behind my reverse proxy. Your # WebSocket support snipped did it for me. I was previously trying to forward port 400, however wss works over 443. FYI future readers :)

@Nishanth ॐ 2018-11-22 08:26:56

Have you figured out the solution? Since I had to also faced a similar problem stackoverflow.com/q/53411060/7713811

@crockpotveggies 2012-08-24 01:23:38

Have no fear, because a brave group of Ops Programmers have solved the situation with a brand spanking new nginx_tcp_proxy_module

Written in August 2012, so if you are from the future you should do your homework.

Prerequisites

Assumes you are using CentOS:

  • Remove current instance of NGINX (suggest using dev server for this)
  • If possible, save your old NGINX config files so you can re-use them (that includes your init.d/nginx script)
  • yum install pcre pcre-devel openssl openssl-devel and any other necessary libs for building NGINX
  • Get the nginx_tcp_proxy_module from GitHub here https://github.com/yaoweibin/nginx_tcp_proxy_module and remember the folder where you placed it (make sure it is not zipped)

Build Your New NGINX

Again, assumes CentOS:

  • cd /usr/local/
  • wget 'http://nginx.org/download/nginx-1.2.1.tar.gz'
  • tar -xzvf nginx-1.2.1.tar.gz
  • cd nginx-1.2.1/
  • patch -p1 < /path/to/nginx_tcp_proxy_module/tcp.patch
  • ./configure --add-module=/path/to/nginx_tcp_proxy_module --with-http_ssl_module (you can add more modules if you need them)
  • make
  • make install

Optional:

  • sudo /sbin/chkconfig nginx on

Set Up Nginx

Remember to copy over your old configuration files first if you want to re-use them.

Important: you will need to create a tcp {} directive at the highest level in your conf. Make sure it is not inside your http {} directive.

The example config below shows a single upstream websocket server, and two proxies for both SSL and Non-SSL.

tcp {
    upstream websockets {
        ## webbit websocket server in background
        server 127.0.0.1:5501;

        ## server 127.0.0.1:5502; ## add another server if you like!

        check interval=3000 rise=2 fall=5 timeout=1000;
    }   

    server {
        server_name _;
        listen 7070;

        timeout 43200000;
        websocket_connect_timeout 43200000;
        proxy_connect_timeout 43200000;

        so_keepalive on;
        tcp_nodelay on;

        websocket_pass websockets;
        websocket_buffer 1k;
    }

    server {
        server_name _;
        listen 7080;

        ssl on;
        ssl_certificate      /path/to/cert.pem;
        ssl_certificate_key  /path/to/key.key;

        timeout 43200000;
        websocket_connect_timeout 43200000;
        proxy_connect_timeout 43200000;

        so_keepalive on;
        tcp_nodelay on;

        websocket_pass websockets;
        websocket_buffer 1k;
    }
}

@jbg 2012-09-02 06:18:19

This was pretty helpful, but I was still getting timeouts at 60secs. I managed to fix this by setting the following: timeout 43200000; websocket_connect_timeout 43200000; websocket_read_timeout 43200000; websocket_send_timeout 43200000; proxy_connect_timeout 43200000; proxy_read_timeout 43200000; proxy_send_timeout 43200000;

@crockpotveggies 2012-09-03 01:41:30

Thanks for sharing that! I later realized I was having similar problems, and coincidentally yaoweibin himself also replied to my GitHub issue with a link to your comment on Issue #28. Small world...

@uroc 2012-11-15 19:06:07

I wanted to serve websockets off the same http port and only after the browser had been authenticated. It looks like this can't handle websockets on the same port. How do people handle this?

@crockpotveggies 2012-11-15 21:20:43

It will take some software modification to detect the incoming protocol. Since websockets actually start as an HTTP handshake (a higher software level than TCP) you have to tweak your app to handle both TCP and HTTP traffic. I can't recommend a way to do this just yet.

@GaryO 2018-06-25 21:01:36

In case other folks from 2018 come here, these directives don't work any more. Go to nginx.org/en/docs/http/websocket.html for recent instructions or see Harlan T Wood's answer below.

@crockpotveggies 2018-06-26 06:35:14

Thanks for the update, I'll change the accepted answer to @Harlan's.

@Nishanth ॐ 2018-11-22 08:24:48

Have you figured out the solution? Since I had to also faced a similar problem stackoverflow.com/q/53411060/7713811

@Tarantula 2013-02-19 23:58:37

Just to note that nginx has now support for Websockets on the release 1.3.13. Example of use:

location /websocket/ {

    proxy_pass ​http://backend_host;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 86400;

}

You can also check the nginx changelog and the WebSocket proxying documentation.

@3rdEden 2013-04-04 11:45:30

It has the same timeout issues as expressed above ;)

@Steve Kehlet 2013-04-29 20:02:30

@3rdEden: For timeout issues, proxy_read_timeout works, I edited the answer.

@Sekai 2014-05-21 21:08:04

Where should I put this configuration and what is backend_host ?

@Radko Dinev 2014-08-13 18:37:15

@Sekai: A location directive is put within a server or another location directive (see location docs). backend_host is an upstream (see upstream docs) - one or a group of servers that you'll proxy to.

@Jan Święcki 2015-02-24 15:03:10

@Tarantula Thanks, this is awesome!:)

@jlee 2016-08-23 04:03:50

@RadkoDinev -- is upstream necessary, or if I just have one server, I can just use that in the proxy_pass directive?

@Radko Dinev 2016-08-23 10:47:18

@jlee As stated in the documentation of the proxy_pass directive it's value is an URL in general. Having one server, you could just use it's DNS name or IP address as a value. upstream is usually used for more than one server, and/or when you want to specify additional options (e.g. keepalive).

@Mohammed Noureldin 2018-01-04 23:48:17

What about this timeout problem? Do we have really to set it to a very large number to avoid it? Isn't there now any more elegant solution?

@Nishanth ॐ 2018-11-22 08:26:32

Have you figured out the solution? Since I had to also faced a similar problem stackoverflow.com/q/53411060/7713811

Related Questions

Sponsored Content

2 Answered Questions

[SOLVED] Nginx reverse proxying websockets

18 Answered Questions

[SOLVED] Difference between proxy server and reverse proxy server

1 Answered Questions

[SOLVED] NGINX: different logs for two different websocket connections

1 Answered Questions

reverse proxy nginx no such file or directory

  • 2017-10-30 13:59:43
  • Felipe Lima de Oliveira
  • 774 View
  • 0 Score
  • 1 Answer
  • Tags:   javascript nginx proxy

1 Answered Questions

[SOLVED] nginx reverse proxy with nodejs and apache over SSL

1 Answered Questions

[SOLVED] Proxy secure websocket to Play server through nginx

1 Answered Questions

[SOLVED] Nginx - Reverse Proxy a WebSocket server with multiple paths

2 Answered Questions

[SOLVED] neo4j webinterface behind nginx reverse proxy

2 Answered Questions

[SOLVED] Node.js - Good WebServer with WebSocket-proxying & SSL support?

Sponsored Content