nginx를 사용하여“www”를 제거하고“https”로 리디렉션


57

nginx에서 두 가지 작업을 수행하는 규칙을 만들고 싶습니다.

  1. "www"를 제거합니다. 요청 URI에서
  2. 요청 URI가 "http"인 경우 "https"로 리디렉션

이러한 각 작업을 개별적으로 수행하는 방법에 대한 많은 예가 있지만 올바르게 수행하는 솔루션을 파악할 수는 없습니다 (예 : 리디렉션 루프를 생성하지 않고 모든 경우를 올바르게 처리).

다음과 같은 경우를 모두 처리해야합니다.

1. http://www.example.com/path
2. https://www.example.com/path
3. http://example.com/path
4. https://example.com/path

이것들은 모두 루핑없이 https://example.com/path (# 4)에 있어야합니다 . 어떤 아이디어?


방금 www.mydomain.com을 DNS 수준에서 mydomain.com으로 리디렉션하고 비 gins에 대한 301을 nginx의 https에 추가했습니다. 괜찮을 것 같아 ¯ \ _ (ツ) _ / ¯
jonathanbell

답변:


94

이를 수행하는 가장 좋은 방법은 세 개의 서버 블록을 사용하는 것입니다. 하나는 http를 https로 리디렉션하고 다른 하나는 https www-name을 no-www로 리디렉션하고 다른 하나는 실제로 요청을 처리하는 것입니다. ifs 대신 추가 서버 블록을 사용하는 이유는 서버 선택이 해시 테이블을 사용하여 수행되고 매우 빠르기 때문입니다. 서버 수준 if를 사용한다는 것은 모든 요청에 ​​대해 if가 실행됨을 의미하며 낭비입니다. 또한 nginx는 이미 $ uri 및 $ request_uri 변수에 쿼리 문자열없이 각각이 정보를 가지고 있기 때문에 요청 된 URI를 다시 쓰기에서 캡처하는 것은 낭비입니다.

server {
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.cert;
    ssl_certificate_key /path/to/server.key;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.cert;
    ssl_certificate_key /path/to/server.key;
    server_name example.com;

    <locations for processing requests>
}

2
중간 블록이 필요합니까? 첫 번째 블록이 이미 www에서 비 www로 다시 쓰지 않습니까?
pbreitenbach

3
첫 번째 블록은 http 만 처리합니다. https 요청을 https : // www.example.com/에서 https : // example.com/으로 리디렉션하려면 중간 블록이 필요합니다. (추가 공간이있어서 죄송합니다. 그렇지 않으면 https를 표시 할 수 없습니다.)
kolbyjack

