セルフホストファネル起動ガイド
Autonnel(Apache-2.0)を使用して、ファネルを何もない状態からオペレーターが管理するインフラストラクチャ上に公開します。このスキルはビルドステップです。まず sales-funnel-blueprint でファネルを設計し、セルフホスティングが適切な選択かどうかを funnel-platform-picker で確認してください(まだ利用可能な場合)。
ステップ 1:実行方法を選択する
| パス | 低トラフィック時のコスト | 運用負荷 | 用途 |
|---|---|---|---|
| Cloudflare Workers | 実質 $0 + Postgres 費用 | サーバー不要、パッチ適用不要 | 本番環境のデフォルト。 ファネルページはほとんどが静的アセットであり、Workers は無料かつ無制限で提供します |
| Docker | VPS またはコンテナホスト1台分のコスト | ユーザー自身: アップグレード、バックアップ、稼働時間管理 | 2分でのローカル評価、または既に運用しているサーバーでデータを保持したい場合 |
| ソースコード (Node) | VPS またはコンテナホスト1台分のコスト | ユーザー自身 | Autonnel 自体の改変、または Node ビルドを直接実行する場合 |
特別な理由がない限り、Workers を推奨します。価格モデルがファネルにほぼ完全に適合し、セルフホスティングを敬遠させる原因となる作業(サーバー管理全般)を排除できます。
最初の確認にはDockerを使用してください。製品を確認する最も速い方法であり、ローカルで構築したものが無駄になることはありません。同じスキーマと同じ管理UIが両方のパスをサポートします。
ステップ 2a:Cloudflare Workers(ほぼ無料の本番パス)
コストがほぼゼロになる理由
ファネルトラフィックの大部分はページ、画像、スクリプトへのリクエストです。Workers 上ではこれらは静的アセットリクエストとなり、無料かつ無制限で、ストレージコストもかかりません。Worker を呼び出すリクエスト(サーバーサイドレンダリングページ、チェックアウト、API)のみが課金されます。ファネルの動的サーフェスは小さく、注文フォーム、アップセル承認、ポストバックキュー程度です。
確認済みの Cloudflare 無料プラン制限(2026年8月確認。利用前に現在の数値を確認してください):
| リソース | Workers 無料プラン |
|---|---|
| 静的アセットリクエスト | 無料かつ無制限、ストレージ料金なし |
| Worker 呼び出し | 100,000 リクエスト/日 |
| Hyperdrive (Postgres プーリング) | 無料プランで利用可能、100,000 データベースクエリ/日 |
| Workers KV (ページキャッシュ) | 100,000 読み取り/日、1,000 書き込み/日、1 GB ストレージ |
| Cron トリガー | サポート対象(リポジトリには scheduled ハンドラが同梱) |
無料ではないもの: Postgres。Hyperdrive はユーザーが提供するデータベースへの接続をプールするため、Postgres プロバイダーが別途必要です。マネージドプロバイダーには独自の無料枠と制限があり、それが唯一計画すべき費用項目です。
実際に最初に達する制限はリクエスト数ではなく、KV 書き込み数です。 1日1,000回の書き込みはページ配信には十分ですが、公開(パブリッシュ)には不十分です。公開はキャッシュエントリを無効化しリフレッシュするためです。編集作業が多い日は、トラフィックが制限に近づいていないうちにこの制限を使い果たす可能性があります。トラフィックより先に公開が失敗し始めた場合、これはバグではなく、この制限が原因です。
デプロイ
リポジトリには Workers ツールチェーン全体が含まれています。cron scheduled ハンドラ(src/cf-worker.ts)、wrangler.toml 生成、KV キャッシュ配線、Postgres 用の Hyperdrive などです。
npx wrangler login
npx wrangler kv namespace create CACHE_KV
# $DATABASE_URL はオペレーター自身の Postgres 接続文字列で、シェルにエクスポートされています。
# このコマンドや wrangler.toml に資格情報を書き込まないでください。
npx wrangler hyperdrive create autonnel-db --connection-string="$DATABASE_URL"
各コマンドは ID を出力します。それらをプロジェクトの隣にある .env に記述します:
CF_WORKER_NAME=my-funnels
CF_KV_NAMESPACE_ID=<kv namespace create の ID>
CF_HYPERDRIVE_CONFIG_ID=<hyperdrive create の ID>
次にシークレットを設定してデプロイします:
npx wrangler secret put DATABASE_URL
npx wrangler secret put AUTH_SESSION_SECRET # openssl rand -hex 32
npx wrangler secret put CREDENTIALS_ENCRYPTION_KEY # openssl rand -base64 32
npm run deploy:cf
deploy:cf は最初にテンプレートから wrangler.toml をビルドおよび生成するため、個別の生成ステップはありません。Cron 式は手書きではなくアプリのクロジョブレジストリから読み取られます。生成された wrangler.toml を手動で編集しないでください。ビルドのたびに上書きされます。
CF_* 変数が欠落している場合、生成は失敗し、その変数名を指定します。これが意図された動作であり、これらのための暗黙のデフォルトはありません。
最初のアクセスの前に、同じ Postgres に対してデータベーススキーマを一度適用し、Worker URL を開いて /setup ウィザードを完了し、管理者アカウントを作成してください。
また、npm run dev:cf(Workers ランタイム上の開発サーバー)および npm run preview:cf(wrangler dev によるローカルプレビュー)も利用可能です。ターゲットが Workers の場合は、プレーンな astro dev よりもこれらを優先してください。ランタイムが異なるためです。
運用後の操作
以下の CLI コマンドはデータベースアクセスを必要とし、コンテナは必要ありません。同じ Postgres を指す DATABASE_URL を持つチェックアウトから:
npx autonnel admin:create [email protected] 'a-strong-password'
npx autonnel password:reset [email protected]
ステップ 2b:Docker(ローカル評価、または独自サーバー)
https://github.com/autonnel/autonnel(Apache-2.0)からリポジトリを取得し、リリースタグをチェックアウトして、その docker-compose.yml を読んでください。実行されるイメージとポートが宣言されています。そのチェックアウトから:
docker compose up
http://localhost:4321 を開き、/setup を完了してください。Compose ファイルは Postgres を起動し、スキーマを適用し、アプリを実行します。起動に他に必要なものはありません。ストア、支払い、メディアストレージ、メール、AI は後で管理 UI で設定され、実際に使用される機能に対してのみ設定します。
公開ホストに公開する前に、docker-compose.yml の隣にある .env に実際のシークレットを配置してください。出荷時のデフォルトは安全でない開発用の値であり、最初のローカル実行がゼロ設定で機能するようにのみ存在します:
AUTH_SESSION_SECRET=$(openssl rand -hex 32)
CREDENTIALS_ENCRYPTION_KEY=$(openssl rand -base64 32)
ADMIN_DOMAIN=admin.example.com
各値を一度生成し、安定させてください。AUTH_SESSION_SECRET をローテートするとセッションが無効になります。CREDENTIALS_ENCRYPTION_KEY をローテートすると、保存されたプロバイダー資格情報が読み取り不能になり、すべての支払いおよびプラットフォーム資格情報を再入力する必要があります。
マルチアーキテクチャイメージは GHCR に公開されており、既存のデータベースに対して単純な docker run で使用できます:
# DATABASE_URL、AUTH_SESSION_SECRET、CREDENTIALS_ENCRYPTION_KEY は
# オペレーター自身の環境から取得します。これらの値をコマンドやファイルに書き込まないでください。
docker run -p 4321:4321 \
-e DATABASE_URL \
-e AUTH_SESSION_SECRET \
-e CREDENTIALS_ENCRYPTION_KEY \
-e ADMIN_DOMAIN="admin.example.com" \
ghcr.io/autonnel/autonnel:v1.5.0
:latest ではなく正確なタグを固定してください。新しいタグをプルした後は、スキーマを再適用してください。Compose ファイルの one-shot スキーマサービスは docker compose up のたびに再実行されます。オーケストレーター用のヘルスエンドポイント: /api/health(データベースとキャッシュの接続性を確認)。
コンテナ内の管理 CLI:
docker compose exec app node dist/cli/index.js admin:create [email protected] 'a-strong-password'
ステップ 2c:ソースコードチェックアウト(Node)
Autonnel 自体を改変する場合、または既に所有しているホスト上で Node ビルドを実行する場合に使用します。Node 22 以上と Postgres が必要です:
npm create autonnel@latest my-funnel
cd my-funnel
cp .env.example .env # DATABASE_URL と ADMIN_DOMAIN を設定
pnpm install # pnpm 10+;リポジトリは npm が無視するオーバーライドを固定
npm run db:push
npm run dev # または: npm run build && npm run start
これによりリポジトリがクローンされ、git 履歴が削除されます。スキーマはチェックアウト内の prisma/schema.prisma にあります。db:push が同期します。管理 CLI: プロジェクトディレクトリから npx autonnel admin:create [email protected] 'a-strong-password'
ステップ 3:ファネルに必要なものだけを設定する
管理 UI の Settings で:
| 設定 | 必要な用途 | オプション |
|---|---|---|
| Ecommerce | 製品および注文データ | Shopify, WooCommerce, Picocart |
| Payments | 支払い受け取り | Stripe, PayPal |
| Storage | 画像/動画アップロード | S3互換バケット(R2, S3, MinIO) |
| 領収書、リコールキャンペーン | SMTP, Resend, AWS SES | |
| LLM | AIページ生成 | OpenAI互換エンドポイント |
| Ad platforms | サーバーサイドコンバージョン(全4つ);広告レベルの支出/クリックレポート(Facebook、Google Ads、TikTokのみ) | Facebook, TikTok, Google Ads, Bing |
やり直しを避けるための作業順序: カタログが最初(チェックアウトで販売できるものが決まる)、次に支払い、次にストレージ、次にメール、最後に広告プラットフォーム。トラッキングは実際の注文に対して検証されるため、他の部分が機能している必要があります。支出レポートのために広告プラットフォームを接続することは、ポストバックのためにファネルにバインドすることとは別のステップです(server-side-conversion-tracking を参照)。両方必要な場合は両方実行してください。
Workers 上では、R2 が明らかなストレージの選択肢です。S3 互換であり、メディアの外部への転送を Cloudflare 内に留めます。
ステップ 4:ページを構築する
ファネルの役割は、ファネル仕様に直接対応します:
| ファネル内の役割 | 目的 | ファネルごとに複数? |
|---|---|---|
LANDING | エントリページ、トラフィックソースごとに1つ | はい |
CHECKOUT | 注文フォーム | いいえ - ファネルごとに1つ |
UPSELL | 購入後のオファー、チェーンに順序付け | はい |
THANKYOU | 確認 | いいえ |
ERROR | 支払い失敗 / フォールバック | いいえ |
これらはページがファネル内で取る役割です。API 上では、ページ自体のタイプは CHECKOUT | THANKYOU | ERROR | UPSELL | CUSTOM です。ランディングページは CUSTOM として作成され、LANDING としてファネルにバインドされることでランディングページになります。
2つのエディターが利用可能です: 出力が差分可能な JSON であるコンポーネントベースのビジュアルエディターと、インポートされたページ用の生の HTML です。後で A/B テストされたりエージェントによって編集されるものには、コンポーネントエディターを優先してください。JSON の差分はきれいにレビューできますが、HTML ブロブはそうではありません。
ランディングページの前にチェックアウトを構築してください。チェックアウトによって実際に販売できるものとその価格が決まります。先に書かれたランディングページは、チェックアウトが提供できないものを約束する可能性があります。
ステップ 5:ファネルを配線する
- ファネルを作成し、ページを役割と順序でアタッチします。
- 同じページを複数のファネルで参照できます。ドメインが強制する唯一の一意性ルールは、
stepSlugが1つのファネル内で一意であることです(そしてページはファネルごとに最大1回表示されます)。クロスファネル拒否は設計上ありません。2つのファネルを分岐させたい場合にのみランディングページをクローンしてください。共有ページの編集は、それを参照するすべてのファネルに反映されます。 THANKYOUとERRORは、作成時に既存のページから自動バインドされます(存在する場合)。テナントにない場合は、公開前に作成してください。エラーページがないファネルは、支払い拒否時に静かに失敗します。- 広告キャンペーンに入る URL は、ストアフロントホスト上のランディングページ自身のスラッグです -
https://shop.example.com/{page.slug}- 決して/n/ステップ URL ではありません。/n/{funnelId}/{stepSlug}は次のステップに転送するため、ページの CTA リンクに属し、広告には属しません。この方法で CTA を記述すると、ステップが別のページに交換された場合でも購入者のパスが安定します。 - 公開は明示的であり、ページごとおよびファネルごとにバージョン管理されます。ページを公開してもファネルバインディングは公開されません。
ステップ 6:トラフィックを送る前に計装する
開始前に必須のチェック:
- 実際のエンドツーエンドの購入を1回、実際の支払いプロバイダーで行う。基本注文、1回の承認されたアップセル、1回の辞退されたアップセル、サンキューページ、領収書メール、接続されたストアに注文が表示されることを含む。
- その注文に対して1回の返金を行い、返金パスが各チャージに対して機能することを確認する。
- クリック ID カバレッジ -
fbclid/ttclid/gclid/msclkidが注文レコードに到達することを確認する。server-side-conversion-trackingを参照。 - サーバーサイドコンバージョンが各広告プラットフォームのイベントデバッガーに到着し、クリック ID が添付され、ブラウザイベントとの重複がないこと。
- エラーページに到達可能であること。カードを強制的に辞退させて確認する。
Workers 上では、もう1つ追加: cron scheduled ハンドラが起動していることを確認する(キューに入れられたポストバックとリコールキャンペーンはこれに依存します)。Cron トリガーが失われたデプロイは、バックグラウンド処理が静かに停止している間も正常に見えます。
その後でのみ支出を増やしてください。実際のトランザクションが通過したことのないファネルは、失敗率が低いのではなく、未知です。
ステップ 7:MCP 経由でエージェントから運用する
インスタンスは管理 API を /api/mcp で MCP ツールとして公開するため、エージェントは UI なしでファネルを構築および変更できます。
{
"mcpServers": {
"autonnel": {
"transport": "http",
"url": "https://<your-autonnel-host>/api/mcp",
"headers": { "Authorization": "Bearer <your-api-key>" }
}
}
}
MCP クライアントではなく生の HTTP で /api/mcp を呼び出す場合、SDK が通常隠す2つのトランスポート要件があります。エンドポイントは Streamable HTTP を話します。リクエストは Accept: application/json, text/event-stream を運ぶ必要があります。不足するとツールレイヤーに到達する前に 406 で拒否されます。そして成功は SSE フレーム(event: message / data: {...})として返されるため、JSON-RPC エンベロープは解析前に data: から取り出す必要があります。
アプリ全体の前にもう1つのトラップがあります。Cloudflare のデフォルトの管理ボットルールの背後にあるインスタンスは、Python 標準ライブラリのユーザーエージェントを拒否します。urllib クライアントは Python-urllib/3.x を送信し、/api/health を含むすべてのパスで平文の本文 error code: 1010 とともに 403 を受け取ります。これは認証または権限の失敗とまったく同じように見え、JSON ではないため、本文を解析するクライアントはステータスを確認する前にエラーをスローします。そのエージェント文字列のみがブロックされます - curl、python-requests、httpx、axios、node、空の UA はすべて通過します。Python でこれをスクリプト化する場合は、明示的な User-Agent を設定するか、requests/httpx を使用してください。認証されていない呼び出しを含むすべての呼び出しが 403 を返す場合、これが理由であり、API キーでは修正できません。
プロジェクトルートの .mcp.json は Claude Code 用、claude_desktop_config.json は Claude Desktop 用です。キーは管理 → Settings → API Keys で生成します。すべての呼び出しはテナントのデータにスコープされます。