Nginx 搭載の Linux で ASP.NET Core をホストする

Sourabh Shirhatti による投稿

注意

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

このガイドでは、Ubuntu、Red Hat Enterprise (RHEL)、SUSE Linux Enterprise Server 用の運用環境に対応した ASP.NET Core 環境の設定について説明します。

ASP.NET Core でサポートされている他の Linux ディストリビューションについて詳しくは、「Linux における .NET Core の前提条件」をご覧ください。

このガイドでは:

  • リバース プロキシ サーバーの背後に既存の ASP.NET Core アプリを配置します。
  • Kestrel Web サーバーに要求を転送するようにリバース プロキシ サーバーを設定します。
  • Web アプリを起動時にデーモンとして実行します。
  • Web アプリの再起動に役立つようにプロセス管理ツールを構成します。

必須コンポーネント

共有フレームワークをアップグレードした後の任意の時点で、サーバーによってホストされている ASP.NET Core アプリを再起動します。

アプリを介して発行およびコピーする

フレームワークに依存する展開用にアプリを構成します。

アプリが開発環境のローカルで実行され、セキュリティで保護された HTTPS 接続を行うようにサーバーによって構成されていない場合は、次のいずれかの方法を採用してください。

  • セキュリティで保護されたローカル接続を処理するようにアプリを構成します。 詳しくは、「HTTPS の構成」セクションをご覧ください。

  • セキュリティで保護されていないエンドポイントで実行するようにアプリを構成します。

    • 開発環境 (Program.cs) で HTTPS リダイレクト ミドルウェアを非アクティブ化します。

      if (!app.Environment.IsDevelopment())
      {
          app.UseHttpsRedirection();
      }
      

      詳細については、「ASP.NET Core で複数の環境を使用する」を参照してください。

    • Properties/launchSettings.json ファイルの applicationUrl プロパティから https://localhost:5001 を削除します (ある場合)。

環境別の構成については、「ASP.NET Core で複数の環境を使用する」を参照してください。

開発環境から dotnet publish を実行して、サーバー上で実行できるディレクトリ (例: bin/Release/{TARGET FRAMEWORK MONIKER}/publish。このプレースホルダー {TARGET FRAMEWORK MONIKER}ターゲット フレームワーク モニカー (TFM) です) にアプリをパッケージします。

dotnet publish --configuration Release

サーバーで .NET Core ランタイムを管理しない場合、アプリは独立した展開として発行することもできます。

組織のワークフローに統合されているツール (SCPSFTP など) を使用して、サーバーに ASP.NET Core アプリをコピーします。 Web アプリは一般的に var ディレクトリの下に配置されます (たとえば、var/www/helloapp)。

Note

運用展開シナリオの場合、継続的インテグレーション ワークフローが、アプリの発行処理とサーバーへの資産のコピーを行います。

アプリをテストします。

  1. コマンド ラインから dotnet <app_assembly>.dll アプリを実行します。
  2. ブラウザーで、http://<serveraddress>:<port> に移動し、アプリが Linux のローカルで動作することを検証します。

リバース プロキシ サーバーを構成する

リバース プロキシは、動的 Web アプリを提供するための一般的な仕組みです。 リバース プロキシは HTTP 要求を終了させ、ASP.NET Core アプリに転送します。

リバース プロキシ サーバーを利用する

Kestrel は、ASP.NET Core から動的なコンテンツを提供するのに役立ちます。 ただし、Web サーバーとしての機能は、IIS、Apache、Nginx などのサーバーと比べると制限されます。 リバース プロキシ サーバーは、静的コンテンツ サービス、要求のキャッシュ、要求の圧縮、HTTP サーバーからの HTTPS 終了などの作業の負荷を軽減します。 リバース プロキシ サーバーは専用コンピューター上に置かれることもあれば、HTTP サーバーと並んで展開されることもあります。

このガイドの目的のために、単一インスタンスの Nginx が使用されます。 HTTP サーバーと並んで、同じサーバー上で実行されます。 要件に応じて、別のセットアップを選択することも可能です。

要求はリバース プロキシによって転送されるため、Microsoft.AspNetCore.HttpOverrides パッケージのForwarded Headers Middleware を使用します。このパッケージは、共有フレームワークの Microsoft.AspNetCore.App メタパッケージを介して ASP.NET Core アプリに自動的に含まれます。 リダイレクト URI とその他のセキュリティ ポリシーを正しく機能させるために、このミドルウェアは、X-Forwarded-Proto ヘッダーを利用して、Request.Scheme を更新します。

Forwarded Headers Middleware は、他のミドルウェアの前に実行する必要があります。 この順序により、転送されるヘッダー情報に依存するミドルウェアが処理にヘッダー値を使用できます。 診断およびエラー処理ミドルウェアの後に Forwarded Headers Middleware を実行する方法については、「Forwarded Headers Middleware の順序」を参照してください。

他のミドルウェアを呼び出す前に UseForwardedHeaders メソッドを呼び出します。 ミドルウェアを構成して、X-Forwarded-For および X-Forwarded-Proto ヘッダーを転送します。

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication();

var app = builder.Build();

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

app.MapGet("/", () => "Hello ForwardedHeadersOptions!");

app.Run();

ミドルウェアに対して ForwardedHeadersOptions が指定されていない場合、転送される既定のヘッダーは None です。

標準 localhost アドレス (127.0.0.1) を含むループバック アドレス (127.0.0.0/8[::1]) 上で実行されるプロキシは、既定で信頼されます。 組織内のその他の信頼されているプロキシまたはネットワークによってインターネットと Web サーバーの間の要求が処理される場合は、それらを、ForwardedHeadersOptions を使って KnownProxies または KnownNetworks のリストに追加します。 次の例では、IP アドレス 10.0.0.100 にある信頼されているプロキシ サーバーが Forwarded Headers Middleware KnownProxies に追加されます。

using Microsoft.AspNetCore.HttpOverrides;
using System.Net;

var builder = WebApplication.CreateBuilder(args);

// Configure forwarded headers
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

builder.Services.AddAuthentication();

var app = builder.Build();

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

app.MapGet("/", () => "10.0.0.100");

app.Run();

詳細については、「プロキシ サーバーとロード バランサーを使用するために ASP.NET Core を構成する」を参照してください。

Nginx をインストールする

apt-get を利用し、Nginx をインストールします。 インストーラーにより systemd init スクリプトが作成されます。このスクリプトがシステム起動時に Nginx をデーモンとして実行します。 「Nginx: Official Debian/Ubuntu packages」 (Nginx: 公式 Debian/Ubuntu パッケージ) にある Ubuntu 用のインストールの指示に従います。

Note

オプションの Nginx モジュールが必要な場合、Nginx をソースからビルドする必要がある場合があります。

Nginx は初めてのインストールとなるので、次を実行して明示的に起動します。

sudo service nginx start

ブラウザーで Nginx の既定のランディング ページが表示されることを確認します。 ランディング ページは http://<server_IP_address>/index.nginx-debian.html からアクセスできます。

Nginx を構成する

Nginx をリバース プロキシとして構成し、ASP.NET Core アプリに HTTP 要求を転送するには、/etc/nginx/sites-available/default を変更してシンボリック リンクを再作成してください。 /etc/nginx/sites-available/default ファイルを作成した後、次のコマンドを使用してシンボリック リンクを作成してください。

sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default

テキスト エディターで /etc/nginx/sites-available/default を開き、内容を次のスニペットに置き換えます。

http {
  map $http_connection $connection_upgrade {
    "~*Upgrade" $http_connection;
    default keep-alive;
  }

  server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://127.0.0.1:5000/;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection $connection_upgrade;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
  }
}

アプリが SignalR または Blazor Server アプリの場合、詳細については、それぞれ ASP.NET Core SignalR 運用環境のホスティングとスケーリング、および ASP.NET Core サーバー側 Blazor アプリのホストと展開に関するページを参照してください。

server_name が一致しない場合、Nginx では既定のサーバーが使用されます。 既定のサーバーが定義されていない場合、構成ファイルの最初のサーバーが既定のサーバーとなります。 ベスト プラクティスとして、自分の構成ファイルで 444 の状態コードを返す既定のサーバーを具体的に追加します。 既定のサーバーの構成例は次のとおりです。

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

