nginx 리버스 프록시로 암호화 가능


45

소개

나는 dev 서버 (현재 Ubuntu 14.04 LTS를 실행 중)를 가지고 있으며, 다른 포트에서 다양한 개발 도구를 호스팅하기 위해 오랫동안 사용 해 왔습니다. 포트를 기억하기 어려울 수 있으므로 모든 서비스에 포트 80을 사용하고 호스트 이름을 기준으로 내부적으로 포트 전달을 수행하기로 결정했습니다.

domain.com:5432를 쓰는 대신 sub.domain.com을 통해 간단히 액세스 할 수 있습니다.

예를 들어 포트 7547을 사용하고 sub.domain.com에서 실행중인 응용 프로그램 X는 다음과 같은 nginx 구성을 갖습니다.

upstream sub {
    server 127.0.0.1:7547;
}

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    access_log /var/log/nginx/sub.log combined;
    location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:7547;
            proxy_set_header Authorization "";
    }
}

질문

내가 선택한 현재 구성 구조를 감안할 때 letsencrypt를 사용하고 https에서 다른 서비스를 실행할 수 있습니까?


3
이 주제에 대한 블로그 게시물을 작성했습니다. tom.busby.ninja/letsecnrypt-nginx-reverse-proxy-no-downtime
Tom Busby

답변:


81

예, HTTP 서버에 nginx 프록시 요청을 한 다음 HTTPS를 통해 클라이언트에 응답 할 수 있습니다. 이 작업을 수행 할 때 예상 공격자가 누구인지 nginx <-> proxy connect가 스니핑되지 않도록해야합니다. 충분히 안전한 접근 방식 다음과 같습니다.

  • 같은 호스트에 프록시하기
  • 방화벽 뒤의 다른 호스트에 프록시

공용 인터넷의 다른 호스트에 프록시하는 것이 안전하지 않을 수 있습니다.

프록시로 사용하는 것과 동일한 웹 서버를 사용하여 Let 's Encrypt 인증서를 얻는 방법은 다음과 같습니다.

Let 's Encrypt에서 초기 인증서 요청

server하위 디렉토리 .well-known를 로컬 디렉토리에서 제공 할 수 있도록 절을 수정하십시오 . 예 :

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    […]
    location /.well-known {
            alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here
        […]
    }
}

http://sub.domain.com/.well-known Let 's Encrypt 서버가 문제에 대한 답을 찾습니다.

그런 다음 certbot 클라이언트를 사용하여 웹 루트 플러그인 (루트로)을 사용하여 Let 's Encrypt에서 인증서를 요청할 수 있습니다 .

certbot certonly --webroot -w /var/www/sub.domain.com/ -d sub.domain.com -d www.sub.domain.com

키, 인증서 및 인증서 체인이 이제 /etc/letsencrypt/live/sub.domain.com/

인증서를 사용하도록 nginx 구성

먼저 다음과 같이 새 서버 절을 작성하십시오.

server {
    listen 443 ssl;

    # if you wish, you can use the below line for listen instead
    # which enables HTTP/2
    # requires nginx version >= 1.9.5
    # listen 443 ssl http2;

    server_name sub.domain.com www.sub.domain.com;

    ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;

    # Turn on OCSP stapling as recommended at 
    # https://community.letsencrypt.org/t/integration-guide/13123 
    # requires nginx version >= 1.3.7
    ssl_stapling on;
    ssl_stapling_verify on;

    # Uncomment this line only after testing in browsers,
    # as it commits you to continuing to serve your site over HTTPS
    # in future
    # add_header Strict-Transport-Security "max-age=31536000";

    access_log /var/log/nginx/sub.log combined;

    # maintain the .well-known directory alias for renewals
    location /.well-known {
        alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here as in your port 80 configuration
        […]
    }
}

nginx를 다시로드하십시오 :

service nginx reload

HTTPS 지금 방문하여 작동하는지 확인 https://sub.domain.com하고 https://www.sub.domain.com브라우저 (및 지원에 특별히 원하는 다른 브라우저) 그들이 인증서 오류를보고하지 않음을 확인합니다.

