web-dev-qa-db-ja.com

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

同じマシン上でいくつかのサーバーを実行しています。httpのみを使用するサーバーもあれば、httpとhttpsの両方を使用するサーバーもあります。メインの構成ファイルからインクルードされた個別のファイルで定義されたいくつかのサーバーブロックがあります。

他の構成ファイル内の他のserver_nameのいずれにも一致しないリクエストに対して、一般的な「メンテナンスページ」を提供するhttpの「デフォルト」サーバーを設定しました。 httpデフォルトサーバーは期待どおりに機能し、server_name "_"を使用し、インクルードのリストの最初に表示されます(サーバー間でserver_nameが重複している場合、最初に表示されているサーバーが使用されることがわかったためです)。これはうまくいきます。

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

だから私の質問は、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;
    }
}

ここで何が悪いのか見ている人はいますか?

84
Roar

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

Common Name *を使用して自己署名証明書を作成し、構成にプラグインすると、希望どおりに機能します。

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

29

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

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

NginxはASCII形式でvhostsをロードしているため、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;
}

-自己署名証明書を作成し、テストし、再読み込みします

/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

それが役に立てば幸い。

25
Ifnot

基本的に、構成ファイルの最初のサーバー定義が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;
    }

    ...
17
Rolf

ラドミラムスタファの答えについてさらに詳しく説明するには:

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
}
8
andreycpp

私と同じくらいこれで髪の毛を失った人なら誰でも(今日はほぼ1日過ごしました)。私はほとんどすべてを試しました、そしてそれを最終的に正しく機能させたのはこの愚かな行でした:

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が彼の望んでいるものを与えないと、非常に奇妙に振る舞うということです。

4
Marek Lisý

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

1
Michael Hampton