← すべての記事

Proxyポート: ユーザー名によるターゲティングとセッション制御

FourAのproxyポートはユーザー名からネットワーク、国、スティッキーセッションを読み取り、タイポ時には有効なキーを示す400を返します。その構文仕様を解説します。

新機能

たった1文字の欠落でも問題になります。プロキシのユーザー名に-contry-deと入力した場合、タイポは一見すると正常なオプションのように紛れ込みます。

FourAプロキシポートは、認識可能なすべてのキーをリストした400エラーでこれに応答します。これは、9月15日にベータを終了した製品の細かな仕様の1つです。これにより、プロキシ設定に対応する任意のクライアント(ブラウザ、ダウンロードツール、既存のスクレイパー)向けに、API呼び出しを記述することなくイグジットノードのプロキシURLを利用できます。ダッシュボードでプロキシユーザーを作成し、接続文字列を貼り付けるだけで、トンネルやトラフィックはAPIリクエストと同様にプランのクォータにカウントされます。

構文の全貌と、各ルールの設計理由を以下に示します。

仕組み

このポートはproxy.foura.ai:34004でリッスンし、ポート443および80のターゲットに対してBasic認証を伴うHTTP CONNECTを処理します。認証情報はプロキシユーザーであり、APIキーとは意図的に分離されています。プロキシのハンドシェイクは平文で送信されるため、API連携に手を加えることなくプロキシユーザーのパスワードをローテーションできます。

認証情報以降の部分は、任意の順序で指定できる-key-valueペアのリストです。

# Shared network, a German address, one sticky session for this job
curl -x "http://USERNAME-country-de-session-job42:PASSWORD@proxy.foura.ai:34004" \
  https://example.com

# Premium network, an Android address in Germany, held 30 minutes
curl -x "http://USERNAME-network-premium-country-de-os-android-session-s1-lifetime-30:PASSWORD@proxy.foura.ai:34004" \
  https://example.com

SharedはFourA自前のイグジットです。デフォルトで提供され、プランに含まれています。Premiumは住宅用アドレスであり、プランのpremiumトラフィックおよび追加購入分から消費されます。sharedネットワーク上では、-fallback-premiumを指定することで、shared側で処理できない接続をpremiumイグジットへフェイルオーバーできます。明示的に指定しない限り無効であり、premiumの利用可能枠が残っている場合にのみ機能します。これをデフォルトで有効化することは、その利用枠の消費をユーザーの承諾なしに決定することを意味するためです。

Countryは複数指定可能で、-country-de-country-frは2か国を対象とするスコープになります。Region、city、AS番号によるネットワーク、デバイス種別(windows、android、ios、mac)、およびlifetime(3から1440分)はpremium限定です。sharedネットワークでcityを要求すると、ベストエフォートでの処理ではなく400が返されます。sharedで指定できるのは国単位までです。大半のケースで維持できない都市フィルターは、フィルターが全く存在しない状態よりも有害だからです。

-session-<name>(1から32文字の英数字またはアンダースコア)は接続を固定化(sticky)します。この名前を持つすべての接続は同一アドレスを共有します。sharedでは10分間のスライディングウィンドウでアドレスが維持されるため、使い続ける限り同一アドレスが保持されます。premiumでは設定されたlifetimeまたはネットワークのデフォルト値に従って維持されます。sessionを省略すると、各接続は新しいアドレスから送信されます。

また、デフォルト設定の保存機能もあります。Dashboardでproxyユーザーに保存したターゲティングは、そのユーザーによるすべての接続に適用されるため、接続文字列を必要最小限の認証情報のみに簡略化できます。接続固有のusername指定は常に優先され、anyによって保存された値をクリアできます。-city-anyは、Munich(ミュンヘン)が記憶されているキーに対し、ドイツ全体を対象とするよう要求します。CONNECTにheaderを付与できるクライアント(curlでは--proxy-headerを使用)は、X-Foura-CountryやX-Foura-Sessionなどのオプションをheaderとして送信可能であり、headerの値はusernameの指定より優先されます。

影響

これらの多くは、開発者が不要な疑問を抱かずに済む仕組みとして現れます。

拒否された理由は何か? 認証通過後の拒否には、すべて理由を1行で示すX-Foura-Error headerが付与されます。400の場合は対象オプションと受け付け可能な値が示されます。429の場合は、同時オープントンネル数、1分あたりのトンネル確立数、または請求期間内の標準トラフィックなど、プランの上限に達した項目が特定されます。

