🎛️

nginx 単一サーバで複数の Blazor Web App をホストする

2024/08/21に公開

はじめに

  • この記事では、ひとつのサイトで、複数の独立したアプリをホストする手法を模索します。
  • サーバやアプリの構成については、以下の記事をご参照ください。

https://zenn.dev/tetr4lab/articles/ad947ade600764

https://zenn.dev/tetr4lab/articles/6b1a70ca7800ed

https://zenn.dev/tetr4lab/articles/1946ec08aec508

複数アプリの構成

ポートで振り分け

  • アプリ毎に仮想サイトとサービスのポートを用意し、https://<domain_name>:<service_port>/から、アプリのポートに転送します。
  • アプリ毎にサイトが分離されたシンプルな構成です。
  • 「番号」とサービス内容が結びつかず、利用者には解りづらいです。

nginx の構成

  • アプリ毎に個別の仮想サイトを構成します。
/etc/nginx/sites-available/<service_name>.conf
map $http_connection $connection_upgrade {
  "~*Upgrade" $http_connection;
  default keep-alive;
}
server {
  # ssl
  listen <service_port> ssl;
  listen [::]:<service_port> ssl;
  server_name <domain_name>;
  # Basic Authentication
  auth_basic "private area";
  auth_basic_user_file /var/www/.htpasswd;
  location / {
    proxy_pass         http://127.0.0.1:<application_port>;
    proxy_http_version 1.1;
    proxy_set_header   Upgrade $http_upgrade;
    proxy_set_header   Connection $connection_upgrade;
    proxy_set_header   Host $http_host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
  }
}

承認済みのリダイレクト URI

  • GCPコンソールで、以下の登録が必要です。
    https://<domain_name>:<service_port>/signin-google
    http://<domain_name>:<service_port>/signin-google
  • 開発時には、以下が必要です。
    https://localhost/signin-google

サブディレクトリで振り分け

  • アプリ毎にサービス名に関連付けたサブディレクトリを用意し、https://<domain_name>/<service_name>から、アプリのポートに転送します。
  • アプリに関連付けた名前が使えるので、利用者に分かり易いです。
  • サービス・ポートで振り分けた上で、サブディレクトリからサービス・ポートに転送することも可能ですが、この記事では扱いません。

nginx の構成

  • アプリに共通の仮想サイト内にサブディレクトリを作ります。
/etc/nginx/sites-available/default
map $http_connection $connection_upgrade {
  "~*Upgrade" $http_connection;
  default keep-alive;
}
server {
  # SSL configuration
  listen 443 ssl default_server;
  listen [::]:443 ssl default_server;
  server_name <domain_name>;
# ~ ~ ~
# ~ ~ ~
  # Basic Authentication
  auth_basic "private area";
  auth_basic_user_file /var/www/.htpasswd;
  # Blazor Apps
  location /<service_name>/ {
    proxy_pass http://127.0.0.1:<application_port>;
    include snippets/blazor_proxy.conf;
  }
  location /<service_name2>/ {
    proxy_pass http://127.0.0.1:<application_port2>;
    include snippets/blazor_proxy.conf;
  }
# ~ ~ ~
# ~ ~ ~
}
  • 共通の設定をスニペットにまとめまておいて、必要箇所に取り込んで使います。
/etc/nginx/snippets/blazor_proxy.conf
  # Blazer proxy common settings
  proxy_http_version 1.1;
  proxy_set_header   Upgrade $http_upgrade;
  proxy_set_header   Connection $connection_upgrade;
  proxy_set_header   Host $http_host;
  proxy_cache_bypass $http_upgrade;
  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header   X-Forwarded-Proto $scheme;

承認済みのリダイレクト URI

  • GCPコンソールで、以下の登録が必要です。
    https://<domain_name>/<service_name>/signin-google
    http://<domain_name>/<service_name>/signin-google
  • 開発時の設定は後述します。

アプリの構成

  • Program.csで早期にWebApplication.UsePathBase ("/<service_name>")を呼ぶことで、指定ディレクトリで稼働するようになります。
Program.cs
// Application Base Path
var basePath = builder.Configuration ["AppBasePath"];
if (!string.IsNullOrEmpty (basePath)) {
    app.UsePathBase (basePath);
}
  • App.razorでも、パスの指定が必要になります。
App.razor
@inject IConfiguration Config

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="@basePath" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="Project.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
    <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
    <HeadOutlet />
</head>

<body>
    @* <Routes @rendermode="new InteractiveServerRenderMode (prerender: false)" /> *@
    <Routes @rendermode="RenderMode.InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
    <script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body>

</html>

@code {
    /// <summary>ベースパス</summary>
    protected string basePath = "/";

    /// <summary>初期化</summary>
    protected override void OnInitialized () {
        base.OnInitialized ();
        basePath = Config.GetValue<string> ("AppBasePath") ?? "/";
        if (!string.IsNullOrEmpty (basePath) && !basePath.EndsWith ('/')) {
            basePath += '/';
        }
    }

}
  • 上記いずれの場合も、AppBasePathは、構成プロバイダーを使用して取得されます。
  • 開発時は、例えばappsettings.Development.jsonで与えることができます。
appsettings.Development.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AppBasePath": "/<service_name>"
}
  • さらに、launchsettings.jsonで指定することで、起動時のURLを変更します。
launchsettings.json
    "launchBrowser": true,
+   "launchUrl": "<service_name>",
  • こうすることで、https://localhost:<port>/<service_name>で起動して動作します。

開発用の承認済みのリダイレクト URI

  • 開発時にルートで起動する場合は、GCPコンソールで、以下の登録が必要です。
    https://localhost/signin-google
  • サブディレクトリで起動する場合は、以下が必要です。
    https://localhost/<service_name>/signin-google
  • 登録が必要なのは起動時のURLで、起動後に切り替える先のURLの登録は不要です。

おわりに

  • お読みいただきありがとうございました。
  • 執筆者は、Blazor、ASP.NETともに初学者ですので、誤りもあるかと思います。
    お気づきの際は、是非コメントや編集リクエストにてご指摘ください。
  • あるいは、「それでも解らない」、「自分はこう捉えている」などといった、ご意見、ご感想も歓迎いたします。

Discussion