NGINX เพื่อย้อนกลับเว็บซ็อกเก็ตพร็อกซีและเปิดใช้งาน SSL (wss: //)?


141

ฉันหลงทางและยังใหม่กับการสร้าง NGINX ด้วยตัวเอง แต่ฉันต้องการเปิดใช้งานเว็บซ็อกเก็ตที่ปลอดภัยโดยไม่ต้องมีเลเยอร์เพิ่มเติม

ฉันไม่ต้องการเปิดใช้ SSL บนเซิร์ฟเวอร์ websocket แต่ฉันต้องการใช้ NGINX เพื่อเพิ่มเลเยอร์ SSL ให้กับสิ่งทั้งหมด

ทุกหน้าเว็บบอกว่าทำไม่ได้ แต่รู้ว่าทำได้! ต้องขอบคุณใครก็ตามที่ (ตัวเอง) สามารถแสดงวิธี!

คำตอบ:


194

โปรดทราบว่าตอนนี้ nginx รองรับ Websockets ในรุ่น 1.3.13 แล้ว ตัวอย่างการใช้งาน:

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;

}

คุณยังสามารถตรวจสอบบันทึกการเปลี่ยนแปลง nginxและเอกสารคู่มือการใช้พร็อกซีของ WebSocket


มีปัญหาการหมดเวลาเช่นเดียวกับที่แสดงไว้ข้างต้น;)
3rdEden

6
@ 3rdEden: สำหรับปัญหาการหมดเวลาใช้proxy_read_timeoutงานได้ฉันแก้ไขคำตอบ
Steve Kehlet

2
ฉันควรวางการกำหนดค่านี้ไว้ที่ใดและ backend_host คืออะไร
Aysennoussi

3
@Sekai: locationคำสั่งอยู่ในคำสั่งserverหรือlocationคำสั่งอื่น(ดูเอกสารสถานที่ ) backend_hostคือupstream(ดูเอกสารต้นน้ำ ) - หนึ่งหรือกลุ่มของเซิร์ฟเวอร์ที่คุณจะใช้พร็อกซี
Radko Dinev

1
แล้วปัญหาการหมดเวลานี้ล่ะ? เราต้องตั้งค่าเป็นจำนวนมากเพื่อหลีกเลี่ยงหรือไม่? ตอนนี้ไม่มีทางออกที่หรูหรากว่านี้แล้วเหรอ?
Mohammed Noureldin

54

ไม่ต้องกลัวเพราะกลุ่ม Ops Programmer ผู้กล้าหาญได้แก้ไขสถานการณ์ด้วยแบรนด์ใหม่ที่ตบnginx_tcp_proxy_module

เขียนในเดือนสิงหาคม 2012 ดังนั้นหากคุณมาจากอนาคตคุณควรทำการบ้าน

ข้อกำหนดเบื้องต้น

ถือว่าคุณกำลังใช้ CentOS:

  • ลบอินสแตนซ์ปัจจุบันของ NGINX (แนะนำให้ใช้เซิร์ฟเวอร์ dev สำหรับสิ่งนี้)
  • ถ้าเป็นไปได้ให้บันทึกไฟล์กำหนดค่า NGINX เก่าของคุณเพื่อให้คุณสามารถใช้ซ้ำได้ (ซึ่งรวมถึงinit.d/nginxสคริปต์ของคุณด้วย)
  • yum install pcre pcre-devel openssl openssl-devel และ libs ที่จำเป็นอื่น ๆ สำหรับการสร้าง NGINX
  • รับnginx_tcp_proxy_moduleจาก GitHub ที่นี่https://github.com/yaoweibin/nginx_tcp_proxy_moduleและจำโฟลเดอร์ที่คุณวางไว้ (ตรวจสอบให้แน่ใจว่าไม่ได้ซิป)

สร้าง NGINX ใหม่ของคุณ

อีกครั้งถือว่า 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 (คุณสามารถเพิ่มโมดูลเพิ่มเติมได้หากต้องการ)
  • make
  • make install

ไม่จำเป็น:

  • sudo /sbin/chkconfig nginx on

ตั้งค่า Nginx

อย่าลืมคัดลอกไฟล์การกำหนดค่าเก่าของคุณก่อนหากคุณต้องการใช้ซ้ำ

สำคัญ:คุณจะต้องสร้างtcp {}คำสั่งที่ระดับสูงสุดในคอนฟิกของคุณ ตรวจสอบให้แน่ใจว่าไม่ได้อยู่ในhttp {}คำสั่งของคุณ

ตัวอย่างการกำหนดค่าด้านล่างแสดงเซิร์ฟเวอร์เว็บซ็อกเก็ตต้นน้ำเดียวและสองพร็อกซีสำหรับทั้ง SSL และไม่ใช่ 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;
    }
}

5
สิ่งนี้มีประโยชน์มาก แต่ฉันยังคงได้รับการหมดเวลาที่ 60 วินาที ฉันจัดการเพื่อแก้ไขปัญหานี้โดยตั้งค่าต่อไปนี้: หมดเวลา 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
ฉันต้องการให้บริการ websockets จากพอร์ต http เดียวกันและหลังจากตรวจสอบสิทธิ์เบราว์เซอร์แล้วเท่านั้น ดูเหมือนว่าจะไม่สามารถจัดการกับ websockets บนพอร์ตเดียวกันได้ ผู้คนรับมือกับเรื่องนี้อย่างไร?
uroc

