NGINX do odwrócenia gniazd sieciowych proxy ORAZ włączenia SSL (wss: //)?

141

Jestem tak zagubiony i nowy w samodzielnym budowaniu NGINX, ale chcę mieć możliwość włączania bezpiecznych gniazd internetowych bez dodatkowej warstwy.

Nie chcę włączać SSL na samym serwerze WebSocket, ale zamiast tego chcę użyć NGINX, aby dodać warstwę SSL do całości.

Każda strona internetowa mówi, że nie mogę tego zrobić, ale wiem, że mogę! Dzięki temu, kto (ja) może mi pokazać jak!

crockpotveggies
źródło

Odpowiedzi:

194

Wystarczy zauważyć, że nginx obsługuje teraz Websockets w wersji 1.3.13. Przykład użycia:

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;

}

Możesz również sprawdzić dziennik zmian nginx i dokumentację serwera proxy WebSocket .

Tarantula
źródło
Ma te same problemy z
limitem
6
@ 3rdEden: W przypadku problemów z przekroczeniem limitu czasu, proxy_read_timeoutdziała, zredagowałem odpowiedź.
Steve Kehlet
2
Gdzie mam umieścić tę konfigurację i co to jest backend_host?
Aysennoussi
3
@Sekai: locationDyrektywa jest umieszczona w serverinnej locationdyrektywie (zobacz dokumentację lokalizacji ). backend_hostjest upstream(zobacz dokumentację źródłową ) - jednym lub grupą serwerów, do których będziesz proxy.
Radko Dinev
1
A co z tym problemem z limitem czasu? Czy naprawdę musimy ustawić bardzo dużą liczbę, aby tego uniknąć? Czy nie ma teraz bardziej eleganckiego rozwiązania?
Mohammed Noureldin
54

Nie bój się, ponieważ odważna grupa programistów operacji rozwiązała sytuację dzięki nowemu nginx_tcp_proxy_module

Napisany w sierpniu 2012 roku, więc jeśli jesteś z przyszłości, powinieneś odrobić lekcje.

Wymagania wstępne

Zakłada, że ​​używasz CentOS:

  • Usuń bieżące wystąpienie NGINX (zasugeruj użycie do tego serwera deweloperskiego)
  • Jeśli to możliwe, zapisz stare pliki konfiguracyjne NGINX, aby móc ich ponownie użyć (w tym init.d/nginxskryptu)
  • yum install pcre pcre-devel openssl openssl-devel i wszelkie inne niezbędne biblioteki do budowania NGINX
  • Pobierz nginx_tcp_proxy_module z GitHub tutaj https://github.com/yaoweibin/nginx_tcp_proxy_module i zapamiętaj folder, w którym go umieściłeś (upewnij się, że nie jest spakowany)

Zbuduj swój nowy NGINX

Ponownie zakłada 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 (możesz dodać więcej modułów, jeśli ich potrzebujesz)
  • make
  • make install

Opcjonalny:

  • sudo /sbin/chkconfig nginx on

Skonfiguruj Nginx

Pamiętaj, aby najpierw skopiować stare pliki konfiguracyjne, jeśli chcesz ich ponownie użyć.

Ważne: będziesz musiał stworzyć tcp {}dyrektywę na najwyższym poziomie w swoim conf. Upewnij się, że nie znajduje się on w Twojej http {}dyrektywie.