上記の構成ファイルと既定のサーバーでは、Nginx は、ホスト ヘッダー example.com または *.example.com で、ポート 80 でパブリック トラフィックを受け入れます。 これらのホストと一致しない要求は、Kestrel に転送されません。 Nginx により一致する要求が、http://127.0.0.1:5000/ の Kestrel に転送されます。 詳細については、「How nginx processes a request」(Nginx で要求を処理する方法) を参照してください。 Kestrel の IP/ポートを変更する場合は、Kestrel のエンドポイントの構成に関する記事を参照してください。

警告

適切な server_name directive を指定しないと、アプリにセキュリティ上の脆弱性が生じます。 親ドメイン全体を制御する場合、サブドメイン ワイルドカード バインド (たとえば、*.example.com) にこのセキュリティ リスクはありません (脆弱である *.com とは対照的)。 詳細については、RFC 9110: HTTP セマンティクス (セクション 7.2: 「Host and :authority (ホストと :authority)」) に関するページを参照してください。

Nginx の構成を確立したら、sudo nginx -t を実行して構成ファイルの構文を確認します。 構成ファイルがテストに合格したら、sudo nginx -s reload を実行することで、強制的に Nginx に変更を反映させます。

アプリをサーバーで直接実行するには、次を実行します。

  1. アプリのディレクトリに移動します。
  2. アプリを実行する:dotnet <app_assembly.dll>。ここで、app_assembly.dll はアプリのアセンブリ ファイル名です。

アプリがサーバーで実行されているにもかかわらず、インターネット経由で応答がない場合、サーバーのファイアウォールを確認し、ポート 80 が開いていることを確認します。 Azure Ubuntu VM を使用している場合、受信ポート 80 のトラフィックを有効にするネットワーク セキュリティ グループ (NSG) 規則を追加します。 送信トラフィックは、受信規則が有効になると自動的に生成されるので、送信ポート 80 規則を有効にする必要はありません。

アプリのテストが終了したら、コマンド プロンプトで Ctrl+C キー (Windows) または +C キー (macOS) を使用してアプリをシャットダウンします。

keepalive_requests を増やす

keepalive_requests は、パフォーマンスを向上させるために増やすことができます。詳細については、「この GitHub の問題」を参照してください。

アプリを監視する

サーバーは、http://<serveraddress>:80 に対する要求を http://127.0.0.1:5000 の Kestrel で実行されている ASP.NET Core アプリに転送するように設定されています。 ただし、Nginx は Kestrel プロセスを管理するようには設定されていません。 systemd を使用してサービス ファイルを作成し、基になる Web アプリを起動して監視できます。 systemd は init システムであり、プロセスを起動、停止、管理するためのさまざまな高性能機能を提供します。

サービス ファイルを作成する

次のように、サービス定義ファイルを作成します。

sudo nano /etc/systemd/system/kestrel-helloapp.service

アプリ用の .ini サービス ファイルの例を次に示します。

[Unit]
Description=Example .NET Web API App running on Linux

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_NOLOGO=true

[Install]
WantedBy=multi-user.target

前の例では、サービスを管理するユーザーは User オプションによって指定されています。 ユーザー (www-data) が存在し、アプリのファイルの適切な所有権を持っている必要があります。

アプリが最初の割り込み信号を受信してからシャットダウンするのを待機する期間を構成するには、TimeoutStopSec を使用します。 この期間内にアプリがシャットダウンしない場合は、SIGKILL を発行してアプリを終了します。 タイムアウトを無効にするには、値として、単位なしの秒数 (150 など)、期間の値 (2min 30s など)、または infinity を指定します。 TimeoutStopSec には、マネージャー構成ファイル (systemd-system.confsystem.conf.dsystemd-user.confuser.conf.d) の DefaultTimeoutStopSec の値が既定で設定されます。 ほとんどのディストリビューションにおいて、タイムアウトの既定値は 90 秒となります。

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux のファイル システムは大文字と小文字を区別します。 ASPNETCORE_ENVIRONMENTProduction に設定すると、appsettings.production.json ではなく、構成ファイル appsettings.Production.json が検索されます。

構成プロバイダーが環境変数を読み取れるようにするために、一部の値 (たとえば SQL の接続文字列) をエスケープする必要があります。 次のコマンドを使用して、構成ファイルで使用するために適切にエスケープされた値を生成します。

systemd-escape "<value-to-escape>"

コロン (:) 区切り記号は、環境変数の名前ではサポートされていません。 コロンの代わりに 2 つのアンダースコア (__) を使用します。 環境変数が構成に読み取られるときに、環境変数構成プロバイダーによって 2 つのアンダースコアがコロンに変換されます。 次の例では、接続文字列キー ConnectionStrings:DefaultConnection はサービス定義ファイルでは ConnectionStrings__DefaultConnection と設定されています。

Environment=ConnectionStrings__DefaultConnection={Connection String}

ファイルを保存し、サービスを有効にします。

sudo systemctl enable kestrel-helloapp.service

サービスを起動し、動作を確認します。

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Linux
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

構成されたリバース プロキシと systemd 経由で管理される Kestrel を使用して、Web アプリが完全に構成され、http://localhost のローカル コンピューター上のブラウザーからアクセスできます。 妨げとなるファイアウォールがなければ、リモート コンピューターからもアクセスできます。 応答ヘッダーを調べると、ASP.NET Core アプリが Kestrel によって提供されていることが Server ヘッダーに示されています。

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

ログを表示する

Kestrel を利用する Web アプリは systemd を使用して管理されるため、すべてのイベントとプロセスが記録され、中心的ジャーナルが生成されます。 ただし、このジャーナルには、systemd が管理するすべてのサービスとプロセスのすべてのエントリが含まれます。 kestrel-helloapp.service 固有の項目を表示するには、次のコマンドを使用します。

sudo journalctl -fu kestrel-helloapp.service

さらに絞り込むには、--since today--until 1 hour ago などの時間オプション、あるいはこれらの組み合わせを使用することで、返されるエントリ数を減らすことができます。

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

データの保護

ASP.NET Core データ保護スタックは、認証ミドルウェア (cookie ミドルウェアなど) やクロスサイト リクエスト フォージェリ (CSRF) 保護を含む、いくつかの ASP.NET Core ミドルウェアで使用されます。 データ保護 API がユーザーのコードから呼び出されない場合でも、永続的な暗号化キー ストアを作成するようにデータ保護を構成する必要があります。 データ保護を構成しない場合、既定でキーはメモリ内に保持され、アプリが再起動すると破棄されます。

キーリングがメモリに格納されている場合、アプリを再起動すると次のことが行われます。

  • すべての cookie ベースの認証トークンは無効になります。
  • ユーザーは、次回の要求時に再度サインインする必要があります。
  • キーリングで保護されているデータは、いずれも復号化できなくなります。 これには、CSRF トークンASP.NET Core MVC TempData cookie が含まれます。

キー リングを永続化して暗号化するようにデータ保護を構成する場合は、次を参照してください。

要求ヘッダー フィールドが長すぎます

プロキシ サーバーの既定の設定では、通常、プラットフォームに応じて、要求ヘッダー フィールドが 4 K または 8 K に制限されます。 アプリによっては、既定よりも長いフィールドが必要になる場合があります (たとえば、Microsoft Entra ID を使用するアプリ)。 長いフィールドが必要な場合は、プロキシ サーバーの既定の設定に対して調整が必要になります。 適用する値は、シナリオによって異なります。 詳細については、ご利用のサーバーのドキュメントを参照してください。

警告

必要な場合を除いて、プロキシ バッファーの既定値を増やさないでください。 これらの値を増やすと、悪意のあるユーザーによるバッファー オーバーラン (オーバーフロー) とサービス拒否 (DoS) の攻撃のリスクが増加します。

アプリをセキュリティで保護する

AppArmor を有効にする

Linux Security Modules (LSM) は、Linux 2.6 以降の Linux カーネルに含まれるフレームワークです。 LSM は、セキュリティ モジュールのさまざまな実装に対応しています。 AppArmor は Mandatory Access Control システムを実装する LSM です。これにより、プログラムのリソース範囲を限定できます。 AppArmor が有効であり、正しく構成されていることを確認します。

ファイアウォールを構成する

使用されていないすべての外部ポートを閉じます。 Uncomplicated firewall (ufw) は iptables のフロント エンドとなり、ファイアウォールを構成するための CLI が提供されます。

警告

