httpsの「デフォルト」nginxサーバーを適切に設定する


71

同じマシンで複数のサーバーを実行していますが、一部はhttpのみ、一部はhttpとhttpsの両方を使用しています。メインの設定ファイルに含まれる個別のファイルで定義されたいくつかのサーバーブロックがあります。

他の構成ファイルの他のserver_namesと一致しない要求に汎用の「メンテナンスページ」を提供するhttp用の「デフォルト」サーバーをセットアップしました。httpのデフォルトサーバーは期待どおりに動作し、server_name "_"を使用し、インクルードのリストの最初に表示されます(サーバー間でserver_namesが重複している場合は、最初に表示されるものが使用されます)。これはうまく機能します。

同じサーバーブロック( "listen 80 default_server"を "listen 443 default_server"に切り替え、ページ "return 444"を提供する代わりに)を期待していますが、そうではありません。代わりに、新しいデフォルトhttpsサーバーが実際にすべての着信https接続を取得して失敗しているように見えますが、他のサーバーブロックには着信要求に対してより適切なserver_nameがあります。新しいデフォルトのhttpsサーバーを削除すると、半正しい動作が再開されます。httpsのあるWebサイトはすべて正しく読み込まれます。ただし、httpsのないWebサイトはすべて、インクルードファイルの最初のhttpsサーバーにルーティングされます(ドキュメントによると、「default_server」が表示されない場合、最初に表示されるサーバーブロックは「default」になります)。

だから私の質問は、ssl接続のためにnginxで「デフォルトサーバー」を定義する正しい方法は何ですか?なぜ「default_server」を明示的に設定すると貪欲になり、すべての接続を取得するのに対して、nginxに暗黙的に「デフォルトサーバー」を決定させると、期待どおりに動作します(間違ったサーバーがデフォルトとして設定され、他の実サーバーが正しく動作します)?

これが私の「デフォルトサーバー」です。Httpは、他のサーバーを壊すことなく機能します。Httpsは他のサーバーを破壊し、すべてを消費します。

server {
    listen 443 ssl default_server;
    server_name _;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    return 444;
}

server {
    listen *:80 default_server;
    server_name _;
    charset utf-8;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    root /home/path/to/templates;

    location / {
        return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /maintenance.html break;
    }
}

ここで何が間違っているのか見ている人はいますか?

ssl  https  nginx 

回答:


27

「デフォルト」httpsブロックにssl_certificateまたはssl_certificate_keyが定義されていません。このデフォルトのシナリオでは実際のキーは持っていないか、必要ではありませんが、設定する必要があります。そうしないと、nginxが説明する望ましくない動作をすることになります。

共通名*の自己署名証明書を作成し、構成にプラグインすると、希望どおりに機能し始めます。

この設定での「デフォルト」の動作は、ブラウザが証明書を信頼できないという警告を受け取ることです。ユーザーが証明書を例外として追加すると、nginxによって接続が切断され、ブラウザのデフォルトが表示されます。 「接続できませんでした」エラーメッセージ。


1
私はこれを試してみましたが、まだ機能しません:IPへのすべてのsslリクエストは、他のsslホストに送られます。私が試すことができる他の何か?
マイケルハートル

23

私は、nginxを使用して単一のIPで共有専用ホスティングを構成することができました。未知のドメインの着信に対して404を提供するデフォルトのHTTPおよびHTTPS。

1-デフォルトゾーンを作成する

nginxはvhostをASCII順でロードしているため、00-defaultファイル/シンボリックリンクをに作成する必要があります/etc/nginx/sites-enabled

2-デフォルトゾーンを埋める

あなたを記入し00-default、デフォルトのバーチャルホストで。私が使用しているゾーンは次のとおりです。

server {
    server_name _;
    listen       80  default_server;
    return       404;
}


server {
    listen 443 ssl;
    server_name _;
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    return       404;
}

3-自己署名証明書を作成し、テストして、リロードする

に自己署名証明書を作成する必要があります/etc/nginx/ssl/nginx.crt

デフォルトの自己署名証明書を作成します。

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

