アーキテクチャと技術リファレンス
本ドキュメントは開発者 / 技術に興味のある方向けです。デプロイして使うだけなら、メイン README の「3 ステップで完了」を参照してください。
これは何をするものか
メールマーケティング/通知システムは、メールに追跡ピクセルとクリック ID 付きリダイレクトリンクを埋め込み、開封率とクリック率を計測します。これらのリンクの背後には追跡バックエンド(例: cf-track.laifa.xin)があります。
問題点:
- バックエンドのドメインを直接使用 → 大量送信 → 迷惑メールフィルタによりブラックリスト化
- 共有追跡ドメイン → 他のユーザーの行動が自分のドメイン評価を汚染
- Microsoft Defender / Outlook がメール内のリンクを自動 GET して事前スキャン → 開封/クリック統計を汚染
この Worker による解決:
自分のドメインをリバースプロキシ層として使い、4 段階フィルタリングを実装:
受信者がクリック → 自分のドメイン (track.yourdomain.com)
↓
┌──────────────────────┐
│ Worker / Edge Func │
│ │
│ L0 .php/.aspx 拒否 │ → 302 google.com
│ L1 パス許可リスト │ → 302 google.com
│ L2 MS スキャナ対策 │ → 302 google.com
│ L3 リバースプロキシ │
└──────────────────────┘
↓
実際の追跡バックエンド (cf-track.laifa.xin または独自)
↓
開封/クリック記録 + ピクセル/リダイレクト返却受信者には自分のドメインが見えますが、データは引き続き元の追跡バックエンドに流れます。
4 段階フィルタリングの詳細
| 段階 | 役割 | 動作 |
|---|---|---|
| L0 | 拡張子ブロックリスト — .php / .aspx は一般的なスキャナの特徴 | 302 → google.com |
| L1 | パス許可リスト — 追跡用パス(/r/、/track/、/img/、/att/、/attachment/ など)とルート直下の静的ファイル(.png/.ico など)のみ許可 | 不一致 → 302 |
| L2 | Microsoft Defender SafeLinks スキャナ指紋検知(ヘッダ + ASN/IP レンジ) | 302 → google.com |
| L3 | BACKEND_HOST へのリバースプロキシ、元のパス/パラメータをそのまま転送 | — |
L2 の 2 つの実装
ヘッダ指紋(全プラットフォーム共通) Referer 空 + Sec-CH-UA-Model="Surface Pro"
ネットワーク指紋(プラットフォーム別)
├─ Cloudflare Worker ネイティブ ASN 8075 (MICROSOFT-CORP-MSN-AS-BLOCK)
└─ Vercel/Netlify/Deno IP レンジマッチング(フォールバック)IP レンジフォールバックについて: Vercel/Netlify/Deno は ASN にアクセスできないため、Microsoft IP レンジ(EOP outbound + Microsoft 365 services + MS Corp 歴史レンジ)をハードコードして照合します。ASN より若干精度は劣り、3〜6 ヶ月ごとに更新が必要です。
リポジトリ構成
.
├── src/index.js # Cloudflare Worker(ASN + IP デュアル検査)
├── wrangler.jsonc # Cloudflare 設定
├── vercel/
│ ├── api/track.js # Vercel Edge Function(IP 検査)
│ ├── vercel.json
│ ├── package.json
│ └── quick-start.md
├── netlify.toml # Netlify 設定
├── netlify/edge-functions/track.js # Netlify Edge Function(IP 検査)
├── deno-deploy/
│ ├── main.js # Deno Deploy(IP 検査)
│ └── quick-start.md
├── shared/microsoft-ranges.js # Microsoft IP レンジの source of truth
├── public/index.html # Netlify publish ディレクトリのプレースホルダ
├── docs/
│ ├── custom-domain.md # カスタムドメインガイド(4 プラットフォーム)
│ └── architecture.md # このドキュメント
├── CHANGELOG.md # バージョン履歴(英語)
├── quick-start.md # メイン README(簡潔版)
└── LICENSE # MITローカル開発
Cloudflare
bash
npm install -g wrangler
wrangler login
wrangler dev # ローカル起動
wrangler deploy # デプロイVercel
bash
cd vercel && npm install -g vercel
vercel dev
vercel --prodNetlify
bash
npm install -g netlify-cli
netlify dev
netlify deploy --prodDeno Deploy
bash
cd deno-deploy
deno run --allow-net --allow-env main.js # :8000 で起動
# デプロイは GitHub 連携 (dash.deno.com/new) 経由、CLI 不要パス許可リストの変更方法
ALLOWED_PATH_PREFIXES を拡張・変更するには、4 つの プラットフォームソースの定数を同期する必要があります:
src/index.js(CF)vercel/api/track.jsnetlify/edge-functions/track.jsdeno-deploy/main.js
編集後 push すれば各プラットフォームが自動再デプロイ(CF は手動で wrangler deploy)。
Microsoft IP レンジの更新
shared/microsoft-ranges.js が source of truth です。同期手順:
- endpoints.office.com または bgpview.io/asn/8075 から最新データを取得
shared/microsoft-ranges.jsのMICROSOFT_IPV4_RANGESを更新- 4 プラットフォームの
MICROSOFT_IPV4_RANGES定数に同期 - Commit + push
3〜6 ヶ月ごとの更新を推奨。CF の ASN 検出には影響しませんが、残り 3 プラットフォームには影響します。
プラットフォーム比較
| プラットフォーム | L2 スキャナ対策 | ドメイン柔軟性 | 無料枠 |
|---|---|---|---|
| Cloudflare Workers | ネイティブ ASN(最高精度) | DNS を CF にホスト必要 | 10 万リクエスト/日 |
| Vercel | IP レンジマッチング | 任意の DNS で CNAME | 100GB 転送量/月 |
| Netlify | IP レンジマッチング | 任意の DNS で CNAME | 100GB 転送量/月 |
| Deno Deploy | IP レンジマッチング | 任意の DNS で CNAME | 100 万リクエスト/月 |
注意事項
- デフォルトのバックエンドは
cf-track.laifa.xin— これはテンプレート作者の追跡バックエンドです。選択肢:- デフォルトを維持: トラフィックは作者のバックエンドを経由(デフォルトプロトコルは HTTP、非暗号化)
- 独自に変更:
BACKEND_HOSTを自分の追跡バックエンドアドレスに変更
- HTTP バックエンド: デフォルトの
BACKEND_PROTOCOL=http:は作者のバックエンドが HTTP のため。HTTPS の場合はhttps:に変更 - 通常の Web サービスを提供するドメインに設置しないこと — パス許可リストが非常に狭いため、通常の Web リクエストは 302 されます
CI 自動化(リポジトリ内部)
.github/workflows/update-i18n-badge.yml: README*.md の push 後、i18n バッジ JSON を自動再計算- メイン README
releaseバッジ: GitHub Releases API から最新タグをリアルタイム読み込み - メイン README
i18nバッジ: endpoint モードで.github/badges/i18n.jsonを読み込み