nginx가있는 단일 포트를 사용하여 http 및 https 요청 처리


16

nginx가 동일한 포트에서 http 및 https 요청을 처리 할 수 ​​있는지 궁금합니다 . [*]

이것이 내가하려고하는 일입니다. http 요청을 처리하는 웹 서버 (lighttpd)와 https를 통해 문서 트리의 특정 섹션을 제공하는 C 프로그램을 실행하고 있습니다. 이 두 프로세스는 동일한 서버에서 실행됩니다.

방화벽 수준 에서이 서버로 트래픽을 전달하는 포트는 하나만있을 수 있습니다 . 그래서 내가하고 싶은 것은이 서버에서 nginx를 설정하여 단일 포트에서 요청을 수신 한 다음에

A) 모든 http://myhost.com/ * 요청을 리디렉션 하여 localhost : 8080 (lighttpd가 청취하는 곳)으로 이동합니다.

B) 사용자가 예를 들어 https : // myhost.com/app로 시작하는 URL을 요청하면 해당 요청을 localhost : 8008 (C 프로그램)로 보냅니다. 이 경우 원격 브라우저와 nginx 간의 트래픽을 암호화해야합니다.

이것이 가능하다고 생각하십니까? 그렇다면 어떻게 할 수 있습니까?

두 개의 다른 포트를 사용 하여이 작업을 수행하는 방법을 알고 있습니다. 내가 직면 한 도전은 단 하나의 포트 로이 작업을 수행하는 것입니다 (불행히도이 특정 환경에서 방화벽 구성을 제어 할 수 없으므로 피할 수없는 제한 사항입니다). 방화벽을 우회하기 위해 ssh를 통한 역방향 포트 포워딩과 같은 기술을 사용하는 것도 작동하지 않습니다. 웹 브라우저와 인터넷 링크에 불과한 원격 사용자에게는 작동하지 않기 때문입니다.

이것이 nginx 기능을 넘어 서면이 요구 사항을 충족시킬 수있는 다른 제품에 대해 알고 있습니까? (지금까지는 lighttpd와 pound으로 이것을 설정하는데 실패했습니다). 또한 Apache를 피하는 것이 좋습니다 (유일한 선택 인 경우 Apache를 기꺼이 사용하지만).

미리 감사드립니다, 알렉스

[*] 명확하게 말하자면, 같은 포트를 통해 암호화 암호화되지 않은 HTTP 연결을 처리하는 것에 대해 이야기하고 있습니다. 암호화가 SSL 또는 TLS를 통해 수행되는지는 중요하지 않습니다.


HTTPS 요청은 기본적으로 포트 443으로 이동하므로이 작업을 수행 할 수 있다고해도 (그리고 약간의 해커로 가능하다고 생각하더라도) yourhost.comyourhost.com:80 을 링크 (또는 yourhost.com:443yourhost.com ).
Zanchey

좋아, 나는 서버 결함에 새로운 사람이고 내 자신의 질문을 삭제할 수 있는지 모르겠습니다. 문제가 명확하게 공식화되지 않은 것 같습니다. 대신 새로운 질문을 드리겠습니다. 어쨌든이 문제에 대한 유용한 제안을 해주신 모든 분들께 감사드립니다.
alemartini

답변:


18

상태 코드에 대한 Wikipedia 기사에 따르면 Nginx에는 http 트래픽이 https 포트로 전송되면 사용자 정의 오류 코드가 있습니다 (오류 코드 497)

error_page의 nginx 문서에 따르면 특정 오류에 대해 표시되는 URI를 정의 할 수 있습니다.
따라서 오류 코드 497이 발생하면 클라이언트가 전송 될 URI를 만들 수 있습니다.

nginx.conf

#lets assume your IP address is 89.89.89.89 and also that you want nginx to listen on port 7000 and your app is running on port 3000