利用可能枠は誰に帰属するか? アカウント全体です。トンネル数と確立数はproxyユーザー単位ではなくアカウント単位でカウントされるため、認証情報を追加しても利用枠は増えません。転送バイト数はプランの帯域幅にカウントされ、premiumバイト数はその合計枠内のpremium利用枠として計上されます(合算して加算されることはありません)。クレジット制プランの場合、ポート固有の付属ギガバイトが存在し、Billingページで補充されます。トンネルが開かれなければ何もカウントされません。

認証情報の所有者は誰か? 組織単位での所有が可能になったため、担当者が退職した当日に社内ダウンローダーが停止することはありません。メンバーは使用およびパスワードの参照が可能で、管理者およびオーナーはローテーション、無効化、ターゲティング再設定を行えます。組織外への移動はオーナーのみが実行できます。

何が行われたか Overview、Metrics、またはActivityのProductスイッチをProxyに切り替えます。APIリクエストと同じ結果クラスのトンネル、現在開いている数、セットアップ時間、トラフィックが、proxyユーザー、ターゲット、出口国、またはクライアントIPごとに分割されて表示されます。すでにアドレスが割り当てられているセッションは、通常1秒未満で接続されます。

しかし、ポートは単なるパイプであり、そこにはトレードオフがあります。クライアントはトンネル経由でサイトと通信するため、ブラウザプロファイル、validate rules、インタラクティブページの処理はその経路に含まれません。また、バイト単位で計測されます。開いているトンネルを通じて返される拒否ページも他のデータと同様にバイトとしてカウントされますが、APIでは成功しなかったリクエストは課金されません。単純なバイト転送にはポートを使用し、ブロックしてくるページはAPIに送信してください。

パワーユーザー向け

プレミアム枠を使い切ると、そのネットワークへの3つのルートには意図的に異なる3つの応答が返されます。-network-premiumを指定する接続は、その旨を示す403で拒否されます。別の場所から黙って処理された場合、呼び出し元はリクエストを送り続け、請求書に記載されないプレミアム枠の行を探すことになるためです。フォールバックは単に実行されず、proxyユーザーに保存されたプレミアムデフォルトは共有ネットワークにフォールバックするため、トンネルは開いたままになります。どちらもその接続でプレミアム枠の消費を選択していません。

中途半端に処理するのではなく、完全に拒否される組み合わせが3つあります。共有ネットワークでの詳細なターゲティング、-fallback-premiumと-network-premiumの併用、およびフォールバックが設定されている状態での詳細なターゲティングです。ポートはCONNECTのみをサポートするため、トンネリングせずに通常のhttp://リクエストを転送するクライアントには405が返されます(curlは--proxytunnelでトンネリングします)。また、1回のページ読み込みで数十の接続が開かれるため、ポート経由で操作されるブラウザには常にセッション名を付与する必要があります。

複数のワーカーがそれぞれ独自のアドレスを持つ場合。各ワーカーに個別のセッション名を割り当てます。

import requests

TEMPLATE = "http://USERNAME-country-de-session-{name}:PASSWORD@proxy.foura.ai:34004"

def worker_session(name):
    proxy = TEMPLATE.format(name=name)
    s = requests.Session()
    s.proxies = {"http": proxy, "https": proxy}
    return s

workers = [worker_session(f"w{i}") for i in range(4)]
print(workers[0].get("https://example.com").status_code)

Dashboardでも同様の操作を大規模に実行できます。Stickyを設定し、数を指定すると、Connection stringタブにアドレスごとの行がURL形式、またはproxyマネージャー向けのhost:port:user:pass形式で一覧表示されます。接続拒否の原因を調査する場合は、cURL呼び出しに-svを追加し、2>&1 | grep -i x-foura-errorにパイプしてください。すべてのオプションはproxy port referenceに記載されており、Dashboard側の設定はProxy Usersにあります。

今後の予定

proxy userを基盤として最初に構築したクライアントは、自社製のツールです。FourA Chrome拡張機能は、ブラウザトラフィックをいずれかのユーザー経由でルーティングします。ネットワークと国を選択してスイッチをオンにすると、サイト側に認識されているアドレスがステータス行に表示されます。これはベータ版であり、Chrome Web Storeには公開されていません。DashboardのToolsからデベロッパーモードでインストールします。さらに先の実装として、公開ロードマップにorganization billingが予定されています。組織のproxy userに対する課金は、現在その組織を所有するアカウントへ請求されるため、この機能は重要になります。

proxy URLは最も古くから存在する統合規約であり、既存のあらゆるツールがすでに対応しています。真に最適化すべき対象はトンネルそのものではありませんでした。その手前にある文字列がどのような意味を持つことを許可されているか、そして指定を誤ったときに何が起きるかという点です。