web-dev-qa-db-ja.com

「www」を削除し、nginxで「https」にリダイレクト

2つのことを行うルールを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)に到達します。何か案は?

60
Devin

これを達成するための最良の方法は、3つのサーバーブロックを使用することです。1つはhttpをhttpsにリダイレクトし、1つはhttps www-nameをno-wwwにリダイレクトし、もう1つは実際にリクエストを処理します。 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>
}
100
kolbyjack

これは私にとってはうまくいきます:

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
}

bothyourdomain.comおよびwww.yourdomain.comSSL証明書に含める必要があります。これは、ワイルドカード証明書または説明されているサーバー代替名 here で可能です。 https://www.startssl.com をチェックして、これを行う素敵で無料の証明書を探します。 (Edith:Chromeバージョン56以降、startssl証明書は信頼されなくなります。試してください https ://letsencrypt.org/ 代わりに)

11
e18r

何百もの同様のケースで多くの時間を費やした後、私は次のスニペットを思いつきました。それは短く、何にでも合うように簡単に調整できます。

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は悪です

はいできます。しかし、それは理由のために存在し、それを適切に使用する方法を知っている人に害を及ぼすべきではありません。 ;)

7
emyller

私は、ブラウザが別の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;
        ...
    }
3
montss

これが私のために働いた完全な例です。問題は、sslの詳細(ssl_certificateなど)。wwwリダイレクトブロック内。ログを確認してください(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;
    }
}
0
user399009

この目的のためにサーバーブロックを作成するのはどうですか。

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

次にnginxを再起動します

0
anthonysomerset

これでうまくいくと思います。

プレーンなHTTPサーバーの定義では、anthonysomersetのようなものが提案されています。

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

次に、SSLサーバー定義で:

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

この方法では、ユーザーが最初にアクセスしたURLに関係なく、リダイレクトはリクエストごとに1回だけ発生します。

0
Eduardo Ivanec