server {
    listen 7000 ssl;

    ssl_certificate /path/to/ssl_certificate.cer;
    ssl_certificate_key /path/to/ssl_certificate_key.key;
    ssl_client_certificate /path/to/ssl_client_certificate.cer;

    error_page 497 301 =307 https://89.89.89.89:7000$request_uri;

    location / {
        proxy_pass http://89.89.89.89:3000/;

        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
}

그러나 클라이언트가 GET을 제외한 다른 방법을 통해 요청하면 해당 요청은 GET으로 바뀝니다. 따라서 클라이언트가 들어오는 요청 방법을 보존합니다. error_page의 nginx 문서에 표시된대로 오류 처리 리디렉션을 사용합니다.

그래서 우리는 301 =307 리디렉션 입니다.

여기에 표시된 nginx.conf 파일을 사용하여 http 및 https가 동일한 포트에서 청취되도록 할 수 있습니다


17

검색하는 사람들을 위해 :

추가 ssl on;error_page 497 $request_uri;서버 정의.


8
HoverHells 리틀 개선 답 : 추가 ssl on;error_page 497 =200 $request_uri;서버 정의에. 상태 코드가 200으로 변경됩니다.
Mawi12345

이 서빙 오류 응답은 이 솔루션이 작동하는 이유를 설명합니다.
SiliconMind

4

정말로 영리하고 싶다면 연결 프록시를 사용하여 들어오는 데이터 스트림의 첫 두 바이트를 스니핑하고 바이트 0의 내용을 기반으로 연결을 전달하십시오 .0x16 인 경우 (SSL / TLS ' 핸드 셰이크 바이트), SSL 측에 연결을 전달하십시오 (알파벳 문자 인 경우 일반 HTTP 수행). 포트 번호에 대한 나의 의견이 적용됩니다 .


2

예, 가능하지만 nginx 소스 코드를 패치해야합니다 (HoverHell은 패치없이 솔루션을 제공합니다). Nginx는 이것을 유효한 구성보다는 잘못된 구성으로 취급합니다.

$ ssl_session_id 변수를 사용하여 일반 연결과 ssl 연결을 구별 할 수 있습니다.

nginx-0.7.65에 대한 패치 :

--- src/http/ngx_http_request.c-orig    2011-05-03 15:47:09.000000000 +0200
+++ src/http/ngx_http_request.c 2011-05-03 15:44:01.000000000 +0200
@@ -1545,12 +1545,14 @@

    c = r->connection;

+    /* disable plain http over https port warning
     if (r->plain_http) {
         ngx_log_error(NGX_LOG_INFO, c->log, 0,
                       "client sent plain HTTP request to HTTPS port");
         ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS);
         return;
     }
+    */

#if (NGX_HTTP_SSL)

서버 설정 :

server {
    listen 80;
    index index.html;

    location / {
        root html;
        if ($ssl_session_id) {
            root html_ssl;
        }
    }

    ssl on;
    ssl_certificate cert.crt;
    ssl_certificate_key cert.key;
}

1

단일 포트에서 서로 다른 두 가지 프로토콜을 처리 할 수있는 것은 없다고 생각합니다.

나는 왜 당신이 하나의 포트 만 전달할 수 있는지 궁금하지만 그 옆에 ... 그것은 이상적이지는 않지만 내가 당신의 신발에 있다면 https를 통해 모든 것을 제공 할 것입니다.


윌 안녕, 답변 주셔서 감사합니다! https를 통해 모든 것을 제공하는 것이 옵션 일 수 있다고 생각하지만, 내가 설명한 방식으로 이것을 설정하고 싶습니다. 전면 웹 서버 (역 프록시로 작동)가 정상적인 http 세션을 설정 한 다음 포트를 변경하지 않고 https로 업그레이드 할 수있는 경우이 작업을 수행 할 수 있습니다. 이 동작은 RFC2817 (HTTP / 1.1을 사용하는 TLS로 업그레이드)에 설명되어 있지만 nginx 또는 다른 웹 서버가 해당 표준을 처리하는 방법을 알고 있는지 잘 모르겠습니다.
alemartini

나는 전체 RFC를 읽을 시간이 없지만 (그리고 그것을 이해할만큼 똑똑하지는 않습니다!) 보안 세션이 설정되거나 다른 세션을 완전히 시작하기 전에 표준 협상에 대해 이야기하고 있습니까? 서버가 두 개의 포트에서 서비스를 제공하고 있으며 요청을 나타내는 프록시입니다. 멋지게 들리지만 결코 본 적이 없습니다. 아마도 하나의 포트에 단일 보안 사이트를 만들고 다른 웹 사이트를 단순히 상속 / 가져 오는 전체 가상 디렉터리를 갖는 것이 해결책 일 수 있습니까? 그것은 모든 문제를 극복하지는 못하지만 효과가 있습니다 : S
William Hilsum

1

연결의 양쪽 끝이 특정 언어를 사용하기를 기대하고 다른 쪽 끝이 다른 것을 말하고있을 때 그것들이 충분히 영리하지 않기 때문에 동일한 포트를 통해 HTTP와 HTTPS를 모두 지원할 수 없습니다.

Wil의 답변에 대한 귀하의 의견에서 제안한 것처럼 TLS 업그레이드를 사용할 있습니다 (나는 시도하지 않았지만 최신 nginx 릴리스가 지원한다고 생각합니다).하지만 HTTP 및 HTTPS를 실행하지 않고 TLS 업그레이드로 HTTP를 실행합니다. 문제는 여전히 브라우저 지원입니다. 대부분의 브라우저는 (아직도) 지원하지 않습니다. 그러나 제한된 클라이언트 풀이 있다면 이것이 가능합니다.


1
암호화 및 암호화되지 않은 HTTP 트래픽은 단일 포트를 통해 처리 할 수 ​​있습니다. 내가 알고 싶은 것은 nginx 또는 리버스 프록시 역할을하는 다른 제품 (lighttpd와 같은)을 사용하여 이것이 가능한지 여부입니다. 아마도 이런 종류의 설정은 Apache에서 처리 할 수 ​​있지만 Apache를 사용하지 않아도되는 원래의 질문에서 언급하지 않았습니다 (Linux에서 다른 선택이 없다면 할 수도 있지만) 이것을 달성하는 플랫폼).
alemartini

내 대답에서 말했듯이 "나는 시도하지 않았지만 최신 nginx 릴리스 지원 [TLS 업그레이드]을 믿습니다." 매뉴얼을 읽어야한다면 운이 나쁘다.
womble

설명서를 읽을 사람이 필요하다는 인상을 주면 죄송합니다. 문제 (및 그것에 대한 질문)가 정확하게 (내 실수) 충분히 설명되어 있지 않아서 내가 요청하거나 필요로하는 것에 대한 다른 해석으로 이어졌습니다. 그래서 나는이 문제에 관한 새로운 질문을 열고 문제 또는 그것에 관한 특정 질문과 관련하여 가능한 혼란을 피하려고 노력했습니다. 어쨌든 시간을 내 주셔서 감사합니다.
alemartini

0

어떻게 풀릴 지 잘 모르겠지만 CUPSD는 포트 631에서 http와 https에 모두 응답합니다. nginx가 지금 그렇게 할 수 없다면 CUPS 팀이 어떻게 그것을 풀 수 있는지 알 수 있지만 CUPS는 GPL, 따라서 nginx는 그러한 기능을 구현하고 다른 곳에서 코드를 찾을 수없는 경우 라이센스 변경을 검토해야 할 수도 있습니다.


0

이론적으로 HTTP를 통해 액세스 할 수있는 웹 페이지를 가질 수 있습니다.이 페이지는 https : 443에서 원하는 위치로 WebSocket 을 열 수 있습니다. WebSocket 초기 핸드 셰이크는 HTTP입니다. 따라서 안전하지 않은보기 페이지를 실제로 안전하게 통신 할 수 있습니다. Netty Library 로이 작업을 수행 할 수 있습니다 .


0

이것은 1.15.2부터 올바르게 수행하는 것이 가능합니다. 여기 에서 정보를 참조 하십시오 .

nginx.conf에서 다음과 같은 블록을 추가하십시오 (http 블록 외부).

stream {
    upstream http {
        server localhost:8000;
    }

    upstream https {
        server localhost:8001;
    }

    map $ssl_preread_protocol $upstream {
        default https;
        "" http;
    }

    server {
        listen 8080;
        listen [::]:8080;
        proxy_pass $upstream;
        ssl_preread on;
    }
}

그런 다음 일반 서버 블록을 만들 수 있지만 다음과 같은 다른 포트에서 수신 대기 할 수 있습니다.

server {
    listen 8000;
    listen [::]:8000;
    listen 8001 ssl;
    listen [::]:8001 ssl;
...

이런 식으로 스트림 블록은 TLS인지 여부를 미리 읽고 (이 예제의 포트 8080에서) 프록시가이를 올바른 서버 포트에 로컬로 전달합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.