ファイアウォールが正しく構成されていない場合、システム全体にアクセスできません。 正しい SSH ポートを指定しないと、SSH を使用してシステムに接続する場合に、そのシステムから事実上閉め出されることになります。 既定のポートは 22 です。 詳細については、ufw の概要マニュアルを参照してください。

ufw をインストールし、必要なすべてのポートでトラフィックを許可するように構成します。

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Nginx をセキュリティで保護する

Nginx 応答名を変更する

src/http/ngx_http_header_filter_module.cを編集します:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

構成オプション

必要なその他のモジュールでサーバーを構成します。 アプリのセキュリティを強化するために、ModSecurity のような Web アプリのファイアウォールの使用を検討してください。

HTTPS の構成

セキュリティで保護された (HTTPS) ローカル接続用にアプリを構成する

dotnet run コマンドでは、アプリの Properties/launchSettings.json ファイルを使用します。これにより、applicationUrl プロパティによって指定された URL でリッスンするように、アプリが構成されます。 たとえば、「 https://localhost:5001;http://localhost:5000 」のように入力します。

次のいずれかの方法を使用して、dotnet run コマンドまたは開発環境 (F5、Visual Studio Code では Ctrl+F5) の開発で、証明書を使用するようにアプリを構成します。

セキュリティで保護された (HTTPS) クライアント接続用にリバース プロキシを構成する

警告

このセクションのセキュリティ構成は、さらにカスタマイズするための出発点として使用される一般的な構成です。 サードパーティ製のツール、サーバー、およびオペレーティング システムに対しては、サポートを提供できません。 "このセクションの構成は、自己責任で使用してください。 " 詳細については、次のリソースをご覧ください。

  • 信頼された証明機関 (CA) が発行した、有効な証明書を指定することで、ポート 443 で HTTPS トラフィックをリッスンするようにサーバーを構成します。

  • 次の /etc/nginx/nginx.conf ファイルで示されているプラクティスの一部を採用することで、セキュリティを強化します。

  • 次の例では、セキュリティで保護されていない要求をリダイレクトするようにサーバーを構成していません。 HTTPS リダイレクト ミドルウェアを使用することをお勧めします。 詳細については、「ASP.NET Core で HTTPS を適用する」を参照してください。

    Note

    サーバー構成で HTTPS リダイレクト ミドルウェアではなくセキュリティで保護されたリダイレクトを処理する開発環境では、永続的なリダイレクト (301) ではなく、一時的なリダイレクト (302) を使用することをお勧めします。 リンク キャッシュを使用すると、開発環境で不安定な動作が発生する可能性があります。

  • Strict-Transport-Security (HSTS) ヘッダーを追加すると、クライアントが行う後続のすべての要求が HTTPS 経由になります。 Strict-Transport-Security ヘッダーの設定に関するガイダンスについては、「ASP.NET Core で HTTPS を適用する」を参照してください。

  • 今後 HTTPS を無効にする場合は、次のいずれかの方法を使用します。

    • HSTS ヘッダーを追加しない
    • 短い max-age 値を選択する

/etc/nginx/proxy.conf 構成ファイルを追加します。

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto $scheme;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

/etc/nginx/nginx.conf 構成ファイルの内容を次のファイルに置き換えます。 この例では、1 つの構成ファイルに http セクションと server セクションの両方が含まれています。

