🦊

ForgejoをAI Scraperから守る:Anubisの導入手順

に公開

ForgejoをAI Scraperから守る:Anubisの導入手順

セルフホストしているForgejoに、大量のAI Scraperが押し寄せてきた話と、Anubisで解決した手順をまとめます。

何が起きていたか

ある日、筆者が管理するForgejoインスタンスの動作が非常に重くなり、ブラウザからアクセスしても応答までに時間がかかるようになりました。時折nginxのタイムアウトが発生し、アクセスできないことも出てきました。

気になってSSHで接続し調べてみると、リソースの使われ方が明らかにおかしい状態でした。

  • Forgejoのメモリ使用量が増え続ける
  • CPUが常時100%に張り付く
  • gitの子プロセスが大量にfork-execされる

nginxのログを確認すると、git blameのような通常はあまり使われない、かつ処理負荷の高いエンドポイントへのリクエストが大量に来ていました。送信元を調べるとAlibaba CloudのIPアドレス群で、AI ScraperによるものとみられるアクセスがForgejoを攻撃し続けていました。

対策の選択肢を検討する

「結論だけ見たい」という方は手順へどうぞ。

いくつかの方法を検討しましたが、それぞれ問題がありました。

IPアドレス・国・AS番号ブロック
AS番号や国単位でブロックすると、AIスクレイパー以外の正規ユーザーまで巻き込みます。企業が自社のソースコードを外部向けに公開している場合など、特定の国や組織を丸ごとブロックできないケースは多いです。逆に、許可した範囲の中にAIスクレイパーが含まれていれば意味がありません。

レートリミット(nginx limit_req / Fail2ban)
今回のケースでは、無数のIPアドレスを使い回しているため、同一IPのリクエスト頻度は低く抑えられていました。IPベースのレートリミットはほぼ効果なしです。

Cloudflareなどの外部サービス
有効な選択肢ですが、外部サービスへの依存が生まれます。プライバシーポリシーや運用ポリシー上、トラフィックを外部に通したくないケースには向きません。

Forgejoの設定でアクセスを絞る
app.iniREQUIRE_SIGNIN_VIEW = trueでログイン必須にする方法もありますが、これだと未登録ユーザーはリポジトリを一切閲覧できなくなります。オープンソースプロジェクトや、外部に向けてコードを公開したい用途には向きません。特定のエンドポイントだけnginxで塞ぐ方法も、正規ユーザーの操作を制限することになります。

Anubisを選んだ理由
AnubisはProof of Workをクライアント側で解かせることで、ブラウザを持つ人間にはほぼ負担なく、ボットには重すぎる処理コストをかけるしくみです(仕組みの詳細はこちら)。IPや所在地に関係なく接続の"重さ"でふるい分けるため、正規ユーザーを巻き込まずに済みます(という触れ込みです)。

また、外部サービスへの依存がなく、docker composeで管理している場合、数行追加するだけで導入できます。Codeberg、GNOME GitLab、OpenWrt、Arch Linux Wiki、freedesktop.orgなど、GitForgeを運用するOSSプロジェクトでは事実上の標準になりつつあるツールでもあります。

構成

もともと nginx → forgejo という構成だったのを、Anubisを挟んで nginx → Anubis → forgejo の三段構成にします。

AnubisはHTTPのリクエストに対してのみ動作します。SSHによるgit操作(git clone git@...)はAnubisを通らないため、影響を受けません。

今回はHTTPSによるgit cloneやForgejoのAPIを利用していなかったため、これらのリクエストも含めてAnubisで一律にふるい分ける設定にしています。設定がシンプルになる分、スクレイパーへの抜け道もなく、確実にブロックできます。

HTTPSクローンやAPIを利用している場合は、Anubisの設定ファイルで該当リクエストを許可する必要があります。その分設定は複雑になり、許可した経路を突かれるリスクも出てきます。そのケースへの対応は別記事にまとめる予定です。

手順(HTTPSクローン・API不使用の構成)

1. docker composeでAnubisを立ち上げる

compose.yml に以下を追加します。

anubis:
  image: 'ghcr.io/techarohq/anubis:latest'
  environment:
    - 'BIND=:3000'
    - 'SERVE_ROBOTS_TXT=true'  # お好みで
    - 'TARGET=http://<forgejoの内部ホスト名>:<forgejoのlistenポート>'
  restart: unless-stopped
  expose:
    - '3000'
  networks:
    - code-link      # Forgejoと同じネットワークに合わせてください

環境変数の詳細は公式ドキュメントを参照してください。

2. nginxのプロキシ先をAnubisに切り替える

proxy_pass の向き先をForgejoからAnubisに変えるだけです。

# 変更前
proxy_pass http://forgejo:3000;

# 変更後
proxy_pass http://anubis:3000;

動作確認

ブラウザでForgejoにアクセスしたとき、以下のような画面が一瞬表示されれば成功です。

最近あちこちで見かけるようになった、ジャッカルの耳を持つ女の子です。CELPHASEさんによるイラストで、PoWのチャレンジ処理中に表示されます。数秒で自動的にForgejoの画面へ遷移します。

まとめ

導入自体はcompose.ymlの編集とnginxの向き先変更だけで、思ったよりシンプルでした。AI Scraperに悩んでいるForgejoユーザーの参考になれば幸いです。


筆者はForgejoのセルフホスト支援・導入・運用サポートを提供しています。お気軽にご相談ください。

Discussion

ログインするとコメントできます