https에 대한 "기본"nginx 서버를 올바르게 설정


70

동일한 컴퓨터에서 여러 서버를 실행하고 있으며 일부는 http 만 있고 일부는 http와 https가 있습니다. 기본 구성 파일에서 포함 된 별도의 파일에 여러 서버 블록이 정의되어 있습니다.

다른 구성 파일의 다른 server_names와 일치하지 않는 요청에 일반 "유지 관리 페이지"를 제공하는 http 용 "기본"서버를 설정했습니다. http 기본 서버는 예상대로 작동하고 server_name "_"을 사용하며 포함 목록에서 첫 번째로 나타납니다 (서버에서 중복 된 server_name이 처음 나타나는 서버가 사용되는 것을 관찰했기 때문에). 이것은 잘 작동합니다.

나는 동일한 정확한 서버 블록 ( "listen 80 default_server"를 "listen 443 default_server"로 전환하고 페이지 "return 444"를 대신하는 것만)을 기대하지만 그렇지 않습니다. 대신 새 기본 https 서버가 들어오는 모든 https 연결을 실제로 가져 와서 실패하게 만드는 것처럼 보이지만 다른 서버 블록에는 들어오는 요청에 더 적합한 server_name이 있습니다. 새로운 기본 https 서버를 제거하면 반 올바른 동작이 다시 시작됩니다. https가있는 웹 사이트는 모두 올바르게로드됩니다. 그러나 https가없는 웹 사이트는 모두 포함 파일의 첫 번째 https 서버로 라우팅됩니다 (문서에 따라 "default_server"가 나타나지 않으면 나타나는 첫 번째 서버 블록은 "default"입니다).

그래서 내 질문은 SSL 연결을 위해 nginx에서 "기본 서버"를 정의하는 올바른 방법은 무엇입니까? 내가 명시 적으로 "default_server"를 설정하면 욕심이 생기고 모든 연결을 잡는 반면 nginx가 "기본 서버"를 암시 적으로 결정할 때 예상대로 작동합니다 (잘못된 서버를 기본값으로 설정하고 다른 실제 서버로 설정) 올바르게 동작)?

여기에 "기본 서버"가 있습니다. Http는 다른 서버를 손상시키지 않고 작동합니다. Https는 다른 서버를 중단하고 모두 사용합니다.

server {
    listen 443 ssl default_server;
    server_name _;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    return 444;
}

server {
    listen *:80 default_server;
    server_name _;
    charset utf-8;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    root /home/path/to/templates;

    location / {
        return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /maintenance.html break;
    }
}

여기에 무엇이 잘못 되었습니까?

ssl  https  nginx 

답변:


27

"default"https 블록에 정의 된 ssl_certificate 또는 ssl_certificate_key가 없습니다. 이 기본 시나리오에 대해 실제 키가 없거나 원하지 않더라도 하나를 구성해야합니다. 그렇지 않으면 nginx가 사용자가 설명하는 원하지 않는 동작을 갖습니다.

Common Name *으로 자체 서명 된 인증서를 작성하고 구성에 연결하면 원하는대로 작동하기 시작합니다.

이 설정에서 "기본"동작은 브라우저가 인증서를 신뢰할 수 없다는 경고를 받고, 사용자가 인증서를 예외로 추가하면 nginx에 의해 연결이 끊어지고 브라우저의 기본값을 보게됩니다. "연결할 수 없습니다"오류 메시지.


1
나는 이것을 시도했지만 여전히 작동하지 않습니다 : IP에 대한 모든 ssl 요청은 다른 ssl 호스트로 이동합니다. 내가 시도 할 수있는 다른 것이 있습니까?
Michael Härtl

22

nginx를 사용하여 단일 IP에서 공유 전용 호스팅을 구성했습니다. 알 수없는 도메인이 들어오는 경우 404를 제공하는 기본 HTTP 및 HTTPS입니다.

1-기본 영역 만들기

nginx가 가상 호스트를 ASCII 순서로로드 할 때에 00-default파일 / 기호 링크를 작성해야 합니다 /etc/nginx/sites-enabled.

2-기본 영역을 채 웁니다

당신의 채우기 00-default기본 가상 호스트와 함께. 내가 사용하는 영역은 다음과 같습니다.

server {
    server_name _;
    listen       80  default_server;
    return       404;
}


server {
    listen 443 ssl;
    server_name _;
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    return       404;
}

3-자체 서명 된 인증서 생성, 테스트 및 다시로드

에 자체 서명 인증서를 작성해야합니다 /etc/nginx/ssl/nginx.crt.

기본 자체 서명 인증서를 작성하십시오.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