http {
    include        /etc/nginx/proxy.conf;
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    server_tokens  off;

    sendfile on;
    # Adjust keepalive_timeout to the lowest possible value that makes sense 
    # for your use case.
    keepalive_timeout   29;
    client_body_timeout 10; client_header_timeout 10; send_timeout 10;

    upstream helloapp{
        server 127.0.0.1:5000;
    }

    server {
        listen                    443 ssl http2;
        listen                    [::]:443 ssl http2;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.key;
        ssl_session_timeout       1d;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_session_cache         shared:SSL:10m;
        ssl_session_tickets       off;
        ssl_stapling              off;

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #Redirects all traffic
        location / {
            proxy_pass http://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

Note

アプリによって行われる大量の要求を受け入れる目的で、Blazor WebAssembly アプリの burst パラメーター値を大きくする必要があります。 詳細については、「ASP.NET Core Blazor WebAssembly のホストと展開」を参照してください。

Note

前の例では、オンライン証明書状態プロトコル (OCSP) のスタンプを無効にしています。 有効になっている場合は、証明書でその機能がサポートされていることを確認します。 OCSP を有効にする方法の詳細とガイダンスについては、Module ngx_http_ssl_module (Nginx ドキュメント) の記事の次のプロパティを参照してください。

  • ssl_stapling
  • ssl_stapling_file
  • ssl_stapling_responder
  • ssl_stapling_verify

Nginx をクリックジャッキングから守る

クリックジャッキングは "UI 着せ替え攻撃" とも呼ばれ、Web サイトの訪問者を騙して現在訪れているものとは異なるページのリンクやボタンをクリックさせる悪意のある攻撃です。 サイトをセキュリティで保護するには、X-FRAME-OPTIONS を使います。

クリックジャッキング攻撃を軽減するには、次の手順に従います。

  1. nginx.conf ファイルを編集します。

    sudo nano /etc/nginx/nginx.conf
    

    http{} コード ブロック内に、行 add_header X-Frame-Options "SAMEORIGIN"; を追加します。

  2. ファイルを保存します。

  3. Nginx を再起動します。

MIME タイプ スニッフィング

このヘッダーは応答コンテンツの種類をオーバーライドしないようにブラウザーに指示するので、ほとんどのブラウザーで MIME スニッフィングが阻止されます。 nosniff オプションを指定すると、サーバーでのコンテンツが text/html の場合、ブラウザーでは text/html と表示されます。

  1. nginx.conf ファイルを編集します。

    sudo nano /etc/nginx/nginx.conf
    

    http{} コード ブロック内に、行 add_header X-Content-Type-Options "nosniff"; を追加します。

  2. ファイルを保存します。

  3. Nginx を再起動します。

Nginx に関するその他の推奨事項

サーバー上で共有フレームワークをアップグレードしたら、サーバーによってホストされている ASP.NET Core アプリを再起動します。

その他の技術情報

このガイドでは、Ubuntu 16.04 サーバーで本稼働対応の ASP.NET Core 環境をセットアップする方法について説明します。 これらの手順は、Ubuntu のより新しいバージョンで動作する可能性が高いですが、手順はまだ新しいバージョンでテストされていません。

ASP.NET Core でサポートされている他の Linux ディストリビューションについて詳しくは、「Linux における .NET Core の前提条件」をご覧ください。

Note

Ubuntu 14.04 の場合、Kestrel プロセスを監視するためのソリューションとして supervisord が推奨されます。 systemd は Ubuntu 14.04 ではご利用いただけません。 Ubuntu 14.04 の手順については、このトピックの前のバージョンを参照してください

このガイドでは:

  • リバース プロキシ サーバーの背後に既存の ASP.NET Core アプリを配置します。
  • Kestrel Web サーバーに要求を転送するようにリバース プロキシ サーバーを設定します。
  • Web アプリを起動時にデーモンとして実行します。
  • Web アプリの再起動に役立つようにプロセス管理ツールを構成します。

必須コンポーネント

  • Ubuntu 16.04 サーバーへのアクセスと sudo 特権が与えられた標準ユーザー アカウント。
  • サーバーにインストールされている .NET ランタイムのプレビュー以外の最新バージョン。
  • 既存の ASP.NET Core アプリ。

共有フレームワークをアップグレードした後の任意の時点で、サーバーによってホストされている ASP.NET Core アプリを再起動します。

アプリを介して発行およびコピーする

フレームワークに依存する展開用にアプリを構成します。

アプリが開発環境のローカルで実行され、セキュリティで保護された HTTPS 接続を行うようにサーバーによって構成されていない場合は、次のいずれかの方法を採用してください。

  • セキュリティで保護されたローカル接続を処理するようにアプリを構成します。 詳しくは、「HTTPS の構成」セクションをご覧ください。

  • セキュリティで保護されていないエンドポイントで実行するようにアプリを構成します。

    • 開発環境 (Program.cs) で HTTPS リダイレクト ミドルウェアを非アクティブ化します。

      if (!app.Environment.IsDevelopment())
      {
          app.UseHttpsRedirection();
      }
      

      詳細については、「ASP.NET Core で複数の環境を使用する」を参照してください。

    • Properties/launchSettings.json ファイルの applicationUrl プロパティから https://localhost:5001 を削除します (ある場合)。

環境別の構成については、「ASP.NET Core で複数の環境を使用する」を参照してください。

開発環境から dotnet publish を実行して、サーバー上で実行できるディレクトリ (例: bin/Release/{TARGET FRAMEWORK MONIKER}/publish。このプレースホルダー {TARGET FRAMEWORK MONIKER} はターゲット フレームワーク モニカー/TFM です) にアプリをパッケージします。

dotnet publish --configuration Release

サーバーで .NET Core ランタイムを管理しない場合、アプリは独立した展開として発行することもできます。

組織のワークフローに統合されているツール (SCPSFTP など) を使用して、サーバーに ASP.NET Core アプリをコピーします。 Web アプリは一般的に var ディレクトリの下に配置されます (たとえば、var/www/helloapp)。

Note

運用展開シナリオの場合、継続的インテグレーション ワークフローが、アプリの発行処理とサーバーへの資産のコピーを行います。

アプリをテストします。

  1. コマンド ラインから dotnet <app_assembly>.dll アプリを実行します。
  2. ブラウザーで、http://<serveraddress>:<port> に移動し、アプリが Linux のローカルで動作することを検証します。

リバース プロキシ サーバーを構成する

リバース プロキシは、動的 Web アプリを提供するための一般的な仕組みです。 リバース プロキシは HTTP 要求を終了させ、ASP.NET Core アプリに転送します。

リバース プロキシ サーバーを利用する

Kestrel は、ASP.NET Core から動的なコンテンツを提供するのに役立ちます。 ただし、Web サーバーとしての機能は、IIS、Apache、Nginx などのサーバーと比べると制限されます。 リバース プロキシ サーバーは、静的コンテンツ サービス、要求のキャッシュ、要求の圧縮、HTTP サーバーからの HTTPS 終了などの作業の負荷を軽減します。 リバース プロキシ サーバーは専用コンピューター上に置かれることもあれば、HTTP サーバーと並んで展開されることもあります。

このガイドの目的のために、単一インスタンスの Nginx が使用されます。 HTTP サーバーと並んで、同じサーバー上で実行されます。 要件に応じて、別のセットアップを選択することも可能です。

要求はリバース プロキシによって転送されるため、Microsoft.AspNetCore.HttpOverrides パッケージの Forwarded Headers Middleware を使用します。 リダイレクト URI とその他のセキュリティ ポリシーを正しく機能させるために、このミドルウェアは、X-Forwarded-Proto ヘッダーを利用して、Request.Scheme を更新します。

Forwarded Headers Middleware は、他のミドルウェアの前に実行する必要があります。 この順序により、転送されるヘッダー情報に依存するミドルウェアが処理にヘッダー値を使用できます。 診断およびエラー処理ミドルウェアの後に Forwarded Headers Middleware を実行する方法については、「Forwarded Headers Middleware の順序」を参照してください。

他のミドルウェアを呼び出す前に、Program.cs の一番上にある UseForwardedHeaders メソッドを呼び出します。 ミドルウェアを構成して、X-Forwarded-For および X-Forwarded-Proto ヘッダーを転送します。

// requires using Microsoft.AspNetCore.HttpOverrides;
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

ミドルウェアに対して ForwardedHeadersOptions が指定されていない場合、転送される既定のヘッダーは None です。

標準 localhost アドレス (127.0.0.1) を含むループバック アドレス (127.0.0.0/8[::1]) 上で実行されるプロキシは、既定で信頼されます。 組織内のその他の信頼されているプロキシまたはネットワークによってインターネットと Web サーバーの間の要求が処理される場合は、それらを、ForwardedHeadersOptions を使用して KnownProxies または KnownNetworks のリストに追加します。 次の例では、IP アドレス 10.0.0.100 にある信頼されているプロキシ サーバーが Program.cs 内の Forwarded Headers Middleware KnownProxies に追加されます。

using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

詳細については、「プロキシ サーバーとロード バランサーを使用するために ASP.NET Core を構成する」を参照してください。

Nginx をインストールする

apt-get を利用し、Nginx をインストールします。 インストーラーにより systemd init スクリプトが作成されます。このスクリプトがシステム起動時に Nginx をデーモンとして実行します。 「Nginx: Official Debian/Ubuntu packages」 (Nginx: 公式 Debian/Ubuntu パッケージ) にある Ubuntu 用のインストールの指示に従います。

Note

オプションの Nginx モジュールが必要な場合、Nginx をソースからビルドする必要がある場合があります。

Nginx は初めてのインストールとなるので、次を実行して明示的に起動します。

sudo service nginx start

ブラウザーで Nginx の既定のランディング ページが表示されることを確認します。 ランディング ページは http://<server_IP_address>/index.nginx-debian.html からアクセスできます。

Nginx を構成する

Nginx をリバース プロキシとして構成し、ASP.NET Core アプリに HTTP 要求を転送するには、/etc/nginx/sites-available/default を変更します。 テキスト エディターでそれを開き、内容を次のスニペットに置き換えます。

server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

アプリが SignalR または Blazor Server アプリの場合、詳細については、それぞれ ASP.NET Core SignalR 運用環境のホスティングとスケーリング、および ASP.NET Core サーバー側 Blazor アプリのホストと展開に関するページを参照してください。

server_name が一致しない場合、Nginx では既定のサーバーが使用されます。 既定のサーバーが定義されていない場合、構成ファイルの最初のサーバーが既定のサーバーとなります。 ベスト プラクティスとして、自分の構成ファイルで 444 の状態コードを返す既定のサーバーを具体的に追加します。 既定のサーバーの構成例は次のとおりです。

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

上記の構成ファイルと既定のサーバーでは、Nginx は、ホスト ヘッダー example.com または *.example.com で、ポート 80 でパブリック トラフィックを受け入れます。 これらのホストと一致しない要求は、Kestrel に転送されません。 Nginx により一致する要求が、http://127.0.0.1:5000 の Kestrel に転送されます。 詳細については、「How nginx processes a request」(Nginx で要求を処理する方法) を参照してください。 Kestrel の IP/ポートを変更する場合は、Kestrel のエンドポイントの構成に関する記事を参照してください。

警告

適切な server_name directive を指定しないと、アプリにセキュリティ上の脆弱性が生じます。 親ドメイン全体を制御する場合、サブドメイン ワイルドカード バインド (たとえば、*.example.com) にこのセキュリティ リスクはありません (脆弱である *.com とは対照的)。 詳細については、RFC 9110: HTTP セマンティクス (セクション 7.2: 「Host and :authority (ホストと :authority)」) に関するページを参照してください。

Nginx の構成を確立したら、sudo nginx -t を実行して構成ファイルの構文を確認します。 構成ファイルがテストに合格したら、sudo nginx -s reload を実行することで、強制的に Nginx に変更を反映させます。

アプリをサーバーで直接実行するには、次を実行します。

  1. アプリのディレクトリに移動します。
  2. アプリを実行する:dotnet <app_assembly.dll>。ここで、app_assembly.dll はアプリのアセンブリ ファイル名です。

アプリがサーバーで実行されているにも関わらず、インターネット経由で応答がない場合、サーバーのファイアウォールを確認し、ポート 80 が開いていることを確認します。 Azure Ubuntu VM を使用している場合、受信ポート 80 のトラフィックを有効にするネットワーク セキュリティ グループ (NSG) 規則を追加します。 送信トラフィックは、受信規則が有効になると自動的に生成されるので、送信ポート 80 規則を有効にする必要はありません。

アプリのテストが終了したら、コマンド プロンプトで Ctrl+C キー (Windows) または +C キー (macOS) を使用してアプリをシャットダウンします。

アプリを監視する

サーバーは、http://<serveraddress>:80 に対する要求を http://127.0.0.1:5000 の Kestrel で実行されている ASP.NET Core アプリに転送するように設定されています。 ただし、Nginx は Kestrel プロセスを管理するようには設定されていません。 systemd を使用してサービス ファイルを作成し、基になる Web アプリを起動して監視できます。 systemd は init システムであり、プロセスを起動、停止、管理するためのさまざまな高性能機能を提供します。

サービス ファイルを作成する

次のように、サービス定義ファイルを作成します。

sudo nano /etc/systemd/system/kestrel-helloapp.service

アプリ用のサービス ファイルの例を次に示します。

[Unit]
Description=Example .NET Web API App running on Ubuntu

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_NOLOGO=true

[Install]
WantedBy=multi-user.target

前の例では、サービスを管理するユーザーは User オプションによって指定されています。 ユーザー (www-data) が存在し、アプリのファイルの適切な所有権を持っている必要があります。

アプリが最初の割り込み信号を受信してからシャットダウンするのを待機する期間を構成するには、TimeoutStopSec を使用します。 この期間内にアプリがシャットダウンしない場合は、SIGKILL を発行してアプリを終了します。 タイムアウトを無効にするには、値として、単位なしの秒数 (150 など)、期間の値 (2min 30s など)、または infinity を指定します。 TimeoutStopSec には、マネージャー構成ファイル (systemd-system.confsystem.conf.dsystemd-user.confuser.conf.d) の DefaultTimeoutStopSec の値が既定で設定されます。 ほとんどのディストリビューションにおいて、タイムアウトの既定値は 90 秒となります。

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux のファイル システムは大文字と小文字を区別します。 ASPNETCORE_ENVIRONMENTProduction に設定すると、appsettings.production.json ではなく、構成ファイル appsettings.Production.json が検索されます。

構成プロバイダーが環境変数を読み取れるようにするために、一部の値 (たとえば SQL の接続文字列) をエスケープする必要があります。 次のコマンドを使用して、構成ファイルで使用するために適切にエスケープされた値を生成します。

systemd-escape "<value-to-escape>"

コロン (:) 区切り記号は、環境変数の名前ではサポートされていません。 コロンの代わりに 2 つのアンダースコア (__) を使用します。 環境変数が構成に読み取られるときに、環境変数構成プロバイダーによって 2 つのアンダースコアがコロンに変換されます。 次の例では、接続文字列キー ConnectionStrings:DefaultConnection はサービス定義ファイルでは ConnectionStrings__DefaultConnection と設定されています。

Environment=ConnectionStrings__DefaultConnection={Connection String}

ファイルを保存し、サービスを有効にします。

sudo systemctl enable kestrel-helloapp.service

サービスを起動し、動作を確認します。

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Ubuntu
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

構成されたリバース プロキシと systemd 経由で管理される Kestrel を使用して、Web アプリが完全に構成され、http://localhost のローカル コンピューター上のブラウザーからアクセスできます。 妨げとなるファイアウォールがなければ、リモート コンピューターからもアクセスできます。 応答ヘッダーを調べると、ASP.NET Core アプリが Kestrel によって提供されていることが Server ヘッダーに示されています。

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

ログを表示する

Kestrel を利用する Web アプリは systemd を使用して管理されるため、すべてのイベントとプロセスが記録され、中心的ジャーナルが生成されます。 ただし、このジャーナルには、systemd が管理するすべてのサービスとプロセスのすべてのエントリが含まれます。 kestrel-helloapp.service 固有の項目を表示するには、次のコマンドを使用します。

sudo journalctl -fu kestrel-helloapp.service

さらに絞り込むには、--since today--until 1 hour ago などの時間オプション、あるいはこれらの組み合わせを使用することで、返されるエントリ数を減らすことができます。

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

データの保護

ASP.NET Core データ保護スタックは、認証ミドルウェア (cookie ミドルウェアなど) やクロスサイト リクエスト フォージェリ (CSRF) 保護を含む、いくつかの ASP.NET Core ミドルウェアで使用されます。 データ保護 API がユーザーのコードから呼び出されない場合でも、永続的な暗号化キー ストアを作成するようにデータ保護を構成する必要があります。 データ保護を構成しない場合、既定でキーはメモリ内に保持され、アプリが再起動すると破棄されます。

キーリングがメモリに格納されている場合、アプリを再起動すると次のことが行われます。

  • すべての cookie ベースの認証トークンは無効になります。
  • ユーザーは、次回の要求時に再度サインインする必要があります。
  • キーリングで保護されているデータは、いずれも復号化できなくなります。 これには、CSRF トークンASP.NET Core MVC TempData cookie が含まれます。

キー リングを永続化して暗号化するようにデータ保護を構成する場合は、次を参照してください。

要求ヘッダー フィールドが長すぎます

プロキシ サーバーの既定の設定では、通常、プラットフォームに応じて、要求ヘッダー フィールドが 4 K または 8 K に制限されます。 アプリでは、既定値よりも長いフィールドが必要になる場合があります (たとえば、Azure Active Directory を使用するアプリ)。 長いフィールドが必要な場合は、プロキシ サーバーの既定の設定に対して調整が必要になります。 適用する値は、シナリオによって異なります。 詳細については、ご利用のサーバーのドキュメントを参照してください。

警告

必要な場合を除いて、プロキシ バッファーの既定値を増やさないでください。 これらの値を増やすと、悪意のあるユーザーによるバッファー オーバーラン (オーバーフロー) とサービス拒否 (DoS) の攻撃のリスクが増加します。

アプリをセキュリティで保護する

AppArmor を有効にする

Linux Security Modules (LSM) は、Linux 2.6 以降の Linux カーネルに含まれるフレームワークです。 LSM は、セキュリティ モジュールのさまざまな実装に対応しています。 AppArmor は Mandatory Access Control システムを実装する LSM です。これにより、プログラムのリソース範囲を限定できます。 AppArmor が有効であり、正しく構成されていることを確認します。

ファイアウォールを構成する

使用されていないすべての外部ポートを閉じます。 Uncomplicated firewall (ufw) は iptables のフロント エンドとなり、ファイアウォールを構成するための CLI が提供されます。

警告

ファイアウォールが正しく構成されていない場合、システム全体にアクセスできません。 正しい SSH ポートを指定しないと、SSH を使用してシステムに接続する場合に、そのシステムから事実上閉め出されることになります。 既定のポートは 22 です。 詳細については、ufw の概要マニュアルを参照してください。

ufw をインストールし、必要なすべてのポートでトラフィックを許可するように構成します。

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Nginx をセキュリティで保護する

Nginx 応答名を変更する

src/http/ngx_http_header_filter_module.cを編集します:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

構成オプション

必要なその他のモジュールでサーバーを構成します。 アプリのセキュリティを強化するために、ModSecurity のような Web アプリのファイアウォールの使用を検討してください。

HTTPS の構成

セキュリティで保護された (HTTPS) ローカル接続用にアプリを構成する

dotnet run コマンドでは、アプリの Properties/launchSettings.json ファイルを使用します。これにより、applicationUrl プロパティによって指定された URL でリッスンするように、アプリが構成されます。 たとえば、「 https://localhost:5001;http://localhost:5000 」のように入力します。

次のいずれかの方法を使用して、dotnet run コマンドまたは開発環境 (F5、Visual Studio Code では Ctrl+F5) の開発で、証明書を使用するようにアプリを構成します。

セキュリティで保護された (HTTPS) クライアント接続用にリバース プロキシを構成する

警告

このセクションのセキュリティ構成は、さらにカスタマイズするための出発点として使用される一般的な構成です。 サードパーティ製のツール、サーバー、およびオペレーティング システムに対しては、サポートを提供できません。 "このセクションの構成は、自己責任で使用してください。 " 詳細については、次のリソースをご覧ください。

  • 信頼された証明機関 (CA) が発行した、有効な証明書を指定することで、ポート 443 で HTTPS トラフィックをリッスンするようにサーバーを構成します。

  • 次の /etc/nginx/nginx.conf ファイルで示されているプラクティスの一部を採用することで、セキュリティを強化します。

  • 次の例では、セキュリティで保護されていない要求をリダイレクトするようにサーバーを構成していません。 HTTPS リダイレクト ミドルウェアを使用することをお勧めします。 詳細については、「ASP.NET Core で HTTPS を適用する」を参照してください。

    Note

    サーバー構成で HTTPS リダイレクト ミドルウェアではなくセキュリティで保護されたリダイレクトを処理する開発環境では、永続的なリダイレクト (301) ではなく、一時的なリダイレクト (302) を使用することをお勧めします。 リンク キャッシュを使用すると、開発環境で不安定な動作が発生する可能性があります。

  • Strict-Transport-Security (HSTS) ヘッダーを追加すると、クライアントが行う後続のすべての要求が HTTPS 経由になります。 Strict-Transport-Security ヘッダーの設定に関するガイダンスについては、「ASP.NET Core で HTTPS を適用する」を参照してください。

  • 今後 HTTPS を無効にする場合は、次のいずれかの方法を使用します。

    • HSTS ヘッダーを追加しない
    • 短い max-age 値を選択する

/etc/nginx/proxy.conf 構成ファイルを追加します。

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto $scheme;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

/etc/nginx/nginx.conf 構成ファイルの内容を次のファイルに置き換えます。 この例では、1 つの構成ファイルに http セクションと server セクションの両方が含まれています。

http {
    include        /etc/nginx/proxy.conf;
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    server_tokens  off;

    sendfile on;
    # Adjust keepalive_timeout to the lowest possible value that makes sense 
    # for your use case.
    keepalive_timeout   29;
    client_body_timeout 10; client_header_timeout 10; send_timeout 10;

    upstream helloapp{
        server 127.0.0.1:5000;
    }

    server {
        listen                    443 ssl http2;
        listen                    [::]:443 ssl http2;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.key;
        ssl_session_timeout       1d;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_session_cache         shared:SSL:10m;
        ssl_session_tickets       off;
        ssl_stapling              off;

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #Redirects all traffic
        location / {
            proxy_pass http://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

Note

アプリによって行われる大量の要求を受け入れる目的で、Blazor WebAssembly アプリの burst パラメーター値を大きくする必要があります。 詳細については、「ASP.NET Core Blazor WebAssembly のホストと展開」を参照してください。

Note

前の例では、オンライン証明書状態プロトコル (OCSP) のスタンプを無効にしています。 有効になっている場合は、証明書でその機能がサポートされていることを確認します。 OCSP を有効にする方法の詳細とガイダンスについては、Module ngx_http_ssl_module (Nginx ドキュメント) の記事の次のプロパティを参照してください。

  • ssl_stapling
  • ssl_stapling_file
  • ssl_stapling_responder
  • ssl_stapling_verify

Nginx をクリックジャッキングから守る

クリックジャッキングは "UI 着せ替え攻撃" とも呼ばれ、Web サイトの訪問者を騙して現在訪れているものとは異なるページのリンクやボタンをクリックさせる悪意のある攻撃です。 サイトをセキュリティで保護するには、X-FRAME-OPTIONS を使います。

クリックジャッキング攻撃を軽減するには、次の手順に従います。

  1. nginx.conf ファイルを編集します。

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Frame-Options "SAMEORIGIN"; を追加します。

  2. ファイルを保存します。

  3. Nginx を再起動します。

MIME タイプ スニッフィング

このヘッダーは応答コンテンツの種類をオーバーライドしないようにブラウザーに指示するので、ほとんどのブラウザーで MIME スニッフィングが阻止されます。 nosniff オプションを指定すると、サーバーでのコンテンツが text/html の場合、ブラウザーでは text/html と表示されます。

  1. nginx.conf ファイルを編集します。

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Content-Type-Options "nosniff"; を追加します。

  2. ファイルを保存します。

  3. Nginx を再起動します。

Nginx に関するその他の推奨事項

サーバー上で共有フレームワークをアップグレードしたら、サーバーによってホストされている ASP.NET Core アプリを再起動します。

その他の技術情報

このガイドでは、Ubuntu 16.04 サーバーで本稼働対応の ASP.NET Core 環境をセットアップする方法について説明します。 これらの手順は、Ubuntu のより新しいバージョンで動作する可能性が高いですが、手順はまだ新しいバージョンでテストされていません。

ASP.NET Core でサポートされている他の Linux ディストリビューションについて詳しくは、「Linux における .NET Core の前提条件」をご覧ください。

Note

Ubuntu 14.04 の場合、Kestrel プロセスを監視するためのソリューションとして supervisord が推奨されます。 systemd は Ubuntu 14.04 ではご利用いただけません。 Ubuntu 14.04 の手順については、このトピックの前のバージョンを参照してください

このガイドでは:

  • リバース プロキシ サーバーの背後に既存の ASP.NET Core アプリを配置します。
  • Kestrel Web サーバーに要求を転送するようにリバース プロキシ サーバーを設定します。
  • Web アプリを起動時にデーモンとして実行します。
  • Web アプリの再起動に役立つようにプロセス管理ツールを構成します。

必須コンポーネント

  • Ubuntu 16.04 サーバーへのアクセスと sudo 特権が与えられた標準ユーザー アカウント。
  • サーバーにインストールされている .NET ランタイムのプレビュー以外の最新バージョン。
  • 既存の ASP.NET Core アプリ。

共有フレームワークをアップグレードした後の任意の時点で、サーバーによってホストされている ASP.NET Core アプリを再起動します。

アプリを介して発行およびコピーする

フレームワークに依存する展開用にアプリを構成します。

アプリが開発環境のローカルで実行され、セキュリティで保護された HTTPS 接続を行うようにサーバーによって構成されていない場合は、次のいずれかの方法を採用してください。

  • セキュリティで保護されたローカル接続を処理するようにアプリを構成します。 詳しくは、「HTTPS の構成」セクションをご覧ください。

  • セキュリティで保護されていないエンドポイントで実行するようにアプリを構成します。

    • 開発環境 (Program.cs) で HTTPS リダイレクト ミドルウェアを非アクティブ化します。

      if (!app.Environment.IsDevelopment())
      {
          app.UseHttpsRedirection();
      }
      

      詳細については、「ASP.NET Core で複数の環境を使用する」を参照してください。

    • Properties/launchSettings.json ファイルの applicationUrl プロパティから https://localhost:5001 を削除します (ある場合)。

環境別の構成については、「ASP.NET Core で複数の環境を使用する」を参照してください。

開発環境から dotnet publish を実行して、サーバー上で実行できるディレクトリ (例: bin/Release/{TARGET FRAMEWORK MONIKER}/publish。このプレースホルダー {TARGET FRAMEWORK MONIKER} はターゲット フレームワーク モニカー/TFM です) にアプリをパッケージします。

dotnet publish --configuration Release

サーバーで .NET Core ランタイムを管理しない場合、アプリは独立した展開として発行することもできます。

組織のワークフローに統合されているツール (SCPSFTP など) を使用して、サーバーに ASP.NET Core アプリをコピーします。 Web アプリは一般的に var ディレクトリの下に配置されます (たとえば、var/www/helloapp)。

Note

運用展開シナリオの場合、継続的インテグレーション ワークフローが、アプリの発行処理とサーバーへの資産のコピーを行います。

アプリをテストします。

  1. コマンド ラインから dotnet <app_assembly>.dll アプリを実行します。
  2. ブラウザーで、http://<serveraddress>:<port> に移動し、アプリが Linux のローカルで動作することを検証します。

リバース プロキシ サーバーを構成する

リバース プロキシは、動的 Web アプリを提供するための一般的な仕組みです。 リバース プロキシは HTTP 要求を終了させ、ASP.NET Core アプリに転送します。

リバース プロキシ サーバーを利用する

Kestrel は、ASP.NET Core から動的なコンテンツを提供するのに役立ちます。 ただし、Web サーバーとしての機能は、IIS、Apache、Nginx などのサーバーと比べると制限されます。 リバース プロキシ サーバーは、静的コンテンツ サービス、要求のキャッシュ、要求の圧縮、HTTP サーバーからの HTTPS 終了などの作業の負荷を軽減します。 リバース プロキシ サーバーは専用コンピューター上に置かれることもあれば、HTTP サーバーと並んで展開されることもあります。

このガイドの目的のために、単一インスタンスの Nginx が使用されます。 HTTP サーバーと並んで、同じサーバー上で実行されます。 要件に応じて、別のセットアップを選択することも可能です。

要求はリバース プロキシによって転送されるため、Microsoft.AspNetCore.HttpOverrides パッケージの Forwarded Headers Middleware を使用します。 リダイレクト URI とその他のセキュリティ ポリシーを正しく機能させるために、このミドルウェアは、X-Forwarded-Proto ヘッダーを利用して、Request.Scheme を更新します。

Forwarded Headers Middleware は、他のミドルウェアの前に実行する必要があります。 この順序により、転送されるヘッダー情報に依存するミドルウェアが処理にヘッダー値を使用できます。 診断およびエラー処理ミドルウェアの後に Forwarded Headers Middleware を実行する方法については、「Forwarded Headers Middleware の順序」を参照してください。

他のミドルウェアを呼び出す前に、Startup.Configure の一番上にある UseForwardedHeaders メソッドを呼び出します。 ミドルウェアを構成して、X-Forwarded-For および X-Forwarded-Proto ヘッダーを転送します。

using Microsoft.AspNetCore.HttpOverrides;

...

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

ミドルウェアに対して ForwardedHeadersOptions が指定されていない場合、転送される既定のヘッダーは None です。

標準 localhost アドレス (127.0.0.1) を含むループバック アドレス (127.0.0.0/8[::1]) 上で実行されるプロキシは、既定で信頼されます。 組織内のその他の信頼されているプロキシまたはネットワークによってインターネットと Web サーバーの間の要求が処理される場合は、それらを、ForwardedHeadersOptions を使用して KnownProxies または KnownNetworks のリストに追加します。 次の例では、IP アドレス 10.0.0.100 にある信頼されているプロキシ サーバーが Startup.ConfigureServices 内の Forwarded Headers Middleware KnownProxies に追加されます。

using System.Net;

...

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

詳細については、「プロキシ サーバーとロード バランサーを使用するために ASP.NET Core を構成する」を参照してください。

Nginx をインストールする

apt-get を利用し、Nginx をインストールします。 インストーラーにより systemd init スクリプトが作成されます。このスクリプトがシステム起動時に Nginx をデーモンとして実行します。 「Nginx: Official Debian/Ubuntu packages」 (Nginx: 公式 Debian/Ubuntu パッケージ) にある Ubuntu 用のインストールの指示に従います。

Note

オプションの Nginx モジュールが必要な場合、Nginx をソースからビルドする必要がある場合があります。

Nginx は初めてのインストールとなるので、次を実行して明示的に起動します。

sudo service nginx start

ブラウザーで Nginx の既定のランディング ページが表示されることを確認します。 ランディング ページは http://<server_IP_address>/index.nginx-debian.html からアクセスできます。

Nginx を構成する

Nginx をリバース プロキシとして構成し、ASP.NET Core アプリに HTTP 要求を転送するには、/etc/nginx/sites-available/default を変更します。 テキスト エディターでそれを開き、内容を次のスニペットに置き換えます。

server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

アプリが SignalR または Blazor Server アプリの場合、詳細については、それぞれ ASP.NET Core SignalR 運用環境のホスティングとスケーリング、および ASP.NET Core サーバー側 Blazor アプリのホストと展開に関するページを参照してください。

server_name が一致しない場合、Nginx では既定のサーバーが使用されます。 既定のサーバーが定義されていない場合、構成ファイルの最初のサーバーが既定のサーバーとなります。 ベスト プラクティスとして、自分の構成ファイルで 444 の状態コードを返す既定のサーバーを具体的に追加します。 既定のサーバーの構成例は次のとおりです。

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

上記の構成ファイルと既定のサーバーでは、Nginx は、ホスト ヘッダー example.com または *.example.com で、ポート 80 でパブリック トラフィックを受け入れます。 これらのホストと一致しない要求は、Kestrel に転送されません。 Nginx により一致する要求が、http://127.0.0.1:5000 の Kestrel に転送されます。 詳細については、「How nginx processes a request」(Nginx で要求を処理する方法) を参照してください。 Kestrel の IP/ポートを変更する場合は、Kestrel のエンドポイントの構成に関する記事を参照してください。

警告

適切な server_name directive を指定しないと、アプリにセキュリティ上の脆弱性が生じます。 親ドメイン全体を制御する場合、サブドメイン ワイルドカード バインド (たとえば、*.example.com) にこのセキュリティ リスクはありません (脆弱である *.com とは対照的)。 詳細については、RFC 9110: HTTP セマンティクス (セクション 7.2: 「Host and :authority (ホストと :authority)」) に関するページを参照してください。

Nginx の構成を確立したら、sudo nginx -t を実行して構成ファイルの構文を確認します。 構成ファイルがテストに合格したら、sudo nginx -s reload を実行することで、強制的に Nginx に変更を反映させます。

アプリをサーバーで直接実行するには、次を実行します。

  1. アプリのディレクトリに移動します。
  2. アプリを実行する:dotnet <app_assembly.dll>。ここで、app_assembly.dll はアプリのアセンブリ ファイル名です。

アプリがサーバーで実行されているにも関わらず、インターネット経由で応答がない場合、サーバーのファイアウォールを確認し、ポート 80 が開いていることを確認します。 Azure Ubuntu VM を使用している場合、受信ポート 80 のトラフィックを有効にするネットワーク セキュリティ グループ (NSG) 規則を追加します。 送信トラフィックは、受信規則が有効になると自動的に生成されるので、送信ポート 80 規則を有効にする必要はありません。

アプリのテストが終了したら、コマンド プロンプトで Ctrl+C キー (Windows) または +C キー (macOS) を使用してアプリをシャットダウンします。

アプリを監視する

サーバーは、http://<serveraddress>:80 に対する要求を http://127.0.0.1:5000 の Kestrel で実行されている ASP.NET Core アプリに転送するように設定されています。 ただし、Nginx は Kestrel プロセスを管理するようには設定されていません。 systemd を使用してサービス ファイルを作成し、基になる Web アプリを起動して監視できます。 systemd は init システムであり、プロセスを起動、停止、管理するためのさまざまな高性能機能を提供します。

サービス ファイルを作成する

次のように、サービス定義ファイルを作成します。

sudo nano /etc/systemd/system/kestrel-helloapp.service

アプリ用のサービス ファイルの例を次に示します。

[Unit]
Description=Example .NET Web API App running on Ubuntu

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

前の例では、サービスを管理するユーザーは User オプションによって指定されています。 ユーザー (www-data) が存在し、アプリのファイルの適切な所有権を持っている必要があります。

アプリが最初の割り込み信号を受信してからシャットダウンするのを待機する期間を構成するには、TimeoutStopSec を使用します。 この期間内にアプリがシャットダウンしない場合は、SIGKILL を発行してアプリを終了します。 タイムアウトを無効にするには、値として、単位なしの秒数 (150 など)、期間の値 (2min 30s など)、または infinity を指定します。 TimeoutStopSec には、マネージャー構成ファイル (systemd-system.confsystem.conf.dsystemd-user.confuser.conf.d) の DefaultTimeoutStopSec の値が既定で設定されます。 ほとんどのディストリビューションにおいて、タイムアウトの既定値は 90 秒となります。

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux のファイル システムは大文字と小文字を区別します。 ASPNETCORE_ENVIRONMENTProduction に設定すると、appsettings.production.json ではなく、構成ファイル appsettings.Production.json が検索されます。

構成プロバイダーが環境変数を読み取れるようにするために、一部の値 (たとえば SQL の接続文字列) をエスケープする必要があります。 次のコマンドを使用して、構成ファイルで使用するために適切にエスケープされた値を生成します。

systemd-escape "<value-to-escape>"

コロン (:) 区切り記号は、環境変数の名前ではサポートされていません。 コロンの代わりに 2 つのアンダースコア (__) を使用します。 環境変数が構成に読み取られるときに、環境変数構成プロバイダーによって 2 つのアンダースコアがコロンに変換されます。 次の例では、接続文字列キー ConnectionStrings:DefaultConnection はサービス定義ファイルでは ConnectionStrings__DefaultConnection と設定されています。

Environment=ConnectionStrings__DefaultConnection={Connection String}

ファイルを保存し、サービスを有効にします。

sudo systemctl enable kestrel-helloapp.service

サービスを起動し、動作を確認します。

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Ubuntu
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

構成されたリバース プロキシと systemd 経由で管理される Kestrel を使用して、Web アプリが完全に構成され、http://localhost のローカル コンピューター上のブラウザーからアクセスできます。 妨げとなるファイアウォールがなければ、リモート コンピューターからもアクセスできます。 応答ヘッダーを調べると、ASP.NET Core アプリが Kestrel によって提供されていることが Server ヘッダーに示されています。

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

ログを表示する

Kestrel を利用する Web アプリは systemd を使用して管理されるため、すべてのイベントとプロセスが記録され、中心的ジャーナルが生成されます。 ただし、このジャーナルには、systemd が管理するすべてのサービスとプロセスのすべてのエントリが含まれます。 kestrel-helloapp.service 固有の項目を表示するには、次のコマンドを使用します。

sudo journalctl -fu kestrel-helloapp.service

さらに絞り込むには、--since today--until 1 hour ago などの時間オプション、あるいはこれらの組み合わせを使用することで、返されるエントリ数を減らすことができます。

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

データの保護

ASP.NET Core データ保護スタックは、認証ミドルウェア (cookie ミドルウェアなど) やクロスサイト リクエスト フォージェリ (CSRF) 保護を含む、いくつかの ASP.NET Core ミドルウェアで使用されます。 データ保護 API がユーザーのコードから呼び出されない場合でも、永続的な暗号化キー ストアを作成するようにデータ保護を構成する必要があります。 データ保護を構成しない場合、既定でキーはメモリ内に保持され、アプリが再起動すると破棄されます。

キーリングがメモリに格納されている場合、アプリを再起動すると次のことが行われます。

  • すべての cookie ベースの認証トークンは無効になります。
  • ユーザーは、次回の要求時に再度サインインする必要があります。
  • キーリングで保護されているデータは、いずれも復号化できなくなります。 これには、CSRF トークンASP.NET Core MVC TempData cookie が含まれます。

キー リングを永続化して暗号化するようにデータ保護を構成する場合は、次を参照してください。

要求ヘッダー フィールドが長すぎます

プロキシ サーバーの既定の設定では、通常、プラットフォームに応じて、要求ヘッダー フィールドが 4 K または 8 K に制限されます。 アプリでは、既定値よりも長いフィールドが必要になる場合があります (たとえば、Azure Active Directory を使用するアプリ)。 長いフィールドが必要な場合は、プロキシ サーバーの既定の設定に対して調整が必要になります。 適用する値は、シナリオによって異なります。 詳細については、ご利用のサーバーのドキュメントを参照してください。

警告

必要な場合を除いて、プロキシ バッファーの既定値を増やさないでください。 これらの値を増やすと、悪意のあるユーザーによるバッファー オーバーラン (オーバーフロー) とサービス拒否 (DoS) の攻撃のリスクが増加します。

アプリをセキュリティで保護する

AppArmor を有効にする

Linux Security Modules (LSM) は、Linux 2.6 以降の Linux カーネルに含まれるフレームワークです。 LSM は、セキュリティ モジュールのさまざまな実装に対応しています。 AppArmor は Mandatory Access Control システムを実装する LSM です。これにより、プログラムのリソース範囲を限定できます。 AppArmor が有効であり、正しく構成されていることを確認します。

ファイアウォールを構成する

使用されていないすべての外部ポートを閉じます。 Uncomplicated firewall (ufw) は iptables のフロント エンドとなり、ファイアウォールを構成するための CLI が提供されます。

警告

ファイアウォールが正しく構成されていない場合、システム全体にアクセスできません。 正しい SSH ポートを指定しないと、SSH を使用してシステムに接続する場合に、そのシステムから事実上閉め出されることになります。 既定のポートは 22 です。 詳細については、ufw の概要マニュアルを参照してください。

ufw をインストールし、必要なすべてのポートでトラフィックを許可するように構成します。

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Nginx をセキュリティで保護する

Nginx 応答名を変更する

src/http/ngx_http_header_filter_module.cを編集します:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

構成オプション

必要なその他のモジュールでサーバーを構成します。 アプリのセキュリティを強化するために、ModSecurity のような Web アプリのファイアウォールの使用を検討してください。

HTTPS の構成

セキュリティで保護された (HTTPS) ローカル接続用にアプリを構成する

dotnet run コマンドでは、アプリの Properties/launchSettings.json ファイルを使用します。これにより、applicationUrl プロパティによって指定された URL でリッスンするように、アプリが構成されます。 たとえば、「 https://localhost:5001;http://localhost:5000 」のように入力します。

次のいずれかの方法を使用して、dotnet run コマンドまたは開発環境 (F5、Visual Studio Code では Ctrl+F5) の開発で、証明書を使用するようにアプリを構成します。

セキュリティで保護された (HTTPS) クライアント接続用にリバース プロキシを構成する

警告

このセクションのセキュリティ構成は、さらにカスタマイズするための出発点として使用される一般的な構成です。 サードパーティ製のツール、サーバー、およびオペレーティング システムに対しては、サポートを提供できません。 "このセクションの構成は、自己責任で使用してください。 " 詳細については、次のリソースをご覧ください。

  • 信頼された証明機関 (CA) が発行した、有効な証明書を指定することで、ポート 443 で HTTPS トラフィックをリッスンするようにサーバーを構成します。

  • 次の /etc/nginx/nginx.conf ファイルで示されているプラクティスの一部を採用することで、セキュリティを強化します。

  • 次の例では、セキュリティで保護されていない要求をリダイレクトするようにサーバーを構成していません。 HTTPS リダイレクト ミドルウェアを使用することをお勧めします。 詳細については、「ASP.NET Core で HTTPS を適用する」を参照してください。

    Note

    サーバー構成で HTTPS リダイレクト ミドルウェアではなくセキュリティで保護されたリダイレクトを処理する開発環境では、永続的なリダイレクト (301) ではなく、一時的なリダイレクト (302) を使用することをお勧めします。 リンク キャッシュを使用すると、開発環境で不安定な動作が発生する可能性があります。

  • Strict-Transport-Security (HSTS) ヘッダーを追加すると、クライアントが行う後続のすべての要求が HTTPS 経由になります。 Strict-Transport-Security ヘッダーの設定に関するガイダンスについては、「ASP.NET Core で HTTPS を適用する」を参照してください。

  • 今後 HTTPS を無効にする場合は、次のいずれかの方法を使用します。

    • HSTS ヘッダーを追加しない
    • 短い max-age 値を選択する

/etc/nginx/proxy.conf 構成ファイルを追加します。

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto $scheme;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

/etc/nginx/nginx.conf 構成ファイルの内容を次のファイルに置き換えます。 この例では、1 つの構成ファイルに http セクションと server セクションの両方が含まれています。

http {
    include        /etc/nginx/proxy.conf;
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    server_tokens  off;

    sendfile on;
    # Adjust keepalive_timeout to the lowest possible value that makes sense 
    # for your use case.
    keepalive_timeout   29;
    client_body_timeout 10; client_header_timeout 10; send_timeout 10;

    upstream helloapp{
        server 127.0.0.1:5000;
    }

    server {
        listen                    443 ssl http2;
        listen                    [::]:443 ssl http2;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.key;
        ssl_session_timeout       1d;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_session_cache         shared:SSL:10m;
        ssl_session_tickets       off;
        ssl_stapling              off;

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #Redirects all traffic
        location / {
            proxy_pass http://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

Note

アプリによって行われる大量の要求を受け入れる目的で、Blazor WebAssembly アプリの burst パラメーター値を大きくする必要があります。 詳細については、「ASP.NET Core Blazor WebAssembly のホストと展開」を参照してください。

Note

前の例では、オンライン証明書状態プロトコル (OCSP) のスタンプを無効にしています。 有効になっている場合は、証明書でその機能がサポートされていることを確認します。 OCSP を有効にする方法の詳細とガイダンスについては、Module ngx_http_ssl_module (Nginx ドキュメント) の記事の次のプロパティを参照してください。

  • ssl_stapling
  • ssl_stapling_file
  • ssl_stapling_responder
  • ssl_stapling_verify

Nginx をクリックジャッキングから守る

クリックジャッキングは "UI 着せ替え攻撃" とも呼ばれ、Web サイトの訪問者を騙して現在訪れているものとは異なるページのリンクやボタンをクリックさせる悪意のある攻撃です。 サイトをセキュリティで保護するには、X-FRAME-OPTIONS を使います。

クリックジャッキング攻撃を軽減するには、次の手順に従います。

  1. nginx.conf ファイルを編集します。

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Frame-Options "SAMEORIGIN"; を追加します。

  2. ファイルを保存します。

  3. Nginx を再起動します。

MIME タイプ スニッフィング

このヘッダーは応答コンテンツの種類をオーバーライドしないようにブラウザーに指示するので、ほとんどのブラウザーで MIME スニッフィングが阻止されます。 nosniff オプションを指定すると、サーバーでのコンテンツが text/html の場合、ブラウザーでは text/html と表示されます。

  1. nginx.conf ファイルを編集します。

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Content-Type-Options "nosniff"; を追加します。

  2. ファイルを保存します。

  3. Nginx を再起動します。

Nginx に関するその他の推奨事項

サーバー上で共有フレームワークをアップグレードしたら、サーバーによってホストされている ASP.NET Core アプリを再起動します。

その他の技術情報