nginx를 사용하여“www”를 제거하고“https”로 리디렉션 올바르게 수행하는

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)에 있어야합니다 . 어떤 아이디어?



답변

이를 수행하는 가장 좋은 방법은 세 개의 서버 블록을 사용하는 것입니다. 하나는 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>
}

답변

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

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/ 를 시도 하십시오 .)


답변

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

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악입니다 !

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


답변

브라우저가 응답 코드를 다른 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;
        ...
    }

답변

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

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

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


답변

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

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

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

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

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

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


답변

다음은 나를 위해 일한 전체 예입니다. 문제는 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;
    }
}