알림 :

  • 다시로드 / 다시 시작하기 전에 nginx 구성을 테스트하십시오. nginx -t
  • 즐기십시오 : sudo service nginx reload

도움이 되길 바랍니다.


2
안전하지 않은 사이트를 방문하는 브라우저 경고를 해결하지 않습니다.
gdbj

4
포괄은 도메인과 일치해야하므로 해결할 수 없습니다. SSL은 모든 도메인을 와일드 카드 할 수 없습니다. 서버에서 google.fr 주소를 스푸핑한다고 가정하면 서버를 google.fr로 인증 할 수 있습니다. 심각한 보안 문제가 될 것입니다 :(
If not if

나중에 말이되는 것 같습니다. 불행히도 Chrome에서는 서버가 단순히 트래픽을 거부하는 것보다 나쁜 404 페이지를보기 전에 무서운 경고가 표시됩니다. 서버가 잘못 구성된 것처럼 보이게합니다.
gdbj

대단히 감사합니다. 이것은 default_server청취 443을 추가해야하고 IPv6 주소 [::] : 80 및 [::] : 443 을 추가했다는 점을 제외하고는 나를 위해 일했습니다 default_server.
chmike

16

기본적으로 구성 파일의 첫 번째 서버 정의가 SSL 연결을위한 범용 서버로 제공되는 것을 피하고 싶습니다. 우리는 그것이 그렇게한다는 것을 알고 있습니다 (http와는 반대로 작동하는 default_server 구성 사용).

SSL에 대해서는 선언적으로 달성 할 수 없으므로 IF로 코딩해야합니다 ...

변수 $host는 요청 라인 또는 http 헤더의 호스트 이름입니다. 변수 $server_name는 현재 우리가 보유한 서버 블록의 이름입니다.

따라서이 둘이 동일하지 않으면 다른 호스트에 대해이 SSL 서버 블록을 제공 했으므로 차단해야합니다.

이 코드에는 서버 IP 주소에 대한 특정 참조가 포함되어 있지 않으므로 수정없이 다른 서버 구성에 쉽게 재사용 할 수 있습니다.

예:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ###
    ### Section: SSL

    #
    ## Check if this certificate is really served for this server_name
    ##   http://serverfault.com/questions/578648/properly-setting-up-a-default-nginx-server-for-https
    if ($host != $server_name) {
        #return 404 "this is an invalid request";
        return       444;
    }

    ...

당신은 무엇을 설명 할 수 listen [::]:443 ssl http2;있습니까? 문서를 찾는 데 문제가 있습니다.
Andrew Brown

내가 찾은 것만으로 무엇을 검색해야하는지 알 필요가있었습니다. IPV4 및 IPV6 지시문.
Andrew Brown

7

Radmilla Mustafa의 답변에 대해 자세히 설명하려면 다음을 수행하십시오.

Nginx는 server_name 일치를 위해 'Host'헤더를 사용합니다. TLS SNI를 사용하지 않습니다. 이는 SSL 서버의 경우 nginx가 SSL 연결을 수락 할 수 있어야하며 이는 인증서 / 키를 갖는 것으로 요약됩니다. 인증서 / 키는 예를 들어 자체 서명 된 것일 수 있습니다.

설명서 참조

따라서 해결책은 다음과 같습니다.

server {
    server_name _;
    listen 80 default_server;
    listen 443 ssl default_server;

    ## To also support IPv6, uncomment this block
    # listen [::]:80 default_server;
    # listen [::]:443 ssl default_server;

    ssl_certificate <path to cert>;
    ssl_certificate_key <path to key>;
    return 404; # or whatever
}

나는 이것이 받아 들여야 할 답변이라고 생각합니다. 많은 감사합니다.
집합

2

나만큼이 머리카락을 잃은 사람에게 (오늘은 거의 하루 종일 보냈다). 나는 거의 모든 것을 시도했지만 마침내 올바르게 작동하게 된 것은 다음과 같은 어리석은 선이었습니다.

ssl_session_tickets off;

Ifnot 의 답변 을 바탕으로 내 작업 예는 다음과 같습니다.

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_session_tickets off;

    return 404;
}

이것이 왜 필요한지 전혀 몰랐습니다. 이로부터 파생 된 유일한 원칙은 nginx가 우리가 원하는 것을주지 않으면 매우 이상하게 행동한다는 것입니다.


1
당신은 전설입니다.
Nizar Blond

1

확실하게 확인하려면 HTTPS에서 응답하지 않아야하는 호스트와 호스트에 대해 별도의 IP 주소를 사용하십시오. 또한 "잘못된 인증서"브라우저 경고 문제도 해결됩니다.

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