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


57

私はnginxで2つのことを行うルールを作成したい:

  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)で終わるはずです。何か案は?


DNSレベルでwww.mydomain.comをmydomain.comにリダイレクトし、nginxのhttpsに非httpsの301を追加しました。そのように思えるが、細かい¯\ _(ツ)_ /¯する必要があります
jonathanbell

回答:


94

これを実現する最良の方法は、3つのサーバーブロックを使用することです。1つはhttpをhttpsにリダイレクトし、1つはhttps www-nameをno-wwwにリダイレクトし、1つは実際に要求を処理します。ifsの代わりに余分なサーバーブロックを使用する理由は、ハッシュテーブルを使用してサーバーの選択が実行され、非常に高速であるためです。サーバーレベルのifを使用すると、すべてのリクエストに対してifが実行されますが、これは無駄です。また、書き換えで要求されたuriをキャプチャするのは無駄です。nginxは既にこの情報を$ uri変数と$ request_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からnon-wwwに書き換えられていませんか?
pbreitenbach

3
最初のブロックはhttpのみを処理します。https要求をhttps:// www.example.com/からhttps:// example.com/にリダイレクトするには、中間ブロックが必要です。(余分なスペースは申し訳ありませんが、それ以外の場合はhttpsを表示できません)
kolbyjack

1
ちょっとしたフォーマットのメモ-リンクを作成したくない場合は、チルダの下にあるバッククォート `の中にコメントテキストを入れることができます。次のように表示さhttps://example.com/
Cyclops

9
2番目のブロックにも証明書情報が必要です。
リカ

3
この答えを試してみると、別の問題が発生しました。からwww.sub.example.comに301リダイレクトできsub.example.com、SSL証明書のみを取得できるsub.example.comと思ったのですが、301リダイレクトの前にSSL証明書チェックが行われることがわかっているため、機能しません。ここにもっと説明: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証明書であること。ここで説明されるようにワイルドカード証明書かServer Alternate Nameでこれが可能です。これを行う素敵で無料の証明書については、https://www.startssl.comを確認してください。(エディス:Chromeバージョン56以降、startssl証明書は信頼されなくなります。代わりにhttps://letsencrypt.org/を試してください。)


これは実際に機能しますが、多くの設定行を重複させることなく、より明確な方法で実行できると考えました。
zloynemec

@zloynemec別の.confファイルにSSLのものを入れ、includeルールを使用して両方のSSLサーバーブロックに追加できます。
イゲッテヤ

また、cloudflareを使用している場合、2つのサブドメイン(www +何か)をリダイレクトおよびプロキシできるようにするには、1か月あたり10ドルの証明書を支払う必要があります。回避策があれば教えてください。
フリード

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です!

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


私はこれが好きですが、パフォーマンスヒットに関するデータはありますか?ありがとうございました!
フリード

1
正直なところ、私はそれをベンチマークしたことはありませんが、効果はほとんど同じであるため、個別のルールと比較してほとんど影響はないと思います。
エミラー

リダイレクトのベンチマーク?それは本当に適切ではない?(トロールではなく、本当の質問^^)
マトリックス

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を再起動します


再起動すると、「競合するサーバー名」エラーが表示されます。また、そのコマンドは、SSL用のポート443をリッスンしませんし、私はリダイレクトを心配する必要があるhttps://www.example.comhttps://example.comも同様に。
デビン

0

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

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

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

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

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

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


うまくいきました、ありがとう。if ($host = 'www.example.com') {ただし、正規表現が機能していないため、条件をに変更する必要がありました。それが正しいように見えるので、理由はわかりません。
デヴィン

ifが悪であり、一般に宣言的な方法を使用する方が良いことに注意してください。
ブレイズ

0

これが私のために機能する完全な例です。問題はssl_certificate、wwwリダイレクトブロックに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.