Poniższa przykładowa konfiguracja przedstawia pojedynczy nadrzędny serwer sieci Web i dwa serwery proxy zarówno dla SSL, jak i bez 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
źródło
5
Było to całkiem pomocne, ale nadal uzyskiwałem limity czasu po 60 sekundach. Udało mi się to naprawić ustawiając: 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
1
Chciałem obsługiwać gniazda sieciowe z tego samego portu http i dopiero po uwierzytelnieniu przeglądarki. Wygląda na to, że nie obsługuje gniazd sieciowych na tym samym porcie. Jak ludzie sobie z tym radzą?
uroc
1
Wykrywanie protokołu przychodzącego zajmie trochę modyfikacji oprogramowania. Ponieważ gniazda sieciowe faktycznie rozpoczynają się jako uzgadnianie HTTP (wyższy poziom oprogramowania niż TCP), musisz dostosować aplikację, aby obsługiwała zarówno ruch TCP, jak i HTTP. Nie mogę jeszcze polecić sposobu, aby to zrobić.
crockpotveggies
2
Na wypadek, gdyby przyjechali tu inni ludzie z 2018 roku, te dyrektywy już nie działają. Odwiedź stronę nginx.org/en/docs/http/websocket.html, aby uzyskać najnowsze instrukcje lub zapoznaj się z odpowiedzią Harlana T Wooda poniżej.
GaryO,
Znalazłeś rozwiązanie? Ponieważ miałem do czynienia również podobny problem stackoverflow.com/q/53411060/7713811
Nɪsʜᴀɴᴛʜ
38

To zadziałało dla mnie:

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

- zapożyczone z: https://github.com/nicokaiser/nginx-websocket-proxy/blob/df67cd92f71bfcb513b343beaa89cb33ab09fb05/simple-wss.conf

Harlan T Wood
źródło
3
Miałem problem z uruchomieniem gniazd sieciowych TeamCity za moim zwrotnym proxy. Twój # WebSocket supportodcięty zrobił to dla mnie. Wcześniej próbowałem przekierować port 400, jednak wss działa na 443. Przyszli czytelnicy do Twojej wiadomości :)
Mario Tacke
Znalazłeś rozwiązanie? Ponieważ ja też musiałem zmierzyć się z podobnym problemem stackoverflow.com/q/53411060/7713811
Nɪsʜᴀɴᴛʜ
Najbardziej podoba mi się ta odpowiedź, ponieważ wiele osób (takich jak ty) używa / dla obu gniazd internetowych i zwykłego HTTP2.
mikemaccana
@Każdy, jaki byłby wywołujący Javascript?
Andrew Simpson
17

dla .net core 2.0 Nginx z 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;
}

To zadziałało dla mnie

Altair CA
źródło
jaki jest kod C #. Obecnie mam to w systemie windows / iis _server = new WebSocketServer ("wss: //0.0.0.0: 8200 / MessageRelayer") {Certificate = new X509Certificate2 (PfxFileName, SslPassword), RestartAfterListenError = true};
Andrew Simpson
Używam SignalR
Altair CA
9

Dla mnie sprowadzało się to do proxy_passustawienia lokalizacji. Musiałem przejść na protokół HTTPS i mieć ważny certyfikat SSL ustawiony po stronie serwera węzłowego. W ten sposób, kiedy wprowadzam zewnętrzny serwer węzłów, muszę tylko zmienić adres IP, a wszystko inne pozostaje bez zmian.

Mam nadzieję, że to pomoże komuś po drodze ... Cały czas gapiłem się na problem ... westchnij ...

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
źródło
Próbowałem localtion /horizon, ale to nie działa. Tylko localtion /lub location /websockifydziała. Nie wiem dlaczego ...
njuguoyi
6

Dobry, zwięzły artykuł autorstwa Pankaja Malhotry omawia, jak to zrobić z NGINX i jest dostępny tutaj .

Podstawową konfigurację NGINX przedstawiono poniżej:

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
źródło
1
Czy nowoczesne wersje NGINX rozwiązują również problemy z limitem czasu?
crockpotveggies
3

Korzystanie z nginx / 1.14.0

Mam serwer WebSocket działający na porcie 8097 i użytkownicy łączą się z wss na porcie 8098, nginx po prostu odszyfrowuje zawartość i przekazuje ją do serwera WebSocket

Więc mam ten plik konfiguracyjny (w moim przypadku /etc/nginx/conf.d/default.conf)

server {
    listen   8098;
        ssl on;
        ssl_certificate      /etc/ssl/certs/domain.crt;
        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
źródło