권장 사항 : raygin.org : nginx의 강력한 SSL 보안을 검토 하고 SSL Labs 에서 구성을 테스트하십시오 .

(권장) HTTP 요청을 HTTPS로 리디렉션

https://일부 사용자가로 http://sub.domain.com이동하여 안전하지 않은 콘텐츠를 제공 한 것이 아니라 사이트 가 URL 버전으로 작동하는 것으로 확인되면 사이트 의 HTTPS 버전으로 리디렉션합니다.

전체 포트 80 server절을 다음으로 바꾸십시오.

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    rewrite     ^   https://$host$request_uri? permanent;
}

또한 포트 443 구성에서이 행의 주석을 해제해야 브라우저에서 HTTP 버전의 사이트를 시도하지 않아도됩니다.

add_header Strict-Transport-Security "max-age=31536000";

인증서 자동 갱신

이 명령을 루트로 사용하여 certbot에 알려진 모든 인증서를 갱신하고 기존 인증서와 동일한 경로를 갖는 새 인증서를 사용하여 nginx를 다시로드 할 수 있습니다.

certbot renew --renew-hook "service nginx reload"

certbot은 60 일이 지난 인증서 만 갱신하려고 시도하므로 가능하면이 명령을 매우 정기적으로 자동 으로 실행하는 것이 안전합니다 (권장됩니다!) . 예를 들어 다음 명령을 넣을 수 있습니다 /etc/crontab.

# at 4:47am/pm, renew all Let's Encrypt certificates over 60 days old
47 4,16   * * *   root   certbot renew --quiet --renew-hook "service nginx reload"

건식 실행으로 갱신을 테스트 할 수 있으며, Let 's Encrypt 준비 서버에 연결하여 실제 도메인에 연결하는 테스트를 수행하지만 결과 인증서 저장 하지 않습니다 .

certbot --dry-run renew

또는 다음을 통해 조기 갱신을 강요 할 수 있습니다.

certbot renew --force-renew --renew-hook "service nginx reload"

참고 : 원하는 횟수만큼 드라이 런을 수행 할 수 있지만 실제 갱신에는 Let 's Encrypt rate limit의 적용을받습니다 .


귀하의 솔루션이 나를 위해 작동하지 않는 것 같습니다. 기본적으로 동일한 구성이 있습니다. goopen.tk에서는 작동하지만 www.goopen.tk에서는 작동하지 않음
Alko

3
@ Alko, 답변의 지침이 정확 하며이 문제를 다루십시오. 사용하는 경우 certbot또는 다른 도구, 당신은 일에 모두 WWW와 www가 아닌 형식으로 도메인을 지정하는 것을 잊지 수 있습니다.
Paulo Coghi

아래는 location /.well-known, 당신은 떠날 필요가 .well-known경로에서. 사용alias /var/www/sub.domain.comalias /var/www/sub.domain.com/.well-known
gldraphael

1
"rewrite ^ https : // $ host $ request_uri? permanent;"를 사용하려는 이유를 누구나 설명해 줄 수 있습니까? "301 https : // $ server_name $ request_uri;"대신에 여기
ZaxLofful

나는 경로에 따옴표가 필요하다는 것을 알았습니다. location '/.well-known' {. 이것이 버전인지 또는 내 설정인지 확실하지 않지만 다른 사람이 갇힌 경우를 대비하여.
Frank V

2

예, nginxhttps의 끝점으로 사용 하고 http를 통해 백엔드와 협력 할 수 있습니다 . 예를 들어 내 구성 :

server {
        server_name host;
        listen 443 ssl;
...
 location /svn/ {
            auth_ldap off;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_pass http://localhost:1080/svn/;
            proxy_redirect http://localhost:1080/ https://host/;
        }
...
}

그러나 아시다시피, 암호화를 사용하면 인증서를 얻을 때 모든 하위 도메인을 가리켜 야하며 이것이 문제가되면 https://host/service대신 URL을 선택하십시오.https://service.host

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