ただのリマインダー:

  • リロード/再起動する前にnginx設定をテストします。 nginx -t
  • エンジョイをリロードします。 sudo service nginx reload

それが役に立てば幸い。


2
安全でないサイトにアクセスしたというブラウザの警告を解決しません。
gdbj

5
キャッチオールはどのドメインとも一致する必要があるため、解決できません。SSLはすべてのドメインをワイルドカードできません。サーバーでgoogle.frアドレスをスプーフィングしている場合、サーバーをgoogle.frとして認証できると想像してください。それは深刻なセキュリティ問題になります:(
Ifnot

ええ、それは理にかなっていると思います。残念ながら、Chromeでは、404ページが表示される前に恐ろしい警告が表示されます。これは、サーバーにトラフィックを単に拒否させるよりも悪いことです。サーバーが正しく構成されていないように見えます。
gdbj

どうもありがとうございました。これは私にとってはうまくdefault_serverいきましたが、listen 443に追加する必要があり、IPv6アドレス[::]:80と[::]:443を追加しましたdefault_server
chmike

16

基本的に、設定ファイルの最初のサーバー定義がSSL接続のキャッチオールサーバーとして提供されることを、すべてのコストで回避したいと思います。私たちは皆、それがそれを行うことを知っています(httpとは対照的に、うまく動作するdefault_server configを使用します)。

これはSSLに対して宣言的に達成することはできませんが(まだ)、IFでコーディングする必要があります...

変数$hostは、要求行またはhttpヘッダーからのホスト名です。変数$server_nameは、現在のサーバーブロックの名前です。

したがって、これら2つが等しくない場合、別のホストに対してこのSSLサーバーブロックを提供したため、ブロックする必要があります。

コードにはサーバーIPアドレスへの特定の参照が含まれていないため、変更せずに他のサーバー構成で簡単に再利用できます。

例:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ###
    ### Section: SSL

    #
    ## Check if this certificate is really served for this server_name
    ##   http://serverfault.com/questions/578648/properly-setting-up-a-default-nginx-server-for-https
    if ($host != $server_name) {
        #return 404 "this is an invalid request";
        return       444;
    }

    ...

あなたは何をするのか説明できますlisten [::]:443 ssl http2;か?ドキュメントを見つけることができません。
アンドリューブラウン

私はそれを見つけたと思う、ただ検索するものを知る必要があった。IPV4およびIPV6ディレクティブ。
アンドリューブラウン

7

Radmilla Mustafaの答えをさらに詳しく説明するには:

Nginxはserver_nameの照合に「Host」ヘッダーを使用します。TLS SNIは使用しません。これは、SSLサーバーの場合、nginxがSSL接続を受け入れられる必要があることを意味します。これは、最終的に証明書/キーを持つことになります。証明書/キーは、自己署名などの任意のものにすることができます。

ドキュメントを参照

したがって、解決策は次のとおりです。

server {
    server_name _;
    listen 80 default_server;
    listen 443 ssl default_server;

    ## To also support IPv6, uncomment this block
    # listen [::]:80 default_server;
    # listen [::]:443 ssl default_server;

    ssl_certificate <path to cert>;
    ssl_certificate_key <path to key>;
    return 404; # or whatever
}

これは受け入れられる答えだと思う。どうもありがとう。
集計

2

これで私と同じくらい髪を失った人に(今日、これにほぼ一日を費やした)。私はほとんどすべてを試しましたが、最終的に正しく動作するようになったのはこの愚かな行でした:

ssl_session_tickets off;

Ifnotの答えに基づいて、私の実例は次のとおりです。

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_session_tickets off;

    return 404;
}

私はこれがなぜ必要なのか分かりませんが、私がこれから導き出した唯一の原則は、nginxが彼が望むものを与えないとき非常に奇妙に振る舞うということでした。


1
あなたは伝説です。
ニザールブロンド

1

確実に確認したい場合は、HTTPSで応答しないホストと応答するホストに別々のIPアドレスを使用します。これにより、「無効な証明書」ブラウザの警告問題も解決されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.