ASP.NET Core Apacheで同じIPとポートで複数アプリケーションを展開する

ASP.NET Core Apacheで同じIPとポートで複数アプリケーションを展開する

ASP.NET CoreのアプリケーションをApacheに展開する場合、同じIP(ドメイン)とポートで複数のアプリケーションを展開する場合の設定方法や注意点について記載します。
執筆時点のASP.NET Coreのバージョンは2.1です。

はじめに

ASP.NET Coreは上図のKestrel単独で稼働することも出来ますが、一般的に多いのは
下図のApache等の既存のウェブサーバーから転送するパターンになります。

ASP.NET Core への Kestrel Web サーバーの実装

ASP.NET Core への Kestrel Web サーバーの実装

その場合、リバースプロキシを設定しますが、公式リファレンスでは一つのIP・ポートに対して1アプリケーションを構築する場合の説明しか記載されていません。
また、公式リファレンスのKestrelに関するページには以下のような記載があり、パッと見たら「あ、非対応か」と思います。
諦めが悪く色々と模索していたら一つのIP・ポートに対して複数アプリケーションが構築できたので、方法を記載したいと思います。

Kestrel は、複数のプロセスによる同じ IP とポートの共有をサポートしていないため、このシナリオには対応しません。 ポートでリッスンするように Kestrel を構成すると、Kestrel は、要求のホスト ヘッダーに関係なく、そのポートに対するすべてのトラフィックを処理します。 ポートを共有できるリバース プロキシは、一意の IP とポート上の Kestrel に要求を転送することができます。

環境構築手順

ファイル名やディレクトリパスなどは、公式リファレンス「Apache 搭載の Linux で ASP.NET Core をホストする」で説明されている名称で方法を記載します。
実際に構築する環境に応じて読み替えて設定して下さい。

VirtualHostのリバースプロキシパスを設定

先にリファレンスに記載されている設定内容について少し解説すると、http://www.example.com/の80ポートに対するアクセスを、ローカスのKestrel(127.0.0.1:5000)へ転送しています。

複数アプリケーションを同じIP・ポートで起動するには、アクセスするURL(転送元URL)は分ける必要があります。
URLを/app1(http://www.example.com/app1)と/app2(http://www.example.com/app2)に分けます。
それぞれの転送先も同じように、app1(http://127.0.0.1:5000/app1)とapp2(http://127.0.0.1:5001/app2)に分けます。
注意点として、kestrelは1ポートに対して1つのプロセスしか起動できないため、ポートもそれぞれ5000、5001等に分ける必要があります。

/etc/httpd/conf.d/hellomvc.conf

<VirtualHost *:*>
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost><VirtualHost *:80>
ProxyPreserveHost On
ProxyPass /app1 http://127.0.0.1:5000/app1
ProxyPassReverse /app1 http://127.0.0.1:5000/app1
ProxyPass /app2 http://127.0.0.1:5001/app2
ProxyPassReverse /app2 http://127.0.0.1:5001/app2
ServerName www.example.com
ServerAlias *.example.com
ErrorLog ${APACHE_LOG_DIR}hellomvc-error.log
CustomLog ${APACHE_LOG_DIR}hellomvc-access.log common
</VirtualHost>
Advertisement

アプリケーションの設定

ポートの設定

Kestrelの設定のうち、待ち受けポートをVirtualHostで設定したポートに変更します。
app1の場合、5000ポートに設定します。
app2の場合、5001ポートとなります。

Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
    {
        return WebHost.CreateDefaultBuilder(args)
            .UseKestrel(options => 
            {
                options.Listen(IPAddress.Loopback, 5000);
            })
            .UseStartup<Startup>();
    }
}

パスの設定

StartupクラスのConfigureメソッド内でリバースプロキシの転送先ディレクトリに設定したパス部分をベースとして設定します。
また、続けてUseStaticFilesを呼ぶことでwwwroot配下のcss, js等のパスが静的に保たれます。
つまり、呼ばなければ/app1/wwwroot/app1/sample.cssとなります。
呼ぶことで/app1/wwwroot/sample.cssとなり、デプロイ先の設定によってアプリケーションの構成が影響を受けることが無くなります。

Startup.cs

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

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

        app.UsePathBase("/app1");
        app.UseStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

設定の反映・確認

Apacheの設定変更はApacheを再起動することで反映されます。
アプリケーションの変更は再度ビルド・発行(publish)し、再配置します。
その後、アプリケーションのサービスも再起動して反映させる必要があります。

コマンド

Apache再起動:systemctl restart httpd
サービス再起動1:systemctl restart /etc/systemd/system/kestrel-app1.service
サービス再起動2:systemctl restart /etc/systemd/system/kestrel-app2.service

その後、各URLでアプリケーションが動作することが確認します。

app1:http://www.example.com/app1/
app2:http://www.example.com/app2/

まとめ

以上の手順で、リバースプロキシの転送先でパスを分け、そのパスをアプリケーション側に設定することで同一URL・ポートにおいても複数アプリケーションを実行することが出来ます。

プログラミングカテゴリの最新記事