Nginx에서 하위 도메인을 유지하면서 어떻게 모든 http 요청을 https로 다시 작성할 수 있습니까?


508

웹 서버의 모든 http 요청을 https 요청으로 다시 작성하고 싶습니다. 다음으로 시작했습니다.

서버 {
    듣고 80;

    위치 / {
      ^ (. *) https : //mysite.com$1 영구 다시 쓰기;
    }
...


하나의 문제는 이것이 하위 도메인 정보 (예 : node1.mysite.com/folder)를 제거한다는 것입니다. 위의 내용을 다시 작성하여 https로 모든 경로를 변경하고 하위 도메인을 유지 관리하려면 어떻게해야합니까?


2
'허용 된 답변'을 serverfault.com/a/171238/90758로 옮기는 것을 고려하십시오 . 맞습니다.
olafure

그냥 대신 하드 mysite.com의 $ 서버 _ 사용
Fedir RYKHTIK

답변:


748

새로운 버전의 nginx에서 올바른 방법

이 질문에 대한 첫 번째 대답은 특정 시간에 맞았지만 다른 함정으로 바뀌 었습니다. 최신 상태를 유지하려면 세금 환급을 다시 작성 하십시오.

나는 많은 SE 사용자에 의해 수정되었으므로 크레딧은 그들에게 전달되지만 더 중요한 것은 올바른 코드입니다.

server {
       listen         80;
       server_name    my.domain.com;
       return         301 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000" always; 

       [....]
}

3
그러나 도메인 단위로 도메인에서이 작업을 수행해야합니다. 서버의 모든 도메인에 적용하려면 어떻게해야합니까?
JM4

30
@ JM4 : server_name 대신 다시 쓰기에서 $ host $를 사용하고 수신 지시문에 default_server를 추가하면 서버의 모든 도메인에서 작동합니다.
Klaas van Schelven

5
301은 만료 날짜없이 로컬 캐시에 저장되어 있습니다. 설정 변경시 유용하지 않음
Trefex

9
@everyone POST 내용을 보존하려면 307 리디렉션을 사용하십시오.
Mahmoud Al-Qudsi

10
하위 도메인을 사용 $host하는 $server_name경우 대신 사용해야합니다 .
메기

276

참고 :이 작업을 수행하는 가장 좋은 방법은 https://serverfault.com/a/401632/3641 에서 제공 되었지만 여기에서 반복됩니다.

server {
    listen         80;
    return 301 https://$host$request_uri;
}

가장 간단한 경우 호스트는 서비스를 보내려는 서비스로 고정됩니다. 이렇게하면 브라우저로 301 리디렉션되고 브라우저 URL이 그에 따라 업데이트됩니다.

아래는 이전 답변입니다. 정규식으로 인해 비효율적입니다. @ kmindi로 표시된 것처럼 간단한 301이 좋습니다.

nginx 0.8.39 이상을 사용하고 있으며 다음을 사용했습니다.

 server {
       listen 80;
       rewrite ^(.*) https://$host$1 permanent;
 }

클라이언트로 영구적 리디렉션을 보냅니다.


15
http를 듣고 클라이언트에게 https (443)로 돌아 오라고 말하면서 80이어야한다고 생각합니다.
Michael Neale

3
이것이 최고의 답변이어야합니다!
Nathan

3
이것은 가장 과세 답변입니다.
Case

1
가장 쉬운 방법이지만 보안 수준이 가장 낮습니다. 이렇게하면 서버에서 서버를 사용할 수 있는지 확인하지 않고도 서버가 사용자를 모든 페이지로 리디렉션 할 수 있습니다. 서버가 mydomain.co를 제공하는 경우에도 악의적 인 사용자는 서버를 사용하여 google.com과 같은 mydomain.co와 같은 다른 도메인으로 사용자를 리디렉션 할 수 있습니다.
friedkiwi

10
@ cab0lt 여기에는 보안 문제가 없습니다. 리디렉션을 제공한다고해서 보안 위험이 발생하지는 않습니다. 액세스 제어 요구 사항이있는 경우 브라우저가 새 URL을 요청하는 시점에서 요구 사항을 확인해야합니다. 브라우저는 단순히 리디렉션을 기반으로 액세스 할 수 없으며 새 URL을 요청하기 위해 리디렉션이 필요하지 않습니다.
mc0e

125

가장 좋은 유일한 방법은 HTTP 301 Moved Permanently 리디렉션을 다음과 같이 사용해야한다고 생각합니다 .

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

영구적으로 이전 HTTP 301 이미 언급에 따라 평가되어야 할 정규식이 없기 때문에 리디렉션 또한 가장 효율적이다 pitfails .


새로운 HTTP 308 Moved는 영구적 으로 Request 메소드를 유지하며 주요 브라우저에서 지원합니다 . 예를 들어를 사용 308하면 브라우저 가 리디렉션 요청 POSTGET대한 요청 방법을에서 로 변경하지 못합니다 .


호스트 이름과 하위 도메인유지하려면 이 방법입니다.

이것은 당신이 어떤 DNS가없는 경우 여전히 작동합니까 나는 또한 로컬로 사용하고 있습니다로. 예를 요청하고 http://192.168.0.100/index.php으로 정확하게 리디렉션됩니다 https://192.168.0.100/index.php.

로 설정 listen [::]:80했기 때문에 호스트에서 사용 하므로 ipv4 소켓에도 바인딩됩니다. IPv6을 원하지 않거나 다른 곳으로 바인딩하려는 경우로 변경하십시오 .bindv6onlyfalselisten 80

Saif Bechan의 솔루션은 server_name필자의 경우 localhost이지만 네트워크를 통해 도달 할 수없는 것을 사용합니다.

Michael Neale의 솔루션은 좋지만 문제에 따르면 리디렉션 301을 사용하는 더 나은 솔루션이 있습니다.)


