WebSocket Proxy 로 NGINX 사용하기

이 포스트는 WebSocket에 대한 간단한 설명과 NGINX로 WebSocket Proxy 를 구성하는 방법을 간단한 예시와 함께 설명합니다.

목차

1. 개요
2. NGINX WebSocket Proxy 구성 예시

1. 개요

WebSocket 프로토콜은 클라이언트(Client)와 서버(Server) 간의 실시간 양방향 통신을 지원하는 웹 애플리케이션을 만드는 방법을 제공합니다. HTML5의 일부인 WebSocket을 사용하면 이전에 사용 가능한 방법보다 이러한 유형의 애플리케이션을 훨씬 쉽게 개발할 수 있습니다. Chrome, Firefox, Internet Explorer, Opera 및 Safari를 포함한 대부분의 최신 브라우저는 WebSocket을 지원하며 점점 더 많은 서버 애플리케이션 프레임워크가 WebSocket도 지원하고 있습니다.


성능 및 고가용성을 위해 여러 WebSocket 서버가 필요한 엔터프라이즈 프로덕션 환경에서는 WebSocket 프로토콜을 이해하는 로드 밸런싱 레이어(Layer)가 필요합니다. NGINX는 버전 1.3부터 WebSocket을 지원하며, WebSocket 애플리케이션의 리버스 프록시 및 로드 밸런싱을 수행할 수 있습니다. (NGINX Plus의 모든 릴리스도 WebSocket을 지원합니다.)

WebSocket 프로토콜은 HTTP 프로토콜과 다르지만 WebSocket 핸드셰이크는 HTTP 업그레이드 기능을 사용하여 HTTP에서 WebSocket으로 연결을 업그레이드하여 HTTP와 호환됩니다. 이를 통해 WebSocket 애플리케이션은 기존 인프라에 보다 쉽게 맞출 수 있습니다. 예를 들어 WebSocket 애플리케이션은 표준 HTTP 포트 80 및 443을 사용할 수 있으므로 기존 방화벽 규칙을 사용할 수 있습니다.

WebSocket 애플리케이션은 클라이언트와 서버 간에 장기 실행 연결을 유지하여 실시간 애플리케이션 개발을 용이하게 합니다. HTTP에서 WebSocket으로 연결을 업그레이드하는 데 사용되는 HTTP 업그레이드 메커니즘은 업그레이드 및 연결 헤더를 사용합니다. 리버스 프록시 서버가 WebSocket을 지원할 때 직면하는 몇 가지 문제가 있습니다. 하나는 WebSocket이 홉(hop) 간 프로토콜이므로 프록시 서버가 클라이언트의 업그레이드 요청을 가로채면 적절한 헤더를 포함하여 자체 업그레이드 요청을 백엔드 서버로 보내야 한다는 것입니다. 또한 WebSocket 연결은 HTTP에서 사용되는 일반적인 단기 연결과 달리 수명이 길기 때문에 리버스 프록시는 이러한 연결이 유휴 상태인 것처럼 보이기 때문에 닫는 것이 아니라 열린 상태로 유지되도록 허용해야 합니다.

NGINX는 클라이언트와 백엔드 서버 간의 터널을 설정하여 WebSocket을 지원합니다. 클라이언트에서 보낸 Upgrade 요청을 백엔드 서버로 전달하기 위해 NGINX는 Upgrade 및 Connection 헤더를 명시적으로 설정해야 합니다. 다음은 그 예시입니다:

location /wsapp/ {
    proxy_pass http://wsbackend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
}

이 작업이 완료되면 NGINX는 이를 WebSocket 연결로 처리합니다.

2. NGINX WebSocket Proxy 구성 예시

