OpenVPN UDP를 위한 Nginx stream 릴레이: 무엇이 달라지는가
UDP는 HTTP location에 속하지 않는다. stream 계층으로 옮기고, VPN에 맞게 세션 시간 제한을 정하고, 프록시가 출발지가 된다는 점을 예상하라.
클라이언트는 UDP로 설정되어 있고, Nginx 서버에는 VPN 포트를 가리키는 location 블록이 있으며, 아무것도 도착하지 않는다. 이는 예상된 일이다: HTTP location은 UDP 데이터그램을 운반할 수 없다, 그 이름이 무엇이든 마찬가지다. 이를 위해 Nginx에는 stream 리스너가 필요하고, 구성을 그쪽으로 옮기면 세션이 살아남을지를 세부 사항의 두 번째 묶음이 결정한다.
프록시 계층이 주소보다 먼저 온다
Nginx의 stream 모듈은 HTTP를 파싱하지 않고 TCP와 UDP를 프록시한다. HTTP 모듈은 요청 줄, 헤더, 응답을 기대하는데 그중 어느 것도 네이티브 OpenVPN 데이터그램에는 없다. 따라서 계층 선택이 첫 번째 결정이며, 리스너가 IPv4인지 IPv6인지와는 무관하다.
TCP OpenVPN에서 작동하는 것처럼 보이는 구성은 UDP의 경우에 대해 아무 말도 하지 않는다. 여기서 전송은 프로토콜의 일부이지 배포의 세부 사항이 아니다.
리스너와 백엔드
nginx -V 2>&1 | tr ' ' '\n' | grep stream
stream {
server {
listen [::]:1194 udp reuseport;
proxy_pass [2001:db8::20]:1194;
}
}
무엇이든 편집하기 전에 빌드에 stream 모듈이 포함되어 있는지 확인하라: 배포 패키지가 이를 별도 모듈로 나눌 수 있고, 모듈이 없으면 터널이 아니라 구성 오류가 발생한다. 블록은 기본 구성 컨텍스트에 두고 http 안에는 두지 말며, 문서용 주소는 실제 백엔드로 바꿔라.
두 경로와 두 방화벽 모두 데이터그램을 허용해야 한다: 리스너까지의 경로와 프록시에서 백엔드까지의 경로다. IPv6 리스너는 IPv4 경로를 만들지 않으므로, 일부 클라이언트가 여전히 IPv4를 쓴다면 그 리스너는 자체 테스트를 가진 별도 항목이다. 백엔드 자체의 방화벽은 노트북이 아니라 프록시의 주소에서 확인하라.
세션 시간 제한은 요청 시간 제한이 아니다
stream 프록시는 UDP 세션의 상태를 유지하고 자신의 시간 제한과 응답 설정에 따라 이를 버린다. DNS 릴레이에서 복사한 짧은 시간 제한은 몇 시간 동안 데이터그램을 교환하려는 VPN에 잘 맞지 않으며, 장애는 시작을 거부하는 연결이 아니라 조용히 죽는 연결로 나타난다.
배포의 실제 proxy_timeout 과 응답 개수 설정을 읽고, VPN이 실제로 사용하는 keepalive 동작과 비교하라. 서로 다른 사람이 서로 다른 파일에 쓴 두 숫자는 작동하는 시스템의 정상 상태다. 한 번도 비교하지 않은 두 숫자는 간헐적으로 멈추는 시스템의 정상 상태다. 비교가 한 번, 대낮에 이루어지도록 둘 다 서비스 기록에 적어라.
릴레이가 바꾸는 것과 바꾸지 않는 것
stream 프록시는 OpenVPN의 TLS 제어 채널을 종료하지 않고 HTTPS로 변환하지도 않는다. 백엔드는 VPN 서비스로 남고, 인증서 관계는 클라이언트와 그 서비스 사이에 남는다. 의도된 백엔드 정체성을 유지하는 것은 여전히 클라이언트와 서버의 일이다.
일반적인 프록시는 백엔드가 보는 출발지 주소도 바꾼다. 로그에는 프록시가 나타나고, VPN 서버의 IP 기반 접근 규칙은 클라이언트가 아니라 그 주소를 평가한다. 출발지를 투명하게 보존하는 것은 별도의 라우팅과 권한 설계이며, 리스너에 udp 를 추가해서 생기는 일이 아니다. 클라이언트 주소에 의존하는 정책을 쓰기 전에 계획하라.
포트가 아니라 클라이언트에서 검증하라
UDP 포트가 열려 있다는 로컬 확인은 리스너가 존재함을 증명한다. 클라이언트가 그를 통해 인증하거나 트래픽을 계속 교환할 수 있음을 증명하지는 않는다. 승인된 클라이언트에서 실제 연결을 완료한 뒤, 세션이 의미 있을 만큼 충분히 오래 유지되는지 확인하라.
누군가 Nginx가 UDP를 할 수 없다고 보고하면서 그 대신 간단한 릴레이 도구가 작동했다고 말한다면, 그 두 사실은 무관하다. 그 도구는 백엔드가 응답한다는 것을 증명했을 뿐, 프런트 엔드가 무엇을 지원하는지는 말하지 않았다. 둘 다 사실일 수 있고, 이 배포를 위한 구성은 그중 하나뿐이다.