인용을 시도해도 좋지만 301은 HTTPS에서 작동하지 않습니다.
Case

5
작동하지 않는 것은 무엇입니까? 명시된 서버 섹션은 암호화되지 않은 http (s가없는) 트래픽이 암호화 된 서버로 영구적으로 리디렉션되도록하기위한 것입니다 (443 (https)에서 수신 대기하는 섹션은 표시되지 않음)
kmindi

나는 이것이 https와 모든 것이 잘 작동하는지 확인했다-@kmindi 나는 당신의 것을 참조하여 내 대답을 업데이트했다. 잘 했어.
Michael Neale

도메인 (ip 이외의) 요청을 사용할 때 '[::] : 80'을 '80'으로 변경하지 않으면 작동하지 않습니다.
Joseph Lust

trac.nginx.org/nginx/ticket/345 예상되는 동작 일 수 있습니다 . 청취 옵션을 설명하기 위해 답변을 업데이트했습니다.
kmindi

20

서버 블록 내에서 다음을 수행 할 수도 있습니다.

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}

2
이 구성으로 인해 서버에서 리디렉션 루프를 생성했습니다
Corkscreewe

사이트 / 앱에서 다른 리디렉션이 발생하거나 https가 사용 설정되어 있지 않을 수 있습니다.
Oriol

1
이것을 제외하고 다른 사람은 아무것도 작동하지 않는 것 같습니다. nginx 버전 사용 : nginx / 1.10.0 (우분투)
ThatGuy343

https : // $ host $ uri에 투표
AMB

4
이것이로드 밸런서 뒤에 있다면 갈 수있는 방법입니다!
Antwan

17

위의 내용은 항상 새로운 하위 도메인이 생성되는 경우 작동하지 않습니다. 예 : 약 30 개의 하위 도메인에 대한 AAA.example.com BBB.example.com

마지막으로 다음 작업을 수행하는 구성이 있습니다.