1
จะต้องใช้การปรับเปลี่ยนซอฟต์แวร์บางอย่างเพื่อตรวจจับโปรโตคอลที่เข้ามา เนื่องจาก websockets เริ่มต้นเป็นการจับมือ HTTP (ระดับซอฟต์แวร์ที่สูงกว่า TCP) คุณจึงต้องปรับแต่งแอปของคุณเพื่อรองรับการรับส่งข้อมูลทั้ง TCP และ HTTP ฉันยังแนะนำวิธีทำสิ่งนี้ไม่ได้
crockpotveggies

2
ในกรณีที่คนอื่น ๆ จากปี 2018 มาที่นี่คำสั่งเหล่านี้จะไม่ได้ผลอีกต่อไป ไปที่nginx.org/en/docs/http/websocket.htmlสำหรับคำแนะนำล่าสุดหรือดูคำตอบของ Harlan T Wood ด้านล่าง
GaryO

คุณคิดหาวิธีแก้ปัญหาแล้วหรือยัง? ตั้งแต่ฉันได้ไปยังต้องเผชิญกับปัญหาที่คล้ายกัน stackoverflow.com/q/53411060/7713811
Nɪsʜᴀɴᴛʜ

38

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

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

- ยืมมาจาก: https://github.com/nicokaiser/nginx-websocket-proxy/blob/df67cd92f71bfcb513b343beaa89cb33ab09fb05/simple-wss.conf


3
ฉันมีปัญหาในการทำให้เว็บซ็อกเก็ตของ TeamCity ทำงานหลังพร็อกซีย้อนกลับของฉัน # WebSocket supportsnipped ของคุณทำเพื่อฉัน ก่อนหน้านี้ฉันพยายามส่งต่อพอร์ต 400 แต่ wss ทำงานได้มากกว่า 443 ผู้อ่านในอนาคต FYI :)
Mario Tacke

คุณคิดหาวิธีแก้ปัญหาแล้วหรือยัง? ตั้งแต่ฉันได้ไปยังต้องเผชิญกับปัญหาที่คล้ายกัน stackoverflow.com/q/53411060/7713811
Nɪsʜᴀɴᴛʜ

ฉันชอบคำตอบนี้มากที่สุดเนื่องจากหลาย ๆ คน (เช่นคุณเอง) ใช้ / สำหรับทั้ง websockets และ HTTP2 ปกติ
mikemaccana

@ ใครจะเรียก Javascript ว่าอะไร?
Andrew Simpson

17

สำหรับ. net core 2.0 Nginx พร้อม 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;
}

สิ่งนี้ได้ผลสำหรับฉัน


รหัส c # คืออะไร ขณะนี้ฉันมีสิ่งนี้สำหรับ windows / iis _server = WebSocketServer ใหม่ ("wss: //0.0.0.0: 8200 / MessageRelayer") {Certificate = new X509Certificate2 (PfxFileName, SslPassword), RestartAfterListenError = true};
Andrew Simpson

ฉันใช้ SignalR
Altair CA

9

สำหรับฉันมันมาถึงการproxy_passตั้งค่าสถานที่ ฉันต้องการเปลี่ยนไปใช้โปรโตคอล HTTPS และมีการตั้งค่าใบรับรอง SSL ที่ถูกต้องบนเซิร์ฟเวอร์โหนดของสิ่งต่างๆ ด้วยวิธีนี้เมื่อฉันแนะนำเซิร์ฟเวอร์โหนดภายนอกฉันต้องเปลี่ยน IP เท่านั้นและทุกอย่างยังคงเป็น config เหมือนเดิม

ฉันหวังว่านี่จะช่วยใครบางคนระหว่างทาง ... ฉันจ้องมองปัญหาตลอดเวลา ... ถอนหายใจ ...

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

ฉันพยายามlocaltion /horizonแล้วแต่มันไม่ได้ผล เท่านั้นlocaltion /หรือใช้location /websockifyงานได้ ไม่รู้ทำไม ...
njuguoyi

6

เป็นบทความที่ดีกระชับโดย Pankaj Malhotra อธิบายถึงวิธีการทำเช่นนี้กับ NGINX และสามารถใช้ได้ที่นี่

การกำหนดค่า NGINX พื้นฐานทำซ้ำด้านล่าง:

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

1
NGINX เวอร์ชันใหม่สามารถแก้ปัญหาการหมดเวลาได้หรือไม่
crockpotveggies

3

ใช้ nginx / 1.14.0

ฉันมีเซิร์ฟเวอร์ websocket ที่ทำงานบนพอร์ต 8097 และผู้ใช้เชื่อมต่อจากเป็น wss บนพอร์ต 8098 nginx เพียงแค่ถอดรหัสเนื้อหาและส่งต่อไปยังเซิร์ฟเวอร์ websocket

ดังนั้นฉันจึงมีไฟล์กำหนดค่านี้ (ในกรณีของฉัน/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;

    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.