NGINX pour inverser les websockets de proxy ET activer SSL (wss: //)?

136

Je suis tellement perdu et nouveau dans la construction de NGINX par moi-même, mais je veux pouvoir activer des websockets sécurisés sans avoir une couche supplémentaire.

Je ne veux pas activer SSL sur le serveur websocket lui-même, mais à la place, je veux utiliser NGINX pour ajouter une couche SSL à l'ensemble.

Chaque page Web dit que je ne peux pas le faire, mais je sais que je peux! Merci à quiconque (moi-même) peut me montrer comment!

crockpotveggies
la source

Réponses:

185

Juste pour noter que nginx prend désormais en charge les Websockets sur la version 1.3.13. Exemple d'utilisation:

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;

}

Vous pouvez également consulter le journal des modifications nginx et la documentation du proxy WebSocket .

Tarentule
la source
Il a les mêmes problèmes de temporisation que ceux exprimés ci-dessus;)
3rdEden
5
@ 3rdEden: Pour les problèmes de timeout proxy_read_timeout, ça marche, j'ai édité la réponse.
Steve Kehlet
2
Où dois-je mettre cette configuration et qu'est-ce que backend_host?
Aysennoussi
3
@Sekai: Une locationdirective est placée dans une serverou une autre locationdirective (voir la documentation de localisation ). backend_hostest un upstream(voir la documentation en amont ) - un ou un groupe de serveurs vers lesquels vous allez utiliser un proxy.
Radko Dinev
1
Qu'en est-il de ce problème de délai d'expiration? Faut-il vraiment le fixer à un très grand nombre pour l'éviter? N'y a-t-il pas maintenant de solution plus élégante?
Mohammed Noureldin le
54

N'ayez pas peur, car un groupe courageux de programmeurs Ops a résolu la situation avec un nouveau nginx_tcp_proxy_module

Écrit en août 2012, donc si vous êtes du futur, vous devriez faire vos devoirs.

Conditions préalables

Suppose que vous utilisez CentOS:

  • Supprimer l'instance actuelle de NGINX (suggérez d'utiliser le serveur de développement pour cela)
  • Si possible, enregistrez vos anciens fichiers de configuration NGINX afin de pouvoir les réutiliser (y compris votre init.d/nginxscript)
  • yum install pcre pcre-devel openssl openssl-devel et toutes les autres bibliothèques nécessaires pour construire NGINX
  • Obtenez le nginx_tcp_proxy_module de GitHub ici https://github.com/yaoweibin/nginx_tcp_proxy_module et souvenez-vous du dossier où vous l'avez placé (assurez-vous qu'il n'est pas compressé)

Construisez votre nouveau NGINX

Encore une fois, suppose 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 (vous pouvez ajouter plus de modules si vous en avez besoin)
  • make
  • make install

Optionnel:

  • sudo /sbin/chkconfig nginx on

Configurer Nginx

N'oubliez pas de copier d'abord vos anciens fichiers de configuration si vous souhaitez les réutiliser.

Important: vous devrez créer une tcp {}directive au plus haut niveau dans votre conf. Assurez-vous que ce n'est pas dans votre http {}directive.

L'exemple de configuration ci-dessous montre un seul serveur websocket en amont et deux proxys pour SSL et 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;
    }
}
crockpotveggies
la source
5
C'était assez utile, mais j'obtenais toujours des délais d'attente à 60 secondes. J'ai réussi à résoudre ce problème en définissant ce qui suit: 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;
jbg le
2
Merci de partager ça! J'ai réalisé plus tard que j'avais des problèmes similaires et, par coïncidence, Yaoweibin lui-même a également répondu à mon problème GitHub avec un lien vers votre commentaire sur le numéro 28. Small World ...
crockpotveggies
1
Je voulais servir les websockets sur le même port http et seulement après que le navigateur ait été authentifié. Il semble que cela ne puisse pas gérer les Websockets sur le même port. Comment les gens gèrent-ils cela?
uroc
1
Il faudra quelques modifications logicielles pour détecter le protocole entrant. Étant donné que les websockets commencent en fait par une prise de contact HTTP (un niveau logiciel plus élevé que TCP), vous devez modifier votre application pour gérer à la fois le trafic TCP et HTTP. Je ne peux pas encore recommander un moyen de le faire.
crockpotveggies
2
Au cas où d'autres personnes de 2018 viennent ici, ces directives ne fonctionnent plus. Allez sur nginx.org/en/docs/http/websocket.html pour des instructions récentes ou consultez la réponse de Harlan T Wood ci-dessous.
GaryO
37

Cela a fonctionné pour moi:

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";
}

- emprunté à: https://github.com/nicokaiser/nginx-websocket-proxy/blob/df67cd92f71bfcb513b343beaa89cb33ab09fb05/simple-wss.conf

Bois Harlan T
la source
3
J'ai eu du mal à faire fonctionner les sockets Web de TeamCity derrière mon proxy inverse. Votre # WebSocket supportcoupure l'a fait pour moi. J'essayais auparavant de transférer le port 400, mais wss fonctionne sur 443. FYI futurs lecteurs :)
Mario Tacke
Avez-vous trouvé la solution? Comme je devais également face à un problème similaire stackoverflow.com/q/53411060/7713811
Nɪsʜᴀɴᴛʜ
J'aime cette réponse, car beaucoup de gens (comme vous) utilisent / pour les Websockets et HTTP2 standard.
mikemaccana
@Anyone quel serait le Javascript appelant?
Andrew Simpson
17

pour .net core 2.0 Nginx avec 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;
}

Cela a fonctionné pour moi

Altair CA
la source
quel est le code c #. J'ai actuellement ceci pour windows / iis _server = new WebSocketServer ("wss: //0.0.0.0: 8200 / MessageRelayer") {Certificate = new X509Certificate2 (PfxFileName, SslPassword), RestartAfterListenError = true};
Andrew Simpson le
J'utilise SignalR
Altair CA le
C'était la seule solution qui fonctionnait pour moi. Merci!
m-ketan
8

Pour moi, cela dépendait du proxy_passréglage de l' emplacement. J'avais besoin de passer à l'utilisation du protocole HTTPS et d'avoir un certificat SSL valide configuré du côté du serveur de nœuds. De cette façon, lorsque j'introduis un serveur de nœud externe, je n'ai qu'à changer l'adresse IP et tout le reste reste la même configuration.

J'espère que cela aide quelqu'un en cours de route ... Je regardais le problème tout le temps ... soupir ...

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 /websocket { #replace /websocket with the path required by your application
                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;
            }
}
CyberDigital
la source
J'ai essayé localtion /horizon, mais ça ne marche pas. Seulement localtion /ou location /websockifyfonctionne. Je ne sais pas pourquoi ...
njuguoyi
6

Un bon article concis de Pankaj Malhotra explique comment faire cela avec NGINX et est disponible ici .

La configuration de base de NGINX est reproduite ci-dessous:

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;
    }
}
Btiernay
la source
1
Les versions modernes de NGINX résolvent-elles également les problèmes de délai d'expiration?
crockpotveggies
2

Utilisation de nginx / 1.14.0

j'ai un serveur websocket fonctionnant sur le port 8097 et les utilisateurs se connectent de à wss sur le port 8098, nginx déchiffre simplement le contenu et le transmet au serveur websocket

Donc j'ai ce fichier de configuration (dans mon cas /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;

    }
}
John Smith
la source