1
사소한 서식 참고 사항-링크를 피하려면 주석 텍스트를 백 따옴표`안에 넣을 수 있습니다. 그것은처럼 보여 것입니다 :https://example.com/
사이클롭스

9
두 번째 블록에도 인증서 정보가 필요합니다.
Ricka

3
이 답변을 시도하면서 다른 문제가 발생했습니다. 나는 301에서 리디렉션 수 있다고 생각 www.sub.example.comsub.example.com하고 위해 만 SSL 인증서를 얻을 sub.example.com지금은 그의 SSL 인증서 검사가 301 리디렉션하기 전에 어떻게 알고, 그래서 작동하지 않을 수 있습니다. 자세한 설명은 여기 : serverfault.com/a/358625/144811
Gruzzles

11

이것은 나를 위해 작동합니다 :

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

server {
    listen              443 ssl;
    server_name         www.yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    return              301 https://yourdomain.com$request_uri;
}

server {
    listen              443 ssl;
    server_name         yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;

    # do the proper handling of the request
}

있다는 사실을 숙지 모두 yourdomain.com 하고 www.yourdomain.com 있어야 당신의 SSL 인증서에합니다. 여기에 설명 된대로 와일드 카드 인증서 또는 서버 대체 이름으로 가능 합니다 . 이를 위한 멋진 무료 인증서는 https://www.startssl.com 을 확인 하십시오 . ( Edith : Chrome 버전 56부터 startssl 인증서는 더 이상 신뢰되지 않습니다. 대신 https://letsencrypt.org/ 를 시도 하십시오 .)


이것은 실제로 작동하지만 많은 중복 구성 줄없이 더 명확한 방법으로 수행 할 수 있다고 생각했습니다.
zloynemec

@zloynemec SSL 항목을 별도의 .conf 파일에 넣고 include규칙을 사용하여 SSL 서버 블록 모두에 추가 할 수 있습니다.
Igettäjä

또한 cloudflare를 사용하는 경우 2 개의 하위 도메인 (www + something)을 리디렉션하고 프록시 할 수 있도록 $ 10 / mo 인증서를 지불해야합니다. 해결 방법이 있으면 알려주세요.
Freedo

7

수백 개의 유사한 사례로 많은 시간을 보낸 후에 다음 스 니펫을 생각해 냈습니다. 짧고 어떤 것에 맞게 쉽게 조정할 수 있습니다.

server {
    listen 80;
    listen 443 ssl;
    server_name example.com www.example.com;
    ssl_certificate /path/to/my/certs/example.com/fullchain.pem;
    ssl_certificate_key /path/to/my/certs/example.com/privkey.pem;

    # Redirect to the correct place, if needed
    set $https_redirect 0;
    if ($server_port = 80) { set $https_redirect 1; }
    if ($host ~ '^www\.') { set $https_redirect 1; }
    if ($https_redirect = 1) {
        return 301 https://example.com$request_uri;
    }

    location / {
    # ...
}

아 그러나 if악입니다 !

네, 그것은 가능 합니다. 그러나 이유가 있기 때문에 올바르게 사용하는 방법을 알고있는 사람들에게는 해를 끼치 지 않아야합니다. ;)


나는 이것을 좋아하지만 성능 저하에 대한 데이터가 있습니까? 감사합니다!
Freedo

1
솔직히 나는 그것을 벤치마킹 한 적이 없지만 효과가 거의 동일하기 때문에 별도의 규칙에 비해 영향이 거의 없을 것이라고 생각합니다.
emyller

리디렉션 벤치 마크? 그것은 실제로 관련되지 않습니다? (진정한 질문, 트롤이 아닌 ^^)
Matrix

3

브라우저가 응답 코드를 다른 URL로 리디렉션하고 있음을 알 수 있도록 응답 코드와 함께 반환하는 것을 선호합니다.

server {
    listen   80;
    server_name  www.example.com;

    return 301 https://example.com$request_uri;
}

다음에 대한 다른 서버 구성 블록 https

server {
        listen   443 ssl;
        server_name  example.com;
        ...
    }

0

이 목적을 위해 서버 블록을 만드는 방법은 다음과 같습니다.

server{
    listen 80;
    server_name www.example.net example.net;
    rewrite ^(.*) https://example.net$1 permanent;
}

그런 다음 nginx를 다시 시작하십시오.


다시 시작할 때 "충돌하는 서버 이름"오류가 발생합니다. 또한 해당 명령은 포트 443에서 SSL을 수신하지 않으므로 리디렉션 https://www.example.com으로 걱정할 필요가 https://example.com있습니다.
Devin

0

나는 이것이 효과가 있다고 생각한다.

일반 HTTP 서버 정의에서 anthonysomerset과 같은 것이 제안되었습니다.

rewrite ^(.*) https://example.net$1 permanent;

그런 다음 SSL 서버 정의에서 :

if ($host ~ /^www\./) {
  rewrite ^(.*) https://example.net$1 permanent;
}

이런 식으로 리디렉션은 사용자가 원래 어떤 URL을 방문하든 요청 당 한 번만 발생해야합니다.


고마워요 그래도 if ($host = 'www.example.com') {정규 표현식이 나를 위해 일하지 않았기 때문에 조건을 변경해야했습니다 . 왜 정확 해 보이는지 모르겠습니다.
Devin

참고 마십시오 경우가 악 하고 선언적인 방법을 사용하는 것이 일반적으로 좋습니다.
Blaise

0

다음은 나를 위해 일한 전체 예입니다. 문제는 ssl_certificatewww 리디렉션 블록에 SSL 세부 정보 ( 등 등) 가 없다는 것 입니다. 로그를 확인하십시오 ( sudo tail -f /var/log/nginx/error.log)!

# HTTP — redirect all traffic to HTTPS
server {
    listen 80;
    listen [::]:80 default_server ipv6only=on;
    return 301 https://$host$request_uri;
}

# HTTPS — redirects www to non-www
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.example.com;

    # Use the Let's Encrypt certificates
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;
    return 301 https://example.com$request_uri;
}

# HTTPS — proxy all requests to the app (port 3001)
server {
    # Enable HTTP/2
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com sub.example.com;

    # Use the Let's Encrypt certificates
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;

    # For LetsEncrypt:
    location ~ /.well-known {
        root /var/www/html;
        allow all;
    }

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://localhost:3001;
        proxy_ssl_session_reuse off;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.