다음은 WebSocket Proxy 로 작동하는 NGINX를 보여주는 라이브 예입니다. 이 예제에서는 Node.js에 구축된 WebSocket 구현인 ws를 사용합니다. NGINX는 ws 및 Node.js를 활용하는 간단한 WebSocket 애플리케이션의 리버스 프록시 역할을 합니다. 이 지침은 Ubuntu 13.10 및 CentOS 6.5에서 테스트되었지만 다른 OS 및 버전에 맞게 조정해야 할 수도 있습니다. 이 예에서 WebSocket 서버의 IP 주소는 192.168.100.10이고 NGINX 서버의 IP 주소는 192.168.100.20입니다.

1. Node.js 및 npm 설치하기

  • Ubuntu/Debian:
$ sudo apt-get install nodejs npm
  • RHEL/CentOS:
$ sudo yum install nodejs npm

2. Node.js는 우분투에서는 nodejs로, CentOS에서는 노드로 설치됩니다. 예제에서는 노드를 사용하므로 Ubuntu에서 nodejs에서 노드로의 심볼릭 링크를 만들어야 합니다.

$ ln -s /usr/bin/nodejs /usr/local/bin/node

3. ws 설치하기

$ sudo npm install ws

참고: “오류: 레지스트리에서 가져오지 못했습니다: ws”라는 오류 메시지가 표시되면 다음 명령을 실행하여 문제를 해결하십시오.

$ sudo npm config set registry http://registry.npmjs.org/

4. ws는 클라이언트에 사용할 /root/node_modules/ws/bin/wscat 프로그램과 함께 제공되지만 서버 역할을 할 프로그램을 만들어야 합니다. 다음 내용으로 server.js라는 파일을 만듭니다.

console.log("Server started");
var Msg = '';
var WebSocketServer = require('ws').Server
    , wss = new WebSocketServer({port: 8010});
    wss.on('connection', function(ws) {
        ws.on('message', function(message) {
        console.log('Received from client: %s', message);
        ws.send('Server received from client: ' + message);
    });
 });

5. 서버 프로그램을 실행하려면 다음 명령을 실행하십시오.

$ node server.js

6. 서버는 초기 “Server started” 메시지를 출력하고 포트 8010에서 클라이언트가 연결될 때까지 대기합니다. 클라이언트 요청을 받으면 해당 요청을 되돌리고 수신한 메시지를 포함하는 메시지를 클라이언트에게 보냅니다. 이러한 요청을 NGINX 프록시로 전달하려면 다음 구성을 만듭니다. Connection 헤더가 요청의 Upgrade 헤더가 ”로 설정되었을 때 올바르게 close로 설정되도록 map 블록을 추가합니다.

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }
 
    upstream websocket {
        server 192.168.100.10:8010;
    }
 
    server {
        listen 8020;
        location / {
            proxy_pass http://websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header Host $host;
        }
    }
}

NGINX는 포트 8020에서 수신하고 백엔드 WebSocket 서버에 요청을 프록시합니다. proxy_set_header 지시문을 사용하면 NGINX가 WebSocket 프로토콜을 올바르게 처리할 수 있습니다.

7. 서버를 테스트하기 위해 wscat을 클라이언트로 실행합니다.

$ /root/node_modules/ws/bin/wscat --connect ws://192.168.100.20:8020

wscat은 NGINX 프록시를 통해 WebSocket 서버에 연결합니다. wscat이 서버로 보낼 메시지를 입력하면 서버에서 메시지가 반향된 다음 서버의 메시지가 클라이언트에 나타납니다. 샘플 상호 작용은 다음과 같습니다.

여기서 우리는 클라이언트(Client)와 서버(Server)가 프록시 역할을 하는 NGINX를 통해 통신할 수 있고 클라이언트나 서버의 연결이 끊어질 때까지 메시지를 계속 주고받을 수 있음을 알 수 있습니다. NGINX가 WebSocket을 제대로 처리하도록 하려면 헤더를 올바르게 설정하여 HTTP에서 WebSocket으로 연결을 업그레이드하는 업그레이드 요청을 처리하기만 하면 됩니다.

NGINX Plus를 직접 사용해 보시려면 30일 무료 평가판을 신청하거나 NGINX STORE에 연락하여 문의하십시오.

사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.