server {
  listen 80;
  server_name _;
  rewrite ^ https://$host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}

감사합니다! nginx는 301 https://*/여기의 다른 답변에서 요청을 조기에 반환 하거나 취소합니다. server_name _;과는 $host속임수를 썼는지 대답했다. +1
zamnuts

1
이것은 최적입니다! 그러나 일부 _는 실제 도메인 으로 교체 하는 것이 좋습니다 . 예를 들어 .domain.com두 대의 서버가 있고 nginx가 실수로 내 서버 중 하나를 기본 서버로 지정했습니다.
zzz

1
이것은 나를 위해 일한 유일한 대답입니다, 감사합니다!
눈사람

많은 친구 감사합니다. 나는 많은 솔루션을 시도했지만 운동하지 않았다. 이 솔루션은 훌륭하고 나를 위해 일했습니다. 서버 이름 _; 이것은 무엇을 의미 하는가. 나는 이해하지 못했다. 이것을 설명 해주세요.
Pavan Kumar

6

오래 전부터 매우 중요한 수정 사항으로 정답에 대한 의견을 게시했지만이 수정 사항을 자체 답변으로 강조 표시해야한다고 생각합니다. 안전하지 않은 HTTP 설정을하고 사용자 콘텐츠가 있거나 양식이 있거나, API를 호스팅하거나, 웹 사이트, 도구, 응용 프로그램 또는 유틸리티가 사이트와 통신하도록 구성한 경우에는 이전 답변 중 어느 것도 사용하기에 안전하지 않습니다.

POST서버에 요청 하면 문제가 발생 합니다. 서버가 일반 30x리디렉션으로 응답 하면 POST 컨텐츠가 손실됩니다. 무슨 일 브라우저 / 클라이언트가 SSL 요청을 업그레이드하지만 것입니다 다운 그레이드POSTA를 GET요청. POST매개 변수가 손실되고 잘못된 요청이 서버에 이루어집니다.

해결책은 간단합니다. HTTP 1.1 307리디렉션 을 사용해야합니다 . RFC 7231 S6.4.7에 자세히 설명되어 있습니다.

  Note: This status code is similar to 302 (Found), except that it
  does not allow changing the request method from POST to GET.  This
  specification defines no equivalent counterpart for 301 (Moved
  Permanently) ([RFC7238], however, defines the status code 308
  (Permanent Redirect) for this purpose).

승인 된 솔루션에서 채택한 솔루션은 307리디렉션 코드 에 사용 하는 것입니다.

server {
       listen         80;
       server_name    my.domain.com;
       return         307 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000"; 

       [....]
}


4

AWS ELB 뒤에서 ngnix를 실행하고 있습니다. ELB는 http를 통해 ngnix와 대화하고 있습니다. ELB는 클라이언트로 리디렉션을 보낼 수있는 방법이 없으므로 X-Forwarded-Proto 헤더를 확인하고 리디렉션합니다.

if ($http_x_forwarded_proto != 'https') {
    return 301 "https://www.exampl.com";
}

1

return 301 https://$host$request_uri;포트 80의 기본 응답 인 경우 , 서버가 조만간 열린 프록시 목록에 올라 인터넷의 다른 곳으로 트래픽을 보내기 위해 남용 될 수 있습니다 [1]. 로그에 다음과 같은 메시지가 가득 차면 자신에게 발생한 일임을 알 수 있습니다.

42.232.104.114 - - [25/Mar/2018:04:50:49 +0000] "GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1" 301 185 "http://www.ioffer.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; RogueCleaner; Alexa Toolbar)"

문제는 $host브라우저가 Host헤더 또는 HTTP의 시작 줄에서 호스트 이름으로 보내는 모든 것을 다음과 같이 에코합니다 .

GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1

그 문제 때문에 여기에있는 다른 대답은 $server_name대신 대신 사용 하는 것이 좋습니다 $host. $server_name항상 무엇을 평가 당신이 에 넣어 server_name선언. 그러나 하위 도메인이 여러 개 있거나 와일드 카드를 사용하는 경우 선언 후 첫 번째 항목 $server_name만 사용 하기 때문에 작동하지 않으며 더 중요하게 와일드 카드를 에코하지 않습니다 (확장하지 않음).server_name

보안을 유지하면서 여러 도메인을 지원하는 방법은 무엇입니까? 내 자신의 시스템에 나는함으로써이 딜레마 처리 한 첫 번째 목록 default_server사용하지 않는 블록을 $host다음 않는 와일드 카드 블록 목록 :

server {
  listen 80 default_server;
  server_name example.com;
  return 301 https://example.com$request_uri;
}
server {
  listen 80;
  server_name *.example.com;
  return 301 https://$host$request_uri;
}

(두 번째 블록에 둘 이상의 도메인을 나열 할 수도 있습니다.)

이 조합을 사용하면 일치하지 않는 도메인이 하드 코드 된 곳 (항상 example.com)으로 리디렉션 되고 자신과 일치하는 도메인이 올바른 위치로 이동합니다. 서버는 개방형 프록시로 유용하지 않으므로 문제를 일으키지 않습니다.

당신이 기분이 나쁘다면, default_server블록을 합법적 인 도메인과 일치 시키지 않고 공격적인 것으로 만들 수 있다고 생각합니다 . . . .

[1] 기술적으로 "프록시"는 잘못된 단어입니다. 서버가 나가지 않고 클라이언트에 대한 요청을 이행하지 않고 리디렉션 만 보내지 만 올바른 단어가 무엇인지 잘 모르겠습니다. 또한 목표가 무엇인지 확실하지 않지만 로그로 노이즈를 채우고 CPU와 대역폭을 소비하므로 중지 할 수도 있습니다.


0

아무도 100 % 맞지 않는 것 같습니다. 포트 80 요청이 전체 웹 서버에 대해 443에 해당 하도록하려면 catch_all 이름 을 지정하기 위해 server_name 지시문이 아닌 listen 지시문 을 사용해야합니다 . 참조 https://nginx.org/en/docs/http/request_processing.html

서버 {
    기본 80 듣기;
    듣기 [::] : 80 기본값;
      307을 반환 https : // $ host $ request_uri;
}
  • $ host는 하위 도메인 이름을 잡습니다.
  • 307 및 308은 POST 및 GET 요청 URI를 모두 포함합니다.
  • 307은 임시적이며 철저한 테스트 후 영구 308로 변경됩니다.

또한 default.conf가 기존 vhost를 반환하는 문제가 발생하지 않았기 때문에 /etc/nginx/conf.d/에 이미있는 내용을 확인하십시오. nginx 문제에 대한 작업 순서는 항상 기본 파일을 이동하여 시작하여 한 줄씩 주석 처리하여 잘못된 위치를 확인합니다.


-1
rewrite ^!https https://$host$request_uri permanent;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.