# banchi 技術導入マニュアル

文書・公式仕様の確認日：2026-09-10。実接続の確認日は[検証範囲](#evidence)に記載しています。

[画面付きの接続ガイド](https://banchi.app/guide) · [English](https://banchi.app/technical-guide-en.md) · [AI向け索引](https://banchi.app/llms.txt)

対象は、自分のホスティングやサーバーを借りた住所で公開する開発者と、その作業を手伝うAIです。設定例の `your-name.banchi.app` は説明用です。自分が取得したホスト名と公開先が指定する値へ置き換えます。以下の手順を読むだけでは、DNS・サーバー・契約の変更は行われません。

AIで進める場合は、[接続用Skill](https://banchi.app/skills/banchi-connect/SKILL.md)を読みます。実際の公開先製品・本番環境を特定し、作業時点の公式資料を必ず開いて、参照URL・確認日・費用を示してから設定します。特定できない、公式資料を読めない、追加費用が不明な場合は、依存する変更へ進みません。[人が確認して始める依頼文](https://banchi.app/guide#ai)も利用できます。

- [提供範囲と準備](#requirements)
- [共通の進め方とDNS入力](#workflow)
- [GitHub Pages](#github) / [Cloudflare Pages](#cloudflare-pages) / [Vercel](#vercel) / [Netlify](#netlify)
- [AWS Amplify](#amplify) / [Firebase Hosting](#firebase) / [Azure Static Web Apps](#azure) / [Heroku](#heroku) / [DigitalOcean](#digitalocean) / [Google Cloud Run](#google-cloud)：追加6サービスは公式照合のみ
- [自分のサーバー](#own-server)：[Caddy](#caddy) / [nginx＋Certbot](#nginx) / [手動DNS-01](#dns01)
- [Workersの接続用入口・R2の制約](#workers-r2)
- [DNS・HTTPSの確認コマンド](#checks)
- [ログイン・フォーム・決済の確認](#app-check)
- [既存APIの契約](#api)
- [切替・利用終了](#retire) / [検証範囲](#evidence)

<a id="requirements"></a>
## 1. 提供範囲と準備

| 項目 | 内容 |
| --- | --- |
| 管理画面・APIの基点 | `https://banchi.app` |
| 借りる住所の例 | `your-name.banchi.app`。その配下の `api.your-name.banchi.app` なども設定可能 |
| 通常の接続 | DNS-only。閲覧者の通信は公開先へ直接届く |
| banchiの担当 | 契約期間中の住所の利用と、対応するDNSレコードの設定 |
| 利用者の担当 | ホスティング、サーバー、アプリ、証明書と更新、公開先の費用・アクセス対策 |
| 料金 | 1住所ごとに年額500円（税込）、自動更新。日本国内向け。同じメールで複数の住所を持てるが契約・更新日は個別 |

運営者向けの既存無料取得例外は、一般向け無料プランではありません。契約条件は[利用規約](https://banchi.app/terms)で確認してください。

購入前に、公開先が「自分では親ドメインを管理していないサブドメイン」を登録できること、必要なDNSが下記の範囲に収まることを確認します。ホスティングの標準URLでサイトやAPIを先に動かし、カスタムドメインを使える契約・権限を用意します。ドメインだけ設定しても、アプリやHTTPSは自動で作られません。

<a id="workflow"></a>
## 2. 共通の進め方とDNS入力

1. banchiで住所を取得し、ログイン後の「住所一覧」から対象住所の設定を開きます。
2. 公開先に借りたホスト名を登録します。`https://`、パス、ポート番号は付けません。GitHubの所有確認など、検証用TXTだけを先に保存する例外は各節に従います。
3. 取得直後は「この名前をどう使いますか」の選択へ直接進みます。既存住所では「使い方を変える」を開きます。「自分のホスティングにつなぐ」でプリセットを選び、公開先のCNAME宛先、またはサーバーの公開IPを保存します。
4. 追加の名前・複数IP・Web用TXT・CAAは「DNSレコードを直接編集」で設定します。既存の所有確認TXTを消さないよう、保存前に全体を見直します。
5. 公開先でDNS確認と証明書発行を確認し、banchiで「状態を調べる」を実行します。[外形確認](#checks)の後、[アプリ確認](#app-check)まで進めます。

| 種類・名前 | 入力するもの・制約 |
| --- | --- |
| 名前 `@` | 借りた住所そのもの。`banchi.app` 全体を指す記号ではない |
| 配下の名前 | `api.dev.your-name.banchi.app` のような完全な名前。`api` のような相対名は不可 |
| A / AAAA | 到達可能な公開IPv4 / IPv6。単一IPは「その他」の簡易入力でも可。同じ名前に複数IPを置く場合は個別設定 |
| CNAME | 公開先が指定したホスト名だけ。URL・ポート・IPは不可。同じ名前にTXTなど別のレコードは置けない |
| TXT | Web所有確認などの値。印字可能ASCII、最大2048バイト。外側の表示用引用符は値に含めない |
| CAA | 公開先の認証局を指定する値。`0 issue "letsencrypt.org"` は形式例であり、全公開先の推奨値ではない |

標準で1住所5レコードまでです。確認用TXT、CAA、システムの案内用rootも数えます。利用者のroot A/AAAA/CNAMEがなければ、案内用rootが1件入り、利用者の枠は残り4件です。rootを指定すると案内用レコードは自動で入れ替わります。案内用レコードを手で送信・編集しません。

TXTだけを先に保存したり、配下のサイトだけを公開したりできます。配下の名前ごとに公開先への登録と証明書が必要です。メール用MX・SPF・DKIM・DMARC、NS委任、ワイルドカードDNS、他人の住所への設定は提供していません。

<a id="github"></a>
## 3. GitHub Pages

1. リポジトリの **Settings → Pages** でブランチまたはGitHub Actionsによる公開元を設定し、標準のGitHub Pages URLを確認します。GitHub Freeで使う場合は公開リポジトリが必要です。公開化するなら追跡ファイルと履歴の秘密情報を先に点検します。
2. アカウント／組織の **Settings → Pages → Add a domain** で借りた住所を検証します。表示されたTXTの完全な名前・値をbanchiの個別設定に保存し、DNS反映後に **Verify** を押します。親ドメイン全体を検証する必要はありません。
3. リポジトリのPages **Custom domain** に借りた住所を保存します。その後、banchiのGitHub PagesプリセットでCNAMEを `YOUR_GITHUB_USER.github.io` または組織の値へ設定します。リポジトリのパスは付けません。検証用TXTも同時に残します。
4. DNS確認・証明書発行後、**Enforce HTTPS** を有効にします。選択できるまで最大24時間かかる場合があります。所有確認TXTは維持します。
5. ブランチ配信ではGitHubが公開元に作る `CNAME` ファイルをビルドで消さないようにします。Actions配信ではそのファイルは必須ではなく、ドメイン設定はPagesの設定で管理します。
6. カスタムドメインに合わせて静的サイトのbase URL、画像パス、外部APIのCORSを見直します。GitHub Pages自体は任意のサーバーAPIを動かしません。[アプリ確認](#app-check)へ進みます。

出典：[GitHubのドメイン設定](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site)、[所有確認](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/verifying-your-custom-domain-for-github-pages)。

<a id="cloudflare-pages"></a>
## 4. Cloudflare Pages

公開前に、プロジェクトのフレームワーク、ビルドコマンドと出力ディレクトリを実際の構成に合わせます。静的ファイルの配備だけでは既存サーバーAPIは移りません。[公式ビルド設定](https://developers.cloudflare.com/pages/configuration/build-configuration/)を確認し、Functionsがある場合は下記のProduction設定も行います。

1. 自分のアカウントのPagesプロジェクトを配備し、`YOUR_PROJECT.pages.dev` で動作させます。
2. そのプロジェクトの **Custom domains → Set up a custom domain** で借りた住所を先に追加します。自分のアカウントに `banchi.app` ゾーンを追加したり、NSを切り替えたりする手順ではありません。
   同じCloudflareアカウントが親ゾーンも管理している場合、Pagesは確認後にCNAMEを自動作成することがあります。DNSの変更確定前に内容を確認し、banchi管理のDNSを直接上書きする画面なら停止してください。通常の別アカウント経路では、次のbanchi画面でCNAMEを保存します。
3. banchiのCloudflare Pagesプリセットで、Pagesが示すCNAME宛先を保存します。Pagesへの登録をせずCNAMEだけ作ると、522などのエラーになり得ます。
4. Pagesでドメインが有効になり、証明書が発行されたことを確認します。任意のCAAを追加済みなら、公開先が使う認証局を妨げていないか確認します。
5. Functionsを使う場合は、Production環境の変数・secrets・bindingsを設定して再配備し、新しい住所でAPIを試します。別アカウントへのDNS接続実績は、アプリ移行の自動化を意味しません。

出典：[Pagesカスタムドメイン](https://developers.cloudflare.com/pages/configuration/custom-domains/)、[Functionsのbindings](https://developers.cloudflare.com/pages/functions/bindings/)。移行は[Workers・R2](#workers-r2)も参照してください。

<a id="vercel"></a>
## 5. Vercel

先に **Settings → Build and Deployment** でRoot Directory、Framework Preset、Build Command、Output Directoryを確認し、本番配備の標準URLで動作させます。自動検出値を別フレームワークの例で上書きせず、APIも対応するFunctions構成で配備します。[公式ビルド設定](https://vercel.com/docs/builds/configure-a-build)。Hobbyは個人・非商用向けです。商用利用は[プラン条件](https://vercel.com/docs/plans/hobby)を確認します。

1. プロジェクトの **Settings → Domains → Add Domain** へ借りた住所を追加します。
2. 表示された、そのプロジェクト固有のCNAME宛先をbanchiのVercelプリセットへ入力します。他のプロジェクトの値や、親ドメイン用のAレコードを流用しません。
3. 所有確認TXTを求められた場合だけ、完全な名前と値を照合して追加します。プリセットが組み立てる名前と違う場合は個別設定を使います。借りた住所の外にある必須レコードは設定できないので、運営へ相談します。
4. Vercelでドメイン設定が有効・HTTPS利用可能となるまで待ち、banchiの診断を実行します。
5. Production環境の公開URL、認証の戻り先、外部API許可Originを更新して必要なら再配備します。プレビュー環境の認証やURLを本番と取り違えず、[アプリ確認](#app-check)を行います。

NS方式やワイルドカードは選びません。出典：[Vercelドメイン追加](https://vercel.com/docs/domains/working-with-domains/add-a-domain)。

<a id="netlify"></a>
## 6. Netlify

まずリポジトリと公開ブランチ、ビルドコマンド、公開ディレクトリを確認して配備し、標準URLで動作させます。Functionsのコードや環境変数は静的な公開ディレクトリへ混ぜず、対応するFunctions設定で配備します。[公式ビルド設定](https://docs.netlify.com/build/configure-builds/overview/)を参照し、秘密を含むリポジトリ全体を公開出力先にしないでください。

1. サイトの **Domain management / Production domains → Add a domain you already own** で借りた住所を登録します。外部DNSを使い、Netlify DNSへのNS切替は選びません。
2. サイトの `YOUR_SITE.netlify.app` など、表示されたCNAME宛先をbanchiのNetlifyプリセットへ保存します。
3. 2026-09-07の試験では親ドメイン所有に関する通知は任意でした。現在の画面で確認が必須なら、指定が借りた住所の配下かを確かめます。親 `banchi.app` のTXTなど、範囲外の必須確認を無視して進めないでください。
4. Netlifyの **HTTPS** でDNS確認と証明書発行を確認します。登録・DNS・必要な検証を維持して自動更新を受けます。
5. サイトの本番URL、Functionsの環境変数、フォームや認証の許可URLを更新し、再配備後に[アプリ確認](#app-check)を行います。

出典：[Netlify外部DNS](https://docs.netlify.com/manage/domains/configure-domains/configure-external-dns/)、[HTTPS](https://docs.netlify.com/manage/domains/secure-domains-with-https/https-ssl/)。

<a id="own-server"></a>
## 7. 自分のサーバー：VPS・クラウドVM・条件を満たす自宅環境

通常構成では、公開IP、TCP 80/443への外部到達性、常時動くアプリ、証明書を管理するWebサーバーが必要です。クラウドのファイアウォール、OSのファイアウォール、ルーター/NATを別々に確認します。CGNATや回線の着信制限がある環境では、DNSを変えるだけでは公開できません。

自宅サーバーを一律に禁止するものではありません。ただしグローバルIPv6があるだけでは不十分です。IPv6の着信と証明書・アプリまでの通し接続はbanchiでは未実証です。到達しないAAAAは公開しません。A＋AAAAを使うなら両方が同じサイトを提供する必要があります。

以下は、サーバー上で `127.0.0.1:3000` に既存Webアプリが動いている例です。DNSに `:3000` は書きません。外部公開する80/443から、そのアプリへプロキシします。アプリ側にも借りたホスト名の受付設定を加えます。

ツールはそのサーバーの既存運用に従って準備してください。NixOSでは宣言的なサービス設定を優先し、生成済み設定をCertbot等で直接書き換えません。ここではインストールや既存設定の上書きは指示せず、Caddy/nginx/Certbotが導入済みであることを前提にします。二つのWebサーバーを同じポートで同時起動しません。

<a id="caddy"></a>
### 7.1 Caddy

1. banchiでrootのAまたはAAAAをサーバーの公開IPへ保存し、[DNS確認](#checks)を行います。
2. 既存Caddy構成に、他のサイトを消さず次のサイトブロックを追加します。これはアプリへのリバースプロキシ例で、実測した簡単な応答ページとは異なります。

```caddyfile
your-name.banchi.app {
    reverse_proxy 127.0.0.1:3000
}
```

3. サーバー上で設定を検証します。パスは実際の構成に合わせます。

```sh
caddy validate --config ./Caddyfile --adapter caddyfile
```

4. 常駐中のCaddyへは、既存サービスの運用手順で反映します。CLIで管理している場合の反映例は次です。これは稼働中の設定を変更するコマンドです。

```sh
caddy reload --config ./Caddyfile --adapter caddyfile
```

まだサービスがない場合は、OSのサービス管理でこの構成を常駐させます。開発用の前面プロセスを閉じただけで本番が止まる構成にしません。Caddyは通常HTTP-01（80番）またはTLS-ALPN-01（443番）を使います。証明書保存領域は書き込み可能かつ再起動・再配備後も保持される状態にし、DNS・ネットワーク到達性も維持します。設定確認後、証明書発行ログと外部HTTPSを確認してください。

出典：[Caddy自動HTTPS](https://caddyserver.com/docs/automatic-https)、[リバースプロキシ](https://caddyserver.com/docs/quick-starts/reverse-proxy)、[設定検証と再読込](https://caddyserver.com/docs/command-line)。

<a id="nginx"></a>
### 7.2 nginx＋Certbot

この組合せのbanchi通し試験は未実施です。既存構成の管理者向けの例です。まずrootのA/AAAAを公開IPへ向け、HTTPで到達できる状態を作ります。nginxの `http` 内で読み込まれるサイト設定に、既存サイトと競合しないブロックを追加します。

```nginx
server {
    listen 80;
    server_name your-name.banchi.app;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
```

AAAAを公開する場合は、IPv6の待受け（例：`listen [::]:80;`）と443の待受け・到達性も必要です。アプリのtrusted proxy設定は管理下のプロキシに限定します。WebSocket等は別途必要な設定を加えます。この短い例は全プロトコルの完成設定ではありません。

構文検証が成功した場合だけ、既存サービスの権限・手順で反映します。

```sh
nginx -t && nginx -s reload
```

Certbotのnginxプラグインが使える構成では、次で証明書を取得し、nginx設定へ反映できます。**認証局への通信と設定変更が発生します。** 設定のバックアップを取り、対話画面の内容を確認して進めます。

```sh
certbot --nginx -d your-name.banchi.app
```

発行後に443の設定・HTTPからHTTPSへの転送・外部HTTPSを確認します。自動更新には、使用したプラグイン、期限前に実行される既存timer/cron、HTTP-01用80番への到達性、更新後のnginxへの証明書読込が必要です。timerの有効状態とログはOSの既存サービス管理で確認します。導入しただけで更新予約済みと判断しません。

```sh
certbot renew --dry-run
```

これは更新経路を試すためのコマンドで、Let's Encryptのステージング等へ通信し、設定済みhookが動くこともあります。完全な読み取り専用コマンドではありません。成功しても将来のDNS・timer・ネットワーク維持は必要です。

出典：[nginxの設定構造](https://nginx.org/en/docs/beginners_guide.html)、[nginxコマンド](https://nginx.org/en/docs/switches.html)、[プロキシヘッダー](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header)、[WebSocket](https://nginx.org/en/docs/http/websocket.html)、[Certbotの利用・更新](https://eff-certbot.readthedocs.io/en/stable/using.html)。

<a id="dns01"></a>
### 7.3 手動DNS-01

通常はサーバーで完結するHTTP-01等を使います。DNS-01はワイルドカード証明書以外でも使えますが、手動設定は放置して自動更新される仕組みではありません。

1. 自分のACMEクライアントで対象ホストのDNS-01確認を開始し、指定されたTXT名と値を取得します。
2. banchiの個別設定で、その完全な名前（通常 `_acme-challenge.your-name.banchi.app`）と値を保存します。既存レコードを残し、5件枠と同名CNAMEとの衝突を確認します。
3. 2系統のDNSでTXTが一致したことを確認してから、ACMEクライアントの確認を進めます。
4. 証明書を自分のWebサーバーへ設定し、HTTPSを確認します。チャレンジ完了後、不要となった今回のTXTだけを取り除きます。次の更新時には新しい値で同じ確認作業が必要です。

Certbotのmanual方式は、独自hook等なしでは自動更新しません。banchiは証明書更新用APIトークンや管理付きDNS-01委譲を提供していません。チャレンジ名をCNAMEで別のDNSへ委譲する技術自体はありますが、認証局・クライアントの対応と委譲先の運用が必要で、banchiでの通し試験は未実施です。これを提供済みの自動更新経路として扱わないでください。NS委任やワイルドカードDNSも使えません。

出典：[Let's Encryptの確認方式](https://letsencrypt.org/docs/challenge-types/)、[Certbot manual方式](https://eff-certbot.readthedocs.io/en/stable/using.html#manual)。

<a id="workers-r2"></a>
## 8. Cloudflare Workers：Pagesに接続用の入口を置く

**既存Workerをそのまま使い、同じCloudflareアカウントに小さいPagesプロジェクトを1つ追加します。** 通信は `閲覧者 → あなたのPages入口 → あなたのWorker`。banchiはDNSを設定し、本文・Cookie・APIを中継しません。

Workersの標準Custom Domainsには同じアカウントでのゾーン管理が必要ですが、Pagesは別アカウントが管理するサブドメインを登録できます。`workers.dev`へのCNAMEではなく、下記のPagesを接続先にします。独立した親ドメインの購入やbanchiへのCloudflare APIキーの共有は不要です。

### 1. 既存Workerと公開する機能を確認する

- 自分のWorkerの標準URLで、サイト・API・ログインが動くことを確認します。PagesとWorkerは**同じアカウント**に置きます。
- 本体のコード、D1・KV・R2・DO、secrets、Cron・Queueは既存Workerに残します。コピー・作り直しは不要です。入口からは既存WorkerのHTTP `fetch`を呼びます。
- **元のURLだけにCloudflare AccessやWAFを設定している場合は、接続前に保護を見直します。** Service bindingはその公開URLを通らず、`ctx.access`も下流へ伝わりません。非公開ページ・管理APIはWorker内でも認証し、必要な入口の保護を用意します。

### 2. 接続用の2ファイルを作る

既存Workerの設定を上書きせず、同じリポジトリ内に `pages-entry/` を作ります。以下の2ファイルだけで、入口のビルドは不要です。`dist/`には入口の `_worker.js` だけを置き、アプリの資産・`.env`・秘密情報をコピーしません。

`pages-entry/dist/_worker.js`：

```js
export default {
  fetch(request, env) {
    if (new URL(request.url).origin !== env.PUBLIC_ORIGIN) {
      return new Response('Not found', { status: 404 });
    }
    if (!env.APP) {
      return new Response('Service unavailable', {
        status: 503, headers: { 'Cache-Control': 'no-store' },
      });
    }
    return env.APP.fetch(request);
  },
};
```

`pages-entry/wrangler.jsonc`：

```json
{
  "name": "my-worker-entry",
  "pages_build_output_dir": "./dist",
  "compatibility_date": "2026-09-09",
  "vars": {},
  "services": [],
  "env": {
    "production": {
      "vars": { "PUBLIC_ORIGIN": "https://your-name.banchi.app" },
      "services": [{ "binding": "APP", "service": "existing-worker" }]
    },
    "preview": {
      "vars": { "PUBLIC_ORIGIN": "" },
      "services": []
    }
  }
}
```

置き換えるのは、Pagesの新しい名前 `my-worker-entry`、借りた住所のHTTPS origin `https://your-name.banchi.app`（末尾の `/` なし）、**配備済みWorkerの名前** `existing-worker`です。WorkerのURLは入力しません。環境別のWorkerならダッシュボードに表示される実際の配備名を使います。

入口は許可したoriginだけを通します。`pages.dev`・プレビューURLは**404が正常**です。Previewとローカルには本番のService bindingを渡しません。テスト環境が必要なら、テスト用Workerと別の許可originを明示して設定します。元のWorkerの公開URLはこの設定では無効化されません。

### 3. 自分のPagesへ配備し、banchiのDNSを設定する

既存のWrangler環境を使います。Nix管理なら先にプロジェクトのdev shellへ入り、`wrangler whoami`でWorkerと同じアカウントを確認します。複数アカウントがある場合は対象の `CLOUDFLARE_ACCOUNT_ID` を指定します。

以下は**新しいDirect Uploadプロジェクト**の例です。既存Pagesを上書きしません。Direct Uploadから後日Git連携へは切り替えられないため、Git自動配備を希望するなら作成時にGit連携を選び、rootを `pages-entry`、ビルドコマンドを空欄、出力を `dist`、本番ブランチを `main` にします。 Git連携では2ファイルをそのブランチへcommit/pushします。既存の `.gitignore` が `dist/` を除外する場合は、リポジトリrootで `git add -f pages-entry/dist/_worker.js` としてこの入口ファイルだけを追跡し、設定ファイルとともにコミットへ含めます。

```sh
cd pages-entry
wrangler pages project create my-worker-entry --production-branch main
wrangler pages deploy ./dist --project-name my-worker-entry --branch main
```

1. Cloudflareの作成したPagesプロジェクトで **Custom domains → Set up a custom domain** を開き、借りたホスト名を登録します。
2. banchiの住所設定で **自分のホスティングにつなぐ → Cloudflare Pages** を選び、Pagesが表示する本番CNAME宛先（通常 `my-worker-entry.pages.dev`）を保存します。URLや配備ごとのプレビュー名は使いません。
3. Pagesでカスタムドメインと証明書が有効になるまで待ち、`https://your-name.banchi.app` を開きます。`pages.dev`の404を直そうと許可条件を外さないでください。
4. banchiの **状態を調べる** と、次のアプリ確認を行います。認証でrootが401/403を返すアプリは、HTTPSが動いていてもbanchiの診断が「接続済み」にならない場合があります。

### 4. アプリの確認と費用

- **URLと認証:** PUBLIC_ORIGIN等のアプリ設定、OAuth callback、Turnstileの許可ホストを借りた住所に合わせます。ログイン・ログアウト・フォーム・APIを実行し、未ログインで管理機能へ入れないことを確認します。Cookieはhost-only、可能なら`__Host-`を使い、親 `banchi.app` のDomain Cookieにしません。兄弟住所はsame-siteになり得るので、書込み時はOriginを完全一致で検証します。
- **静的ファイルと通信:** JS・CSS・画像・深いURL・404・Range、使用するWebSocket/SSEを確認します。本体の `env.ASSETS.fetch(request)` とassets-first配信は同じとは限りません。入口へ本体のファイルやbindingsをコピーしたり、Request/Responseを書き換えたりせず、アプリの実際の配信経路を確かめます。
- **費用:** 追加の固定契約は必須ではありません。FreeではPages FunctionsとWorkersが日次100,000要求の枠を共有し、超過時は失敗します。既存Paid StandardならService binding自体の追加要求料金はなく、入口の要求と入口・本体の合計CPUが対象です。画像等も入口のFunctionを通るため、無料の静的配信と同じ計算にはなりません。枠内なら追加料金なし、超過分やDB等は利用者の契約に従います。banchiの料金は別に1住所500円/年です。

[検証範囲](#evidence)はサンプル構成の結果です。すべてのアプリ機能・フレームワーク・外側Accessの互換性を保証するものではありません。接続を終えるときは、先にbanchiの接続先を外し、DNS反映を確認してからPagesのドメイン登録と入口を削除します。既存Worker・DB・定期処理は残します。

### R2について

R2の標準Custom Domainにも同じアカウントのゾーンが必要です。既存WorkerがR2を安全に配信している場合は、そのHTTP機能をこの入口から呼べます。R2のbindingを置くだけで認証・Range・キャッシュを備えたファイル配信が完成するわけではありません。R2への直接Custom Domain接続はこの手順の対象外です。

出典：[Workers Custom Domains](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/)、[Pages Custom domains](https://developers.cloudflare.com/pages/configuration/custom-domains/)、[Service bindingsとAccessの制約](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/)、[Pages設定](https://developers.cloudflare.com/pages/functions/wrangler-configuration/)、[Advanced mode](https://developers.cloudflare.com/pages/functions/advanced-mode/)、[Pages CLI](https://developers.cloudflare.com/workers/wrangler/commands/pages/)、[Direct Upload](https://developers.cloudflare.com/pages/get-started/direct-upload/)、[Pages料金](https://developers.cloudflare.com/pages/functions/pricing/)、[Workers料金](https://developers.cloudflare.com/workers/platform/pricing/)、[R2公開](https://developers.cloudflare.com/r2/buckets/public-buckets/)。

<a id="checks"></a>
## 9. DNS・HTTPSの確認コマンド

以下は設定変更をしない確認です。自分のホストだけを指定し、繰り返しの自動監視にはせず、保存後に必要な回数だけ実行します。`dig` と `curl` は既存の開発環境を使います。Nixを使う環境ならプロジェクトのdev shellを優先し、必要時は `nix shell nixpkgs#dig nixpkgs#curl` で一時的に用意できます。

```sh
BANCHI_HOST='your-name.banchi.app'
dig @1.1.1.1 "$BANCHI_HOST" A +short
dig @8.8.8.8 "$BANCHI_HOST" A +short
dig @1.1.1.1 "$BANCHI_HOST" AAAA +short
dig @8.8.8.8 "$BANCHI_HOST" AAAA +short
dig @1.1.1.1 "$BANCHI_HOST" CNAME +short
dig @8.8.8.8 "$BANCHI_HOST" CNAME +short
```

保存した種類の答えが両方で一致するか見ます。Aへの応答にCNAMEの経路と公開先のIPが出る場合もあるため、CNAME構成ではCNAME照会の宛先と比較します。問い合わせていない種類の空回答だけで失敗と判断しません。TXTなら変数を指定された完全な確認名に替え、次のように調べます。

```sh
BANCHI_VERIFY_NAME='_acme-challenge.your-name.banchi.app'
dig @1.1.1.1 "$BANCHI_VERIFY_NAME" TXT +short
dig @8.8.8.8 "$BANCHI_VERIFY_NAME" TXT +short
```

保存直後の古い答えはキャッシュの可能性があります。プロバイダーの案内に従って待ち、既存レコードを何度も消して作り直さないでください。キャッシュと証明書発行に共通の「最大30分保証」はありません。

```sh
curl --head --connect-timeout 5 --max-time 15 "https://$BANCHI_HOST/"
```

HEADに405または501が返ったときだけ、GETでも確認します。本文は保存せず、転送先へ自動追従しません。

```sh
curl --silent --show-error --connect-timeout 5 --max-time 15 \
  --dump-header - --output /dev/null "https://$BANCHI_HOST/"
```

証明書検証を無効にする `-k` は使いません。2xx/3xxは応答の証拠であり、アプリ機能の証拠ではありません。3xxの `Location` が意図したURLか確認します。DNS-onlyでは初期接続先サーバーの証明書が有効でなければ、転送も安全に受け取れません。

| banchiのコード | 診断した範囲 | 次の確認 |
| --- | --- | --- |
| `DNS_SAVED` | 保存済み。利用者のroot公開先がない | 個別レコードのDNSと、各配下ホストのHTTPS |
| `HTTPS_REACHED` | rootのHTTPSに到達したが、401/403/404/405等の応答 | 認証・パス・公開先の設定をブラウザで確認 |
| `LIVE` | root DNSが2系統で一致し、HTTPSが200〜399。HEADが405/501ならGETで再試行 | 転送先・アプリの実操作。診断は転送先へ追従しない |

診断はrootだけを見ます。追加した配下の名前は個別に同じ確認を行います。接続先のエラーページと判定された場合などは、200でも `LIVE` にならないことがあります。

<a id="app-check"></a>
## 10. ログイン・フォーム・決済まで確認する

ここで変更するのは、借りた住所へ接続する**自分のアプリ**の設定です。banchiのログインや住所代のStripe設定を変更する作業ではありません。

| 対象 | 変更する設定 | 公開前の確認 |
| --- | --- | --- |
| ページ・API | 公開base URL、canonical、画像/APIの参照先。変数名はアプリごとに確認 | トップと深いURLを直接開いて再読込。HTTP混在・旧URL・404がない |
| OAuth等 | 認証提供元の許可Origin・callback URL・logout後URLを、新しい完全URLへ。必要なパスを維持 | ログイン→再読込→ログアウト→再ログイン |
| メールのログインリンク | アプリが生成する公開URLと戻り先 | テスト用利用者で発行されたリンクが新しいホストへ戻る |
| フォーム・別ホストのAPI | API側の許可Originを必要な完全Originだけ追加。CSRFの検証は維持 | 送信結果が保存され、再読込で確認できる |
| Turnstile | 自分のwidgetに借りたホスト名を追加。scheme・path・portを付けない | 新しいフォームで確認と送信が成功する |
| Cookie | 原則Domain省略。必要なら `__Host-` 接頭辞と `Secure; Path=/`。親ドメインを指定しない | 新しいホストでセッション継続。ログアウトで無効化 |
| Stripe等 | アプリが作るsuccess/cancel/return URL。Webhookも移すならその送信先 | テスト環境で成功・キャンセル・復帰。サーバーが署名を検証し、重複イベントで二重処理しない |
| WebSocket・大きなファイル | proxy設定、認証、Content-Type、Range等 | 接続・切断・再接続、再生・必要な部分読込 |

同じ親ドメインの別利用者はブラウザ上で同じsiteと扱われる場合があります。SameSiteだけをCSRF対策にせず、Origin等を検証します。CORSを `*` にして認証付き操作を解決したことにしたり、Turnstileに親 `banchi.app` 全体を許可したりしません。

Webhookの署名secretは送信先ごと・テスト/本番ごとに確認し、サーバー側だけへ設定します。成功画面を開けただけで入金処理済みと判断しません。公開確認のために実課金を勝手に作らず、提供元のテスト環境とテストデータを使います。

出典：[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS)、[Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie)、[Turnstileホスト制限](https://developers.cloudflare.com/turnstile/additional-configuration/hostname-management/)、[Stripe Checkout URL](https://docs.stripe.com/api/checkout/sessions/create)、[Portalの戻り先](https://docs.stripe.com/api/customer_portal/sessions/create)、[Webhook](https://docs.stripe.com/webhooks)。

<a id="api"></a>
## 11. 既存APIの契約：ブラウザの所有者セッションを使う

以下は現在の管理画面用APIの説明です。外部向けのAPIキー・PAT・OAuthクライアント認証・DNS更新専用tokenは提供していません。無人のDNS-01更新に使えるAPIとして組み込まないでください。APIは管理画面の実公開基点でのみ使います。

### 公開読み取り

```sh
BANCHI_API='https://banchi.app'
curl --fail --silent --show-error --connect-timeout 5 --max-time 15 \
  "$BANCHI_API/api/config"
curl --fail --silent --show-error --connect-timeout 5 --max-time 15 \
  --get --data-urlencode 'q=your-name' --data-urlencode 'parent=banchi.app' \
  "$BANCHI_API/api/search"
```

`config` は `price_jpy`、`parents`、`app_host` 等を返します。ブラウザでログイン中の応答には本人のメールも含まれるため、応答全体を公開ログへ保存しません。`search` は `{label, results:[{hostname,parent,status,reason}]}` で、`status` は `available` / `taken` / `invalid`。空き検索は予約ではなく、購入可能性を確定しません。

### 所有者用の操作

ログインには画面のメールリンクと必要な人間確認を使います。認証は `__Host-sid` のSecure・HttpOnly Cookieで、各住所の所有権もサーバーが確認します。Cookie、ログインリンク、決済セッション、秘密鍵をAIへの入力や共有ログへ抜き出さないでください。別サイトからの書き込みは許可されず、変更リクエストでは同一Originの検証があります。

| Method / path | 用途 |
| --- | --- |
| `GET /api/labels` | 本人の住所一覧 `{labels}` |
| `GET /api/labels/:hostname` | `{label, records, subscription}`。`label.plan_version` とレコード一覧を読む |
| `PUT /api/labels/:hostname/records` | 望むDNSレコード全体を保存。差分追加APIではない |
| `POST /api/labels/:hostname/records/retry` | 保存済みの計画の再適用。新しい設定値を送る経路ではない |
| `GET /api/labels/:hostname/diagnose` | 接続を実測。成功時に接続状態を確定する場合があり、純粋な読み取りではない |
| `PATCH /api/labels/:hostname` | park / redirect / connectのモード切替。parkやredirectへ切り替えると接続DNS・確認TXTを撤去する |

安全な読み取り例は、本人がログインしている**banchi管理画面と同じOrigin内**のJavaScriptです。これはCookieを取得・表示しません。AIが自動操作する場合も既存の認証済み画面を使い、認証を迂回しません。

```js
const hostname = 'your-name.banchi.app'; // 自分が保有する住所へ変更
const response = await fetch(`/api/labels/${encodeURIComponent(hostname)}`, {
  credentials: 'same-origin',
  headers: { Accept: 'application/json' },
});
if (!response.ok) throw new Error(`Read failed: HTTP ${response.status}`);
const detail = await response.json();
// detail はローカルで確認。メール等を含み得る全応答を共有しない。
```

### 個別DNS保存の注意

PUTのJSONは `{ "plan_version": <最新の整数>, "records": [ ... ] }` です。`records` の各要素は `{ "id"?: <既存ID>, "type": "A"|"AAAA"|"CNAME"|"TXT"|"CAA", "name": <@または完全名>, "content": <文字列> }`。これは形の説明で、コピーして送信できる値ではありません。

1. 直前に詳細をGETし、`label.plan_version` と全レコードを取得します。
2. `managed_by: "system"` と `state: "deleting"` の行を除き、残す利用者レコードをすべて計画へ含めます。既存行のIDは維持し、新規行はIDなしにします。送信する行のフィールドは `id/type/name/content` だけです。
3. 消す行と変更する値を利用者に分かる形で確認します。**省略した既存レコードは削除対象になります。** TXTだけを追加するつもりで、その1行だけを送信しないでください。
4. 直前GETの整数 `plan_version` と全計画を同一Originで送信します。`values` の簡易形式と混在させません。個別形式の `preset` 省略時は `generic` です。
5. 成功応答のレコード状態と診断を確認します。HTTP 200はDNSの全世界反映やHTTPS完了を保証しません。適用処理中・再試行待ちの場合があります。

競合409なら再GETし、他の変更を取り込んで利用者の意図を確認します。版番号だけ差し替えて古い全計画を再送してはいけません。401は再ログイン、403はOrigin等の拒否、404は対象がないか所有権がない場合、429は待機して再試行します。5xxやタイムアウトでは処理済みの可能性もあるため、先にGETで現状を確認し、連続して変更を送信しません。個々のエラーは `{error:{code,message}}` で内容を確認します。

購入・支払い・自動更新停止は対象住所を確認できる画面から進めます。本文はAPIを通じた無断の購入・契約変更を許可するものではありません。

<a id="retire"></a>
## 12. 切替・利用終了

公開先を変えるときは、新しい公開先へホスト名を登録してからbanchiのDNSを変更します。旧公開先はDNSとアプリの切替を確認してから撤去します。

終了するときは、先にbanchiでパークへ戻して接続DNS・所有確認TXTの削除と反映を確認し、その後に公開先のCustom domain、認証・Turnstileの許可URL、GitHubのVerified domains登録を外します。公開先だけ先に削除してDNSを残すと、第三者に登録される危険があります。

自動更新停止は接続解除とは別です。住所詳細の「自動更新の停止へ」で対象契約を確認し、Stripeで確定します。支払い済み期間の扱いは[利用規約](https://banchi.app/terms)に従います。設定不能・撤去不明の場合は[報告フォーム](https://banchi.app/help)へ、ホスト名・公開先・日時・診断コードを記載します。パスワード、Cookie、メールリンク、secretは送らないでください。

<a id="evidence"></a>
## 13. 検証範囲

| 対象 | 実測した内容 | 日付 |
| --- | --- | --- |
| GitHub Pages | 通常画面の取得・DNS、所有確認、HTTPS強制。つなぎ帳の検索・保存・共有・ファイル出力 | 2026-09-06 |
| Cloudflare Pages | 別アカウントへのDNS-only CNAMEとHTTPS。試験接続は撤去済み | 2026-09-05 |
| Workers＋Pages入口 | 別アカウント管理の実DNS・証明書、Service binding、URL/Host/接続元IP、Cookie/Origin/body、CSRF拒否、リダイレクト、SSE・WebSocket、静的ファイルとETag条件付き応答。プレビューの拒否 | 2026-09-10 |
| Vercel / Netlify | 実際の公開先への接続、DNS診断、証明書発行、撤去 | 2026-09-07 |
| 公開IPv4のVM＋Caddy | GCE e2-microでHTTP-01による証明書発行、DNS診断、簡単なHTTPS応答、撤去 | 2026-09-07 |

Workers入口の試験は合成データで行い、banchiの購入・DNS保存画面を通す試験とは分けています。ブラウザ側が検証用ドメインをブロックしたため、Cookieのブラウザ保存・実ログインは未確認です。静的AssetsはRange要求に206ではなく200の全体応答を返しました（条件付きETagは304）。動画のシークや再開ダウンロードなど、部分応答を必要とする機能は個別に確認してください。既存アプリのOAuth・Access・実決済・大容量/長時間通信もこの試験の対象外です。

未実証：到達可能なIPv6環境へのHTTPS通し接続、A＋AAAA構成、手動DNS-01発行・更新、nginx＋Certbot構成、Caddyの実期限での長期更新、任意のWorker/R2アプリのPages移行。本書の設定例や公式手順は、これらの実測成功を主張するものではありません。

追加6サービス（Amplify Hosting、Firebase Hosting、Azure Static Web Apps、Heroku、DigitalOcean App Platform、Cloud Run）のDNS・証明書・アプリの通し接続は未実測です。Workersへの直接CNAME・別アカウントCustom Domainを提供するものではありません。

公開先の仕様や画面が変わった場合は、本文の公式リンクと現在の設定画面を照合してください。借りた住所の外へのDNS、NS移管、秘密情報の提供が必要と出たときは、対応を推測せず運営へ確認します。

<a id="additional-providers"></a>
## 14. 追加の公開先：公式仕様を確認した手順

対象は [State of JavaScript 2025](https://2025.stateofjs.com/en-US/other-tools/) のホスティング利用経験上位10社です（10,704人、複数回答）。AWS、Vercel、GitHub Pages、Netlify、Cloudflare、Firebase、Azure、Heroku、Digital Ocean、Google Cloudの順で、[Stack Overflow 2025](https://survey.stackoverflow.co/2025/technology)も照合しました。個人開発者だけの世界シェアではなく、AWS等の回答数が以下の個別サービスの利用数を表すわけでもありません。Cloudflareは[Pages](#cloudflare-pages)と[Workersの接続用入口](#workers-r2)を同じ事業者の2方式として案内します。

以下は**公式資料に基づく未実測の設定手順**です。ホスティング費用はbanchiの料金と別です。新しい課金設定や公開範囲を、手順の一部として無断で有効にしないでください。親の所有確認、NS移管、5件を超えるDNSが必須なら、値を作り替えて回避せず[問い合わせ](https://banchi.app/help)へ進みます。

| 公開先 | 短い画面案内 | 詳細 |
| --- | --- | --- |
| AWS Amplify Hosting | [画面案内](https://banchi.app/guide#amplify) | [設定手順](#amplify) |
| Firebase Hosting | [画面案内](https://banchi.app/guide#firebase) | [設定手順](#firebase) |
| Azure Static Web Apps | [画面案内](https://banchi.app/guide#azure) | [設定手順](#azure) |
| Heroku | [画面案内](https://banchi.app/guide#heroku) | [設定手順](#heroku) |
| DigitalOcean App Platform | [画面案内](https://banchi.app/guide#digitalocean) | [設定手順](#digitalocean) |
| Google Cloud Run | [画面案内](https://banchi.app/guide#google-cloud) | [設定手順](#google-cloud) |

<a id="amplify"></a>
### 14.1 AWS Amplify Hosting

**アプリの準備:** 公開するリポジトリ・ブランチを選び、**Hosting → Build settings** でビルドコマンドと成果物の `baseDirectory` を照合します。SSRはフレームワークのAmplify対応構成・アダプターを使います。任意のサーバー起動コマンドだけで移せるとは限りません。[ビルド設定](https://docs.aws.amazon.com/amplify/latest/userguide/build-settings.html)・[SSRアダプター](https://docs.aws.amazon.com/amplify/latest/userguide/using-framework-adapter.html)。

**条件付き・実接続未確認。** ビルド・保存・転送等は従量料金です。新規AWSアカウントの条件・期間付きクレジットを恒久無料とは扱いません。

1. 既存アプリをAmplifyで配備し、標準URLで表示・API・認証を確認します。
2. **Hosting → Custom domains → Add domain** を開き、借りたホスト名だけを公開する構成で **Manual configuration** を選びます。デフォルトの親・www登録や転送を確認し、共有親 `banchi.app` の登録・NS移管は選びません。
3. **View DNS records** を開き、配信用CNAMEと証明書確認用CNAMEの**完全な名前**を確認します。すべて借りた名前または配下であることが条件です。`_<発行値>.your-name.banchi.app` のような確認名は個別設定へ入力できますが、画面が実際に指定した名前を使い、推測で借りた範囲内へ書き換えません。
4. banchiの個別設定で、rootのCNAMEと確認用CNAMEを全体の計画に含めて保存します。親側の必須確認やALIAS・NSを要求された場合は停止します。証明書確認のCNAMEを、同じ名前のTXT等と共存させないでください。
5. Amplifyでドメイン・証明書が利用可能になった後、[外形](#checks)と[アプリ](#app-check)を確認します。証明書の自動更新に使う確認用CNAMEは残します。

TLSはAmplifyが管理します。アプリの公開URL、OAuth callback、必要な環境変数は利用者が変更・再配備します。通常のCNAME/TXTの型だけを根拠に、全Amplify構成が利用可能とは判断しません。

出典：[外部DNSでのドメイン設定](https://docs.aws.amazon.com/amplify/latest/userguide/to-add-a-custom-domain-managed-by-a-third-party-dns-provider.html)、[料金](https://aws.amazon.com/amplify/pricing/)。

<a id="firebase"></a>
### 14.2 Firebase Hosting

**アプリの準備:** [公式の初期設定](https://firebase.google.com/docs/hosting/quickstart)で対象プロジェクトを選び、`firebase.json` の `hosting.public` をビルド済み静的ファイルの出力先へ設定してHostingを配備します。既存の設定・HTMLを初期化で上書きせず、公開出力に秘密を含めません。静的Hostingだけでは既存Node等のAPIは動かないため、APIがあれば[Cloud Run等との連携](#google-cloud)と別料金を確認します。

**条件付き・実接続未確認。** 必須TXTが親 `banchi.app` に要求されたら、この構成では接続できません。Firebase HostingとApp Hostingは別製品です。HostingのSpark無料枠は保存10GB・転送360MB/日で、Cloud Run等との動的連携はCloud Billing・Blazeの条件を確認します。

1. 対象Firebaseプロジェクトの **Hosting** を配備し、標準URLで確認します。既存の課金設定・利用量を確認し、無料の試験のために課金を新たに有効にしません。
2. Hostingの **Add custom domain** に借りたホスト名を入力します。所有確認が要求されたら、その名前を確認します。公式ウィザードは必要時にapexの検証を要求するため、借りたホストだけの確認で完了するか、ここで判断します。
3. 貸出範囲内のTXTなら、banchiの個別設定へ保存して **Verify** を押します。続いて **Quick Setup** 等が示すAなどを保存します。接続レコードと同時に確認用TXTを残し、競合する古いCNAMEは計画から外します。要求名・種類が変わった場合は最新画面を優先します。
4. Firebaseの **Connected** と証明書を確認します。確認用TXTは所有確認・証明書更新のため継続保持します。CAAを設定済みなら、Firebaseが使う認証局を妨げていないか確認します。
5. 借りた住所で表示・API・ログインを確認します。Firebase Authentication等を使う場合は、該当ホストの許可設定とOAuthの戻り先も確認します。

所有確認は構成次第です。RESTの現行仕様には対象ホストのTXTまたはHosting標準ホストへのCNAMEによる確認もありますが、ウィザードが要求する親確認を無視してよいという意味ではありません。共有親の証明書発行・子ドメイン数の制限もあるため、接続成功や即時発行を保証しません。

出典：[ドメインの設定](https://firebase.google.com/docs/hosting/custom-domain)、[所有確認のモデル](https://firebase.google.com/docs/reference/hosting/rest/v1beta1/projects.sites.customDomains)、[料金](https://firebase.google.com/pricing)。

<a id="azure"></a>
### 14.3 Azure Static Web Apps

**アプリの準備:** リポジトリ・ブランチと `app_location`（アプリのソース）、`api_location`（管理Functionsを使う場合のソース）、`output_location`（ビルド出力）を[公式ビルド設定](https://learn.microsoft.com/en-us/azure/static-web-apps/build-configuration)で合わせます。任意の常駐サーバーをそのまま起動する構成ではありません。統合APIは `/api` 配下で**最大45秒、WebSocket非対応**です。管理FunctionsはFreeでも使えますが、既存APIを接続するBring your own APIはStandardが必要です。[API仕様](https://learn.microsoft.com/en-us/azure/static-web-apps/apis-overview)。

**公式照合のみ・実接続未確認。** 個人向けFreeはカスタムドメイン2件と自動TLSを含みますが、SLAはありません。独自認証登録や既存Functionsの接続等ではStandardが必要な場合があります。

1. 既存のStatic Web Appsを標準の `azurestaticapps.net` URLで確認します。対象は本番環境で、previewのドメイン設定と混同しません。
2. banchiの個別設定で、rootのCNAMEをそのアプリの標準ホスト名へ保存します。スキームやパスは含めません。
3. Azureの **Settings → Custom domains → Add → Custom domain on other DNS** から借りたホスト名を入力し、**CNAME** で検証します。TXT方式が要求された場合は、指定された完全名が貸出範囲内か確認して保存します。
4. 検証と自動証明書が正常になった後、借りた住所でページ、管理Functions、ログインを確認します。独自の認証プロバイダーを使う場合は利用プランとcallbackを照合します。

Enterprise-grade edge等の別構成ではTXTが必須になるため、すべてをCNAME検証だけで進めません。NS移管やAzure DNSゾーンの作成は、この外部DNS経路の手順に含めません。

出典：[外部DNSでの設定](https://learn.microsoft.com/en-us/azure/static-web-apps/custom-domain-external)、[ドメイン条件](https://learn.microsoft.com/en-us/azure/static-web-apps/custom-domain)、[プラン](https://learn.microsoft.com/en-us/azure/static-web-apps/plans)。

<a id="heroku"></a>
### 14.4 Heroku

**アプリの準備:** `Procfile` 等で `web` プロセスの起動コマンドを定義し、Herokuが設定する環境変数 `PORT` で待ち受けます。再起動でローカルファイルやメモリが失われるため、保存データは別のDB・ストレージへ置きます。標準URLで起動と保存を確認してからドメインへ進みます。[実行環境の契約](https://devcenter.heroku.com/articles/runtime-principles)。

**公式照合のみ・実接続未確認。** アプリ実行は有料です。Ecoは月5米ドルで、30分の非利用による休止等の制限があります。DBや常時稼働の料金は別に確認します。

1. Herokuの標準URLで既存アプリを確認し、ドメイン追加に必要なアカウント確認とプランを確認します。
2. アプリの **Settings → Domains and certificates** に借りたホスト名を追加します。
3. 表示される固有の **DNS Target**（`…herokudns.com`）を、banchiのroot CNAMEへ保存します。アプリの `herokuapp.com` や過去の別アプリの値を使いません。
4. **Automated Certificate Management（ACM）** を有効にし、証明書が正常となるまで待ちます。現在はEcoもACMに対応しています。独自証明書を必須とする古い説明を流用しません。
5. 借りたホストをアプリの許可Host・Origin等に設定し、再配備後に[アプリ確認](#app-check)を行います。ACMの更新にはDNSとドメイン登録の維持が必要です。

出典：[Custom domains](https://devcenter.heroku.com/articles/custom-domains)、[ACM](https://devcenter.heroku.com/articles/automated-certificate-management)、[料金](https://www.heroku.com/pricing/)。

<a id="digitalocean"></a>
### 14.5 DigitalOcean App Platform

**アプリの準備:** 作成時に静的ファイルは **Static Site**、常駐APIは有料の **Web Service** を選びます。リポジトリ・ブランチ、ビルドコマンド、静的出力先を照合します。Web Serviceでは起動コマンドとHTTPポートをアプリの待受けに合わせ、正常に配備されてからドメインへ進みます。自動検出されたコンポーネントの種類・サイズ・費用を確認せず作成しないでください。[アプリ作成](https://docs.digitalocean.com/products/app-platform/how-to/create-apps/)・[ビルドと起動コマンド](https://docs.digitalocean.com/products/app-platform/how-to/build-run-commands/)。

**条件付き・実接続未確認。** 公式はDNSSEC有効ドメインを非対応としています。購入前に現在の条件を確認してください。静的専用3アプリまでの無料枠にも転送上限があり、動的サービス・DBは別料金です。

1. 既存App Platformアプリを標準URLで確認します。DNSSEC条件を満たすか不明な場合は、ドメイン追加の前に問い合わせます。共有親のDNSSECを回避のために変更しません。
2. **Networking → Domains → Add domain** に借りたホスト名を入力し、**You manage your domain** を選びます。**We manage your domain** のNS方式は選びません。
3. 表示された `…ondigitalocean.app` のCNAMEを、banchiの個別設定でrootへ保存し、DigitalOceanで追加を完了します。A経路が必要なら、そのアプリに対して提供元が案内する値と条件を確認します。
4. ドメインと証明書の正常状態を確認し、借りた住所のルート・API・認証を試します。

静的無料枠は各アプリの転送1GiBを含み、超過分は課金されます。banchiでCNAMEを保存できることは、App Platformのドメイン審査・TLSの成功を証明しません。

出典：[ドメインの条件と手順](https://docs.digitalocean.com/products/app-platform/how-to/manage-domains/)、[料金](https://docs.digitalocean.com/products/app-platform/details/pricing/)。

<a id="google-cloud"></a>
### 14.6 Google Cloud Run：Firebase Hosting経由

**アプリの準備:** HTTPを受けるCloud Runの**サービス**を使います。入口のコンテナは `127.0.0.1` ではなく `0.0.0.0` と環境変数 `PORT`（既定8080）で待ち受けます。TLSはCloud Run側で終端するため、コンテナ内の待受けに独自証明書を設定しません。[コンテナの実行契約](https://docs.cloud.google.com/run/docs/container-contract)。公開範囲・IAM・ingressを確認し、意図しない一般公開へ変更せず標準URLの動作を確かめます。

**条件付き・実接続未確認。** Cloud Runの直接Domain mappingは親ドメイン所有確認を要求するため、通常の利用者が `banchi.app` を検証する手順では接続できません。直接mappingはPreview・本番非推奨でもあります。下記の公式Hosting経路はCloud Billing・Blazeが必要です。**60秒を超える要求と、`__session` 以外のCookieを必要とする既存認証は、そのままでは通せません。**

1. 既存Cloud Runの標準URLで動作を確認します。同じFirebase / Google CloudプロジェクトでHostingとCloud Billing・Blazeの条件を確認します。課金を新たに有効にする必要があれば、利用者の判断前に進めません。
2. 対象アプリがHostingの60秒タイムアウトとCookie制約に合うか確認します。HTTP公開用のサービスであってもアプリ自身の認証は必要です。IAMで保護された既存サービスを、この例に合わせて無断で公開しません。
3. 既存 `firebase.json` の `hosting.rewrites` へ対象パスとCloud Runの `serviceId`・`region` を追加します。以下は `/api/**` だけを転送する例です。既存のHosting設定をファイルごと置き換えず、サービス名・地域・パスを実値へ変更します。

```json
{
  "hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "/api/**",
        "run": {
          "serviceId": "your-cloud-run-service",
          "region": "us-central1"
        }
      }
    ]
  }
}
```

4. 対象プロジェクトと公開内容を確認し、既存の配備手順でHostingだけを配備します。Firebase CLIが既に準備・認証され、対象プロジェクトを選択済みの場合の公式コマンドは `firebase deploy --only hosting` です。Nix管理なら既存の開発環境内で実行します。**これは公開設定を変更します。** `web.app` 等の標準URLで、静的ファイル、転送パス、ログインを先に確認します。
5. [Firebase Hostingの手順](#firebase)で借りたホストを登録し、要求された範囲内のDNSを保存します。親TXTを要求されたら停止します。HTTPS完了後、[アプリ確認](#app-check)を実施します。

`public` は静的出力先の例です。静的ファイルはrewriteより先に配信される場合があるため、APIと同名の出力や既存の転送規則を確認します。Cookieの名前だけを変更して認証を弱めず、ホスト限定Cookieとアプリ側の厳密な検証を保ちます。新しい管理APIや専用トークンをbanchiへ要求する構成ではありません。

別案はGoogle推奨の外部HTTPSロードバランサとserverless NEGを使い、banchiのA/AAAAをそのfrontendへ向ける方式です。LB・IP・転送等に独立した料金と運用が必要なので、購入・新規構築前に相談してください。Cloud Runが無料枠内でも構成全体の無料を保証しません。

出典：[HostingとCloud Run](https://firebase.google.com/docs/hosting/cloud-run)、[Cookieとキャッシュ](https://firebase.google.com/docs/hosting/manage-cache#using_cookies)、[rewriteの優先順位](https://firebase.google.com/docs/hosting/full-config#hosting_priority_order)、[ドメイン接続方式](https://docs.cloud.google.com/run/docs/mapping-custom-domains)、[ネットワーク料金](https://cloud.google.com/vpc/network-pricing)。
