web-dev-qa-db-ja.com

Nginxでは、サブドメインを維持しながら、すべてのhttpリクエストをhttpsに書き換えるにはどうすればよいですか?

Webサーバー上のすべてのhttp要求をhttps要求に書き換えたいので、次のように始めました。

 server {
 listen 80; 
 
 location/{
 rewrite ^(。*)https://mysite.com$1 persistent; 
} 
 ... 


1つの問題は、これによりサブドメイン情報(node1.mysite.com/folderなど)が削除されることです。上記を書き換えてすべてをhttpsに再ルーティングし、サブドメインを維持するにはどうすればよいですか?

517
MikeN

Nginxの新しいバージョンでの正しい方法

この質問に対する私の最初の答えが特定の時間に正しかったことが判明したが、それは別の落とし穴に変わった-最新の状態に保つために確認してください Taxing rewrite pitfalls

私は多くの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; 

       [....]
}
758
Saif Bechan

注:これを行う最良の方法は 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;
 }

クライアントに永続的なリダイレクトを送信します。

280
Michael Neale

次のようにHTTP 301 Moved Permanentlyリダイレクトを使用するのが最善で唯一の方法だと思います。

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

すでに述べたように、評価される正規表現がないため、HTTP 301 Moved Permanentlyリダイレクトも最も効率的です pitfails


新しい HTTP 308 Moved Permanently は、Requestメソッドを保持し、 主要なブラウザでサポートされています です。たとえば、308を使用すると、ブラウザがリダイレクトリクエストのリクエストメソッドをPOSTからGETに変更できなくなります。


ホスト名とサブドメインを保存したい場合これが方法です。

これもDNSがない場合でも機能します。これもローカルで使用しているためです。たとえばhttp://192.168.0.100/index.phpを使用してリクエストすると、正確にhttps://192.168.0.100/index.phpにリダイレクトされます。

私はlisten [::]:80falseに設定しているため、ホストでbindv6onlyを使用しているため、ipv4ソケットにもバインドします。 IPv6が不要な場合、または他の場所にバインドする場合は、listen 80に変更します。

Saif Bechanのソリューションはserver_nameを使用します。私の場合はlocalhostですが、ネットワーク経由では到達できません。

Michael Nealeのソリューションは優れていますが、pitfailsによると、リダイレクト301を使用したより良いソリューションがあります;)

125
kmindi

サーバーブロック内では、次の操作も実行できます。

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

上記は、常に作成される新しいサブドメインでは機能しませんでした。例えばAAA.example.com BBB.example.comは約30のサブドメイン。

最後に、以下で動作する設定を取得しました:

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
# ...
}
17
Aleck Landgraf

私は正解に非常に重要な修正を加えてずっと前にコメントを投稿しましたが、この修正を独自の解答で強調する必要があると感じています。 安全でないHTTPを設定してユーザーコンテンツを期待している、フォームを持っている、APIをホストしている、または話すようにWebサイト、ツール、アプリケーション、またはユーティリティを構成している場合、以前の回答はどれも安全に使用できますあなたのサイト。

この問題は、サーバーにPOSTリクエストが行われたときに発生します。サーバーの応答がプレーンな30xリダイレクトの場合POSTコンテンツは失われます。ブラウザー/クライアントが要求をSSLにアップグレードすることにより、しかしdowngradePOSTから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"; 

       [....]
}
6

AWS ELBの背後でngnixを実行しています。 ELBはhttpを介してngnixと通信しています。 ELBにはクライアントにリダイレクトを送信する方法がないため、X-Forwarded-Protoヘッダーとリダイレクトを確認します。

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

私はこのようにしてなんとかしました:

server {
listen 80;
listen 443 ssl;

server_name domain.tld www.domain.tld;

# global HTTP handler
if ($scheme = http) {
        return 301 https://www.domain.tld$request_uri;
}

# global non-WWW HTTPS handler
if ($http_Host = domain.tld){
        return 303 https://www.domain.tld$request_uri;
}
}

https://stackoverflow.com/a/36777526/6076984

4
stamster

ポート80のデフォルトの応答としてreturn 301 https://$Host$request_uri;を指定した場合、サーバーは遅かれ早かれオープンプロキシのリスト[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宣言に入力されたyoに評価されます。ただし、そこに複数のサブドメインがある場合、またはワイルドカードを使用する場合、$server_nameserver_name宣言の後にfirstエントリのみを使用するため、機能しません。さらに重要なのは、ワイルドカードをエコーバックします(展開しません)。

では、セキュリティを維持しながら複数のドメインをサポートするにはどうすればよいでしょうか。私自身のシステムでは、このジレンマをfirstdefault_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;
}

(2番目のブロックに複数のドメインをリストすることもできます。)

この組み合わせにより、一致しないドメインはハードコーディングされた場所にリダイレクトされ(常にexample.com)、独自のドメインと一致するドメインは適切な場所に移動します。サーバーはオープンプロキシとしては役に立たないので、問題が発生することはありません。

乱暴に感じている場合は、default_serverブロックを正規のドメインのnoneに一致させて、不快なものを提供することもできます。 。 。 。

[1]技術的に「プロキシ」は間違ったWordです。サーバーが外に出てクライアントへのリクエストを実行せず、リダイレクトを送信するだけだからですが、適切なWordが何かはわかりません。また、目的が何であるかはわかりませんが、ログがノイズでいっぱいになり、CPUと帯域幅が消費されるため、停止することもできます。

1

100%正解した人はいないようです。ポート80要求をWebサーバー全体の対応する443に送信するには、server_nameディレクティブではなく、listenディレクティブを使用して指定する必要があります。 catch-allの名前。参照 https://nginx.org/en/docs/http/request_processing.html

サーバー{
 listen 80 default; 
 listen [::]:80 default; 
 return 307 https:// $ Host $ request_uri; 
} 
  • $ Hostはサブドメイン名をキャッチします。
  • 307と308には、POSTとGETリクエストURIの両方が含まれています。
  • 307は一時的なものです。十分なテストを行った後、Permanent 308に変更します。

/etc/nginx/conf.d/の内容を確認してください。default.confが既存のvhostを返すという問題が発生することが多かったためです。 nginxの問題を扱う私の順序は、デフォルトのファイルを移動することから始まり、行ごとにコメントアウトして、どこで問題が発生しているかを確認します。

0
Julius