Linux環境のホスティング
ASP.NET Coreを使用したWebアプリは、.NET Core上で動作するKestrelというWebサーバー機能を持ち、独立したコンソールアプリとして実行します。
ただし、Kestrelにはアプリ実行のための基本的な機能しか持たないため、Webサーバーが持つセキュリティ機能や冗長化のための機能、リクエストのキャッシュなど多くのWebサーバーが持つ数々の機能を持ちません。
ホスティングする場合は、各プラットフォームの稼働するWebサーバー機能などによってリクエストを受けて、リクエストをASP.NET Coreアプリに転送する、いわゆるリバースプロキシーとして設定し、Kestrelが持たないWebサーバー機能を補完します。
本記事では、Linux環境のWebサーバー機能である「Ngnix」と「Apache」のリバースプロキシー機能を使用して行うホスティング方法をご紹介します。なお、今回ホスティングするLinux環境には、あらかじめ.NET Core SDKのインストールを行っています。
Ngnix によるホスティング
Nginx(エンジンエックスと発音します)は、オープンソースのWebサーバーです。Apacheほど高機能ではありませんが、処理性能/並列処理/メモリ使用量が小さく、パフォーマンスに優れていることが特徴で、LinuxだけではなくWindowsやMacでも動作します。
今回は、NgnixをCentOS 7にインストールし、Ngnixのリバースプロキシー機能を利用してASP.NET Coreアプリのホスティングします。
Nginxのインストール方法は既に多くのサイトで既に紹介されているため、ここでは割愛しますが、参考までに筆者がCentOS 7で行った手順を記しておきます。
Nginxのレポジトリの登録
Nginxが公開しているyumレポジトリの追加を行います。
yumレポジトリの追加は、Nginxの公式サイトに記載のある手順で以下の通り行います。
root権限を持つユーザーで、「/etc/yum.repos.d/nginx.repo」ファイルを作成し、以下の通り内容を記述します。
[nginx] name=nginx repo baseurl=http://nginx.org/packages/OS/OSRELEASE/$basearch/ gpgcheck=0 enabled=1
この内容を保存して、ファイルが正常に作成されていることを確認します。
# ls -l /etc/yum.repos.d/nginx.repo -rw-r--r--. 1 root root 108 Mar 21 11:35 /etc/yum.repos.d/nginx.repo
Nginxのインストール
レポジトリ情報の保存が終わると、いよいよインストールです。インストールも引き続きroot権限で、以下の通りコマンドを実行します。
yum install nginx
インストール完了後、Nginxを自動起動するように設定します。
systemctl enable nginx
最後に起動して、表示を確認しましょう。
systemctl start nginx
以上で起動するはずです。あとはブラウザで「http://サーバーホスト名/」の表示を確認しましょう。
ASP.NET Coreアプリのホスト
ASP.NET Coreアプリをホストするためには、単独のASP.NET Coreアプリが実行できる環境の作成を行います。Windows、Mac、Linuxの開発環境で、あらかじめ実行用ファイルを作成します。
実行用ファイルの作成は、プロジェクトのあるディレクトリに移動し、dotnet CLIを使用して行います。
dotnet publish
publishコマンドの実行に成功するとプロジェクトフォルダー内に「/bin/Debug/netcoreapp2.0/publish」が作成され、発行用モジュール群が作成されます。
publishに作成された実行モジュールが正しく動作するか確認します。
dotnet [作成された実行モジュール名].dll
コマンドラインに表示されたURL(下図にある赤い矢印の箇所)をWebブラウザで表示して、正しく表示が行えれば準備完了です。
Nginxのリバースプロキシー機能を設定
それでは、Nginxのリバースプロキシー機能を設定します。基本的な設定は、Host ASP.NET Core on Linux with Nginxに記載された方法に沿って行います。
ここでは、実際に前述のアプリケーションをホストする手順を紹介します。
アプリ側の設定
今回のホスティングでは、単一のNginxインスタンスと同一のサーバー上にアプリをホストします。
つまり、Nginxからリクエストがフォワードされてくるので、ASP.NET CoreアプリにMicrosoft.AspNetCore.HttpOverrides
パッケージを追加し、パッケージに含まれるForwarded Heaaderミドルウェアを使用します。
このミドルウェアはX-Forwarded-Proto
ヘッダーを使用してRequest.Scheme
を更新することで、リダイレクトURIやその他のセキュリティポリシーが正しく機能することができます。
X-Forwarded-Proto(XFP)
ヘッダーとは、クライアントがプロシキやロードバランサーに接続するために使用したプロトコル(HTTPまたはHTTPS)を識別するためのヘッダーです。
一般的なサーバーのアクセスログには、サーバーとプロキシー間で使用されたプロトコルは残されますが、クライアントとプロキシーとの間のプロトコル情報は含まれません。そのため、クライアントとプロキシー間で使用したプロトコルを識別する場合は、XFPを使用します。
いくつかの種類の認証ミドルウェアでは、Forwarded Headersミドルウェアを最初に適用にすることを必須としています。この適用順序を守ることで認証ミドルウェアがヘッダー値を識別し、正しいリダイレクトURIを生成することができるようになります。
Forwarded Headersミドルウェアは、StartupクラスのConfigureメソッド内で宣言します。
認証ミドルウェアを使用する場合は、UseAuthenticationの前で宣言するようにします。
app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); app.UseAuthentication();
Nginx側の設定
Ngnixは、設定ファイルの定義に基づいてリクエストを処理します。設定ファイルは「/etc/nginx/conf.d」に格納します。(Microsoftサイトでは/etc/nginx/sites-available/defaultと記載がありますが、実際には設定ファイルは「/etc/nginx/conf.d」に格納されています)
Nginxの設定ファイルの記法
設定ファイルの書式は、シンプルディレクティブとブロックディレクティブに分かれます。
シンプルディレクティブの書式は[定義名] [定義値];
で表現します。ブロックディレクティブは、以下の通り複数のディレクティブを内包することができます。
[ディレクティブ] { [ディレクティブ] 定義値; [ディレクティブ] 定義値; [ディレクティブ] { [ディレクティブ] [定義値]; [ディレクティブ] [定義値]; [ディレクティブ] [定義値]; } }
ブロックディレクティブにはevents
、http
、server
、location
などがあり、ブロックディレクティブに内包の定義群のことを「コンテキスト」、そして、このコンテキストの外に置かれたディレクティブ群のことを「メインコンテキスト」と呼びます。
ASP.NET Coreアプリへのリバースプロキシーを行う場合の設定サンプル
ASP.NET Coreアプリへのリバースプロキシーとして設定する場合、以下の通り設定ファイルを記述します。
server { listen 80; server_name example.com *.example.com location / { proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $http_host; proxy_cache_bypass $http_upgrade; } }
上記の設定では、server_name
ディレクティブには、現在example.com *.example.com
を設定しています。これは、サーバー名にこのアドレスが指定されている場合に、以下の設定に基づくリクエストの転送が行われることを意味しています。
設定ファイルにserver_name
が未指定だった場合は、Nginxはデフォルトサーバーを使用します。デフォルトサーバーが未指定だった場合、設定ファイルに記述される最初のサーバーの定義をデフォルトサーバーと見なします。
そのため、推奨設定としては、デフォルトサーバーが444のステータスコードを返すように設定することで、該当アドレス以外のリクエストを受け付けないように構成することができます。
server { listen 80 default_server return 444; }
逆にすべてのリクエストを処理したい場合はserver_name
行を削除することで、受信したリクエストをすべて処理します。
設定の反映
Nginxの設定の反映は「設定内容の確認」「設定の再読み込み」の順に行います。設定内容の確認はShellから以下のコマンドで行います。
sudo nginx -t
問題がある場合は、問題行の表示が行われます。問題がなければ、設定の再読み込みを行います。設定の再読み込みは、Shellから以下のコマンドで行います。
sudo nginx -s reload
以上でNginxの設定は完了ですが、CentOSはSELinuxが既定でON(Enforcing)になっているため、リクエストが「502 Bad Gateway」となってしまう場合があります。その場合は以下のShellから以下のコマンドを実行して、SELinuxをOFF(Permissive)にすることで動作するようになります。
sudo setenforce 0