
悪意のあるボットがサーバーにアクセスするのを自動的に阻止する
TUI、Web UI、CLI を備え、CDN の背後に隠れることなく、悪質なボットをサーバー側で遮断するための設定を支援するツールです。
NGINX と既存のファイアウォール(iptables または nftables)と連携し、2 つの異なるレイヤーで動作します:
このアプリはサーバーから締め出さないよう最善を尽くしますが、使用は自己責任でお願いします。また、AGPL ライセンスの下で提供されているため、商用利用する場合はライセンスの文言に従ってください。
crates.io から:``` cargo install stop-bots
チェックアウトからビルドする場合:```
cargo install --path .
GitHub の releases で、ビルド済みの x86_64 Linux バイナリを入手できます。
ビルドには Rust 1.88 以降が必要です。実質的に Linux 専用です。systemctl、nginx -t、nft/iptables を外部コマンドとして呼び出すため、他の環境でもコンパイルはできますが、そこではほとんど役に立ちません。
引数なしでバイナリを実行すると TUI が起動します。同じ画面をブラウザで表示するには stop-bots web(Web UI を参照)、CLI サブコマンドの完全な一覧は stop-bots --help を参照してください。TUI と CLI は併用できます。TUI ですべてを設定し、その後 crontab で CLI を使ってルールを最新の状態に保つ、という使い方ができます。
アプリの終了、またはポップアップ/サブメニューから戻るには、'q' または Escape を押します。
't' でダークテーマとライトテーマを切り替えられます。アプリはテーマの自動検出を試みますが、一部のターミナルとマルチプレクサの組み合わせでは、正しい選択を行うための情報が十分に得られません。
1〜4(または d/b/s/p)で各画面に直接ジャンプできます。Left/Right、またはその vim エイリアス h/l で画面を順に移動できます。? でいつでもキーバインドの完全なリファレンスを切り替え表示でき、: でコマンドパレットを開いてすべてのアクションを名前で一覧表示できます。Tab / Shift+Tab は常に現在の画面のパネル間を移動し、画面間を移動することはありません。
Dashboard はファイアウォールスクリプトに最終的に含まれるすべてを管理し、Site settings はNGINX 設定に最終的に含まれるすべてを管理します。この分担によって、各設定がどこに属するかが決まります。
Up/Down は 3 つのリスト間を移動します。m はジオモードを切り替えます。F を押すと現在のファイアウォールルールをスクリプトにレンダリングします — ポップアップには「apply after writing」トグル(Space)もあり、後で手動で適用する代わりに、実際に即座に適用できます。さらに 3 つのキーがホスト全体に作用します。u はすべてのリストをダウンロードし、a は両方のプレーン(NGINX、次にファイアウォール)を適用し、w はこのコンソールを NGINX の背後に配置します — ブラウザでボタンとパネルとして提供されているのと同じ 3 つです。Tab でフォーカス)— ブロックされたリクエストに何を返すか(下記参照)、生成された robots.txt を配信するかどうか、レート制限 — が、ディスク上で検出されたすべての NGINX サイトの上にあります。各サイトにはライブの「up to date / stale / not found」ステータスと、現在のポリシーを 1 つのサイトまたはすべてのサイトに適用するアクションがあります。これらの設定を変更すると、適用済みのすべてのサイトが STALE に変わり、再適用の合図となります。サイトを開くと、そのカテゴリ/ボットポリシーをオーバーライドし、6 つのリクエスト形状ルールのいずれかをオンにし、ブロックから除外するパスを一覧表示できます。Bot settings。すべてのリストソースとすべての個別ボットがここにあります:
Site settings。ホスト全体の NGINX の選択肢が、ディスク上で見つかったすべてのサイトの上にあります:
Dynamic Protection。現在サーバーに到達しているもののライブビュー:
既知のボットをカテゴリ別(scanner / search engine / AI crawler)に。
ArcJet's Well-Known Bots、
ai.robots.txt、
NGINX Ultimate Bad Bot Blocker
リストから取得します。カテゴリをブロックすると、各サイトの NGINX 設定に if ($http_user_agent ...) ルールが挿入されます(apply-blocks / Site settings の a/A)。
リクエストが多すぎる場合は、NGINX 自身のレート制限を使います。ここにある他のすべてとは異なり、これは後でログを分析するのではなく、リクエスト時に NGINX によって適用されます。既定ではオフです。間違ったサイトに合わせた制限は、実際の訪問者を追い払ってしまいます。
まず礼儀正しく — ブロックしているすべてのボットを列挙した、生成された robots.txt(任意)。これを尊重するクローラー向けで、下記のハニーポットパスも含みます。既定ではオフです。現在 /robots.txt で配信しているものを置き換えてしまうからです。
ただし指定した場所以外では — サイトごとのパス除外により、/blog 以外では AI クローラーをブロックする、といったことができます。
ブラウザらしくないリクエストをサイトごとに。6 つの独立したルールがあり、それぞれに専用のトグルがあり、すべて既定ではオフです — ルールごとに 1 つのスイッチなので、自分の何かが動かなくなったとき、どのルールが原因か分かります:
Site settings にあるホスト全体の 1 つの選択肢です。これらは互換可能なステータスコードではありません — それぞれ異なることを伝え、その違いは、あなたが捕まえるつもりのなかったクライアントにとって最も重要です:
ターピットは誤検知に対して最も穏やかなオプションです — 誤って捕まえたクライアントは拒否されず、遅くされるだけです — そしてボットにとってはコスト面で最も厳しく、その接続はアイドル状態のままになります。これを選ぶ前に知っておくべきことが 2 つあります。ターピットはその間、あなたのワーカー接続の 1 つも占有するので、ターピットされたクライアントの洪水は worker_connections をめぐって実際の訪問者と競合します。そして実際にどれだけ続くかは、NGINX が小さなエラーボディをどう書くかに依存し、TODO.md に実際のサーバーでの確認が必要と記されています。
これらはそれぞれ Dashboard の「Automatic blocking」パネルにある独立したスイッチで、それぞれが自動的に期限切れになり、行為が続けば再追加される一時的なファイアウォールブロックを追加します。
これらは内部タイマーで動作し、毎分 SSH と NGINX のアクセスログを読み直します — ただし TUI または Web UI が実行されている間だけです。 どちらでも同じスケジュール、同じデータベースで動作するので、Web UI を立ち上げたままにしておけば十分です。どちらも実行されていないときは何も検出されません。stop-bots プロセスがまったく動いていないサーバーについては、下記の Unattended, from cron を参照してください。
/.env、/.git/config、/wp-config.php などへの単一のリクエストはそれだけで決定的なので、しきい値は不要です。組み込みリストは、どこかで正当なパス — /wp-login.php、/wp-admin/、/xmlrpc.php、/phpmyadmin — を意図的に除外しています。自分の管理者を締め出すのは、404 検出器がどうせ捕まえるスキャナーを見逃すより悪いからです。set-probe-paths で独自のパスを追加できます。robots.txt に Disallow: としてのみ公開され、どこからもリンクされていないパス。そこに到達することは robots.txt を無視することを意味し、正当なものは偶然にはそうしません — ここで最強のシグナルであり、最長のブロックです。機能させるには robots.txt 生成がオンになっている必要があります。さらに 3 つは、クライアントが何を求めるかではなく、どのように振る舞うかに注目します。3 つとも既定ではオフです。それぞれに単独では排除できない誤検知があるからです — そして 3 つとも検証済みの検索エンジンクローラーを除外します。そうでなければ、それらすべてに一致してしまうからです:
304 は取得されたアセットとして数えられます)。アセットをまったく配信しないサイト — 純粋な JSON API — では役に立ちません。Referer が決してない。Referrer-Policy: no-referrer とプライバシーツールによって弱められます。異なるパスのしきい値が、これをそもそも使えるものにしています。/24 内の複数のアドレスが同じパスでフラグ付けされた場合、その /24 をブロックします。既定ではオフです — 3 つが問題を起こしたからといって 256 個のアドレスをブロックするのは、設計上の巻き添えです。(IPv6 は異なり、スイッチは不要です。検出は常に /64 をブロックします。/64 は 1 つの LAN であり、単一の IPv4 アドレスが表すものと同じだからです。IPv6 攻撃者がたまたま使った単一のアドレスをブロックしても何も止まりません — 彼らにはさらに 2^64 個あります。)上記はすべて生成されたものです。そのいずれかが実際に有効かどうかは別の問題であり、それに答えるのが stop-bots status です:```
stop-bots status
7つのチェックがあり、最初のものが最も価値がある。生成されたルールは実際にカーネル内に存在するのか、それともディスク上にあるだけなのか? ある実ホストでは、`/etc/stop-bots/firewall.nft` に48,860件のdropルールがありながらルールセットが空のまま3週間稼働していた。スクリプトの作成とロードは2つのステップであり、2番目を確認するものが何もなかったからだ。
残りは、ルールセットが再起動後も維持されるか(`nftables.service` が有効か?)、スクリプトが依然としてルールと一致しているか、NGINXのブロックが適用されているか、コンソールサービスが指定されたバイナリを実行しているか、データベース用の空き容量があるか、検出器がログを読み取れるか、である。
何かが **CRITICAL** であれば非ゼロで終了するため、監視チェックとして機能する。`--quiet` は注意が必要なものだけを出力し、これがcron用の形式である:```
0 * * * * /usr/local/bin/stop-bots status --quiet
実行できなかったチェック — nft list には root が必要 — は UNKNOWN を報告し、決して OK にはなりません。確認できなかったからといってすべて問題ないと報告するヘルスチェックは、信じられてしまう分、何もないより悪いのです。
同じレポートはコンソールと TUI の両方の Dashboard にあり、レンダリングのたびではなく内部 cron によって毎時取得されます。大規模なルールセットに対する nft list は数メガバイトのテキストになるからです。
上記のすべてのファイアウォール判断は生成されるだけで、自動的に適用されることはありません。render-firewall(または Dashboard の f キー)はレビューして自分で適用するための iptables または nftables スクリプトを書き出し、現在接続中の SSH セッションをロックアウトしてしまうスクリプトの書き出しは拒否します。
それを代わりに適用できるものが 3 つあり、いずれもあなたが要求する必要があります。TUI のレンダーポップアップ(「書き込み後に適用」)またはその a キー、Web コンソールのファイアウォールパネル(「書き込み後に実行」)またはその「Apply everything」ボタン、そしてあなたが書いた crontab からの batch --apply です — Unattended, from cron を参照してください。これらのいずれも、何か自動的なものの副作用ではありません。内部 cron はスクリプトをレンダリングするだけで、決して実行しません。
同じことは NGINX 側にも当てはまります。設定を変更しても、書き込まれるであろう内容が変わるだけです。Site settings は適用するまで各サイトを STALE として表示します。
検出器をオフにしても、すでに追加されたブロックは削除されません — それらは自然に期限切れになります。「検出を停止する」と「検出されたものを元に戻す」は意図的に別物です。後者は Dynamic Protection 画面または remove-firewall-rule です。
ブロックとは独立した、単純なアクセスログの集計もあります。record-access-stats / list-access-stats は、成功した(エラーでない)リクエストに各ユーザーエージェントがどれだけ頻繁に現れるかを数えるので、誰がブロックされているかに加えて、誰が実際に訪問しているかを確認できます。
stop-bots batch は、TUI が手動で行うすべてを 1 回のパスで実行します。すべてのリストを更新し、ログをスキャンし、NGINX ブロッキングルールとファイアウォールスクリプトを書き出します。```
0 4 * * * root /usr/local/bin/stop-bots batch --apply --ssh-log /var/log/auth.log
*/10 * * * * root /usr/local/bin/stop-bots batch --apply --no-fetch --ssh-log /var/log/auth.log
すべてがうまくいったときは何も出力しないので、正常な夜間実行ではメールが届きません。失敗した
ステップは stderr に出力し、非ゼロの終了ステータスを設定します。これにより cron があなたに
それを知らせます。まず手動で `--verbose` を付けて一度実行してください — ステップごとに1行出力され、
実際に何をしているかを確認する最も簡単な方法です。
**`--apply` が実際に何かを強制する鍵です。** これがないと、`batch` は NGINX 設定
とファイアウォールスクリプトを書き出して停止します。設定はリロードするまで何もせず、スクリプトは実行されるまで何もしません。
これはこのプロジェクトのどこでもデフォルトであり、ここでもデフォルトのままです。
`batch` と長時間実行されるフロントエンドは安全に共存できます。TUI、Web UI、`batch` はすべて
同じデータベースの同じキーを通じて実行内容を記録するため、どれかが先にジョブに到達すればそれを実行し、他はそれが期限切れでないことを検知します — 二重の検出パスは発生せず、
Dashboard の「Scheduled tasks」パネルには、すべてが期限切れだと主張するのではなく、実際に何が起きたかが表示されます。すでに Web UI を動かしっぱなしにしているなら、夜間の `batch` エントリは必須ではなく念のための保険です。動かしていないなら、それが検出を最新に保つ唯一の手段です。
**`--apply` を付けると、SSH ロックアウトガードが拒否することがあります — そして拒否は何も適用されないことを意味します。**
ルールが現在接続中のクライアントをブロックする場合、*かつ* SSH ログがまったく読めなかった場合に拒否します。後者の場合、チェックを実行できないからです。対話型の
`render-firewall` は2番目のケースでメモを出力するだけです。人間がターミナルを見ているという理由からです。cron からは誰も見ていません。**`--ssh-log` を明示的に渡してください**: cron は root として実行されるため `/var/log/auth.log` は通常問題なく読めますが、journald のみのホストでは cron 下の `journalctl` が空を返すことがあり、まさにそれが拒否するケースです。`--force` は本気ならガードを上書きします。
1つのステップが失敗しても他のステップは決して停止せず、NGINX とファイアウォールの半分は独立しています —
NGINX のリロードが失敗してもファイアウォールは適用されたままで、その逆も同様です。
`batch` は各ステップを TUI の内部 cron が使用するのと同じスケジュールに対して記録するため、両者は
すでに実行された内容について一致し、両方が実行することを避けます。また Dashboard の「Scheduled
tasks」パネルには、実際の cron が何をしたかが表示されます。
# Web UI
`stop-bots web` は同じ5つの画面をブラウザで提供します。```
stop-bots web
127.0.0.1:8787 にバインドされ、そのマシンからのみ到達可能で、初回実行時に生成されたパスワードを一度だけ出力します。ラップトップから SSH トンネル経由でアクセスします:``` ssh -L 8787:127.0.0.1:8787 your-server
次に <http://127.0.0.1:8787/> を開きます。

コンソールはオペレーティングシステムのライト/ダーク設定に従い、ヘッダーにトグルがあります。上記のTUIスクリーンショットはダークテーマで、こちらはライトテーマです。TUIが使用するキーはここでも機能します: `1`–`4` で画面を切り替え、`/` で検索ボックスにフォーカスし、`?` でヘルプを開きます。

3つのホスト全体のアクションがヘッダーにあり、ブラウザではボタンとして、TUIでは単一キーとして利用できます:
- **すべて更新** (`u`) は、すべてのボットリスト、すべてのクローラーIP範囲、すべての*有効な*レピュテーションフィード、およびすべての*選択された*国をダウンロードします — `stop-bots batch` が取得するのと同じセットを、同じプランから取得します。1つのソースが失敗しても残りは停止せず、何かが適用するまで何も強制されません。
- **すべて適用** (`a`) は、NGINX設定を書き込んでリロードし、次にファイアウォールスクリプトを書き込んで実行します。2つのプレーンは独立しています: どちらかが失敗しても、もう一方は順番を得ます。なぜなら、半分適用されたホストは、NGINX構文エラーでファイアウォールも古いままになったホストよりもましだからです。
- **Webアクセス** (`w`) は、NGINXがコンソール自体を提供するように設定します — [NGINXの背後](#behind-nginx-a-subdomain-or-a-path-prefix)を参照してください。
## サービスとして (Debian)```
sudo stop-bots install web
/etc/systemd/system/stop-bots-web.service を書き込み、/var/lib/stop-bots(0700 — コンソールのパスワードハッシュを保持)と /etc/stop-bots を作成し、パスワードが存在しなければ生成し、ユニットを有効化して起動します。
--dry-run は計画全体を表示し、何も変更しません。 これはプロジェクト内でデーモンを起動する唯一のコマンドなので、まずそこから始めてください。--prefix <dir> は同じツリーを root なしで読める場所に書き込みます。ユニットが既に存在し、あなたが編集している場合、インストーラーはあなたの編集を置き換えるのではなく停止してその旨を伝えます。本当に置き換えるつもりなら --force を使ってください。
サービスは root として実行されます。コンソールが /etc/nginx を書き換え、ファイアウォールスクリプトを書き込み、nginx -t と systemctl reload nginx を実行するためです。機能セットを維持したまま非特権に分割する方法はありません。ユニットにはその要件を生き残るハードニングと、どのハードニングを省略したか、その理由を記したコメントが含まれています。
バインドアドレス、ホスト許可リスト、パスプレフィックスは意図的にユニットに含まれていません — 実行中のサーバーがデータベースから再読み込みするため、ExecStart に入れると信頼できる情報源が二つになってしまいます。これらを変更するには stop-bots web --save ... を使って再起動してください。
これが root として実行されると一つ変わることがあります。内部 cron の毎日の RenderFirewall ジョブが /etc/stop-bots/firewall.nft を書き込めるようになりますが、あなた自身としてコンソールを手動で実行していたときは書き込めませんでした。そのスクリプトを適用するものは何もありません — 実行するのは依然としてあなたの役目です。
チェックされるのは Debian のみです。テストされているのがそれだからです。ユニットは systemd を採用するあらゆるディストリビューションでほぼ確実に正しく動作しますが、想定している SSH ログのパスは Debian のものです。
ループバック以外にバインドするには、二つ目の意図的なフラグが必要です。このコンソールは実行されているホストのファイアウォールと NGINX 設定を書き換えられるためです:``` stop-bots web --bind 0.0.0.0:8787 --expose --allowed-hosts admin.example.com --save
`--allowed-hosts` は実運用上省略できません。リストにないホスト名を持つリクエストは拒否されます。これによりコンソールに対する DNS リバインディングが失敗し、名前でアクセスされる公開サーバーではその名前を明示する必要があるのです。
TLS 付きの NGINX の背後に配置してください — このツールが保護しているのと同じ NGINX です。そうする場合、プロキシが `X-Forwarded-For` を設定するなら、コンソールにそのヘッダーを信頼してよいと伝えてください。そうしないと、リクエストが実際にどこから来たのかを判別できません:```
stop-bots web --bind 127.0.0.1:8787 # and set web:trust_forwarded_for
TLS の背後では、web:secure_cookie も設定してください。これがないと、ブラウザは同じホストの http:// URL に対してもセッション Cookie を送信してしまいます。
web:trust_forwarded_for は見た目以上に重要です。これがないと、プロキシ背後のすべてのリクエストが 127.0.0.1 から到着したものとして扱われるため、コンソールはあるクライアントと別のクライアントを区別できません — つまり、大量のログイン試行があなたと同じスロットルバケットを共有することになり、自分自身のアドレスをブロックしてしまうのを防ぐガードも比較対象を持ちません。これを設定すれば、どちらもクライアント単位で機能します。
コンソールからこれを設定できますし、TUI からも可能です(Dashboard で w)。どちらも NGINX 設定を書き込み、パスプレフィックスを記録し、ホスト名を許可リストに追加します — この 3 つは一致していなければなりません。なぜなら、プレフィックスが欠けるとすべてのリンクが location ブロックから外れてしまい、ホスト名が欠けるとすべてのリクエストが 403 になるからです。どちらも設定が有効になる前に nginx -t で検証し、失敗した場合はロールバックし、検証が通って初めて新しいアドレスを記録します。
2 つのモードがあり、path がデフォルトであるのには理由があります。既存のサイトに location ブロックを追加するため、コンソールはそのサイトの証明書を継承します。サブドメインには独自の証明書が必要で、certbot --nginx -d <host> が実行されるまで、このコンソールのパスワードフォームとセッション Cookie は平文でネットワークを流れます。
このセクションの残りは同じことを手動で行う方法です。パネルを使う場合でも一度読む価値があります — 以下の末尾スラッシュの罠は、まさにそれを防ぐために存在する間違いです。
サブドメインの方がシンプルなデプロイであり、可能ならこちらを選ぶべきです:```nginx server { server_name stopbots.example.com; location / { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; } }
## 検出
### 検出ルール
- ルールは `rules/` ディレクトリに配置されています。
- 各ルールは、検出ロジックを定義した YAML ファイルです。
- ルールは、疑わしいアクティビティのパターンを識別するために、イベントデータと照合されます。
### 検出の仕組み
1. イベントが収集され、正規化されます。
2. 正規化されたイベントが、有効な検出ルールと照合されます。
3. 一致したルールは、設定された重要度に基づいてアラートを生成します。
4. アラートは、設定された出力先に送信されます。
### ルールの構造
```yaml
title: Suspicious Process Execution
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects suspicious process execution patterns
author: Security Team
date: 2024/01/01
level: high
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith:
- '\suspicious.exe'
- '\malicious.exe'
condition: selection
falsepositives:
- Legitimate administrative tools
tags:
- attack.execution
- attack.t1059
rules/ ディレクトリ内でカテゴリ別に整理されています。id フィールドが必要です。status フィールドを使用して、experimental、testing、stable としてマークできます。level フィールドを使用して、重要度別に分類されます。| レベル | 説明 |
|---|---|
| critical | 即時の対応が必要 |
| high | 早急な調査が必要 |
| medium | 調査が必要 |
| low | 情報提供目的 |
| informational | 参考情報 |
falsepositives フィールドを使用して文書化する必要があります。**パスプレフィックスも同様に機能します**が、コンソールにそれを伝える必要があります — すべてのリンク、フォームアクション、リダイレクト、Cookieパスをプレフィックス込みで生成する必要があり、推測することはできません:```
stop-bots web --base-path /stop-bots --allowed-hosts example.com --save
rules/ ディレクトリに YAML ファイルとして保存されます。detection ブロックを含みます。severity、tags、metadata などのメタデータを含むことができます。detection ブロックは、selection と condition のキーをサポートします。selection は、マッチさせるフィールドと値を定義します。condition は、selection をどのように組み合わせるかを定義します(例: and、or、not)。detection:
selection:
EventID: 4624
LogonType: 3
condition: selection
contains、startswith、endswith、re があります。|)を使用して適用されます。detection:
selection:
CommandLine|contains: 'powershell'
Image|endswith: '\cmd.exe'
condition: selection
and、or、not があります。detection:
selection1:
EventID: 1
selection2:
EventID: 2
condition: selection1 or selection2
| 演算子と count() 関数を使用して定義されます。detection:
selection:
EventID: 4625
condition: selection | count() by SourceIp > 10
threshold キーを使用して定義されます。detection:
selection:
EventID: 4625
condition: selection
threshold:
count: 10
timeframe: 5m
correlation キーを使用して定義されます。correlation:
- name: Multiple Failed Logons Followed by Success
rules:
- failed_logon
- successful_logon
timeframe: 10m
condition: failed_logon and successful_logon
filter キーを使用して定義されます。detection:
selection:
EventID: 4624
filter:
User: 'SYSTEM'
condition: selection and not filter
suppression キーを使用して定義されます。suppression:
- name: Suppress Duplicate Alerts
field: SourceIp
timeframe: 1h
alert キーを使用して定義されます。alert:
- name: Suspicious Logon
severity: high
message: 'Suspicious logon detected from {SourceIp}'
``````nginx
location /stop-bots/ {
proxy_pass http://127.0.0.1:8787; # NO trailing slash
proxy_set_header Host $host;
}
proxy_pass の末尾スラッシュは重要であり、その欠如が仕組みのすべてです。
これがないと、NGINX はフルパスをそのまま通し、stop-bots は
/stop-bots/whatever を見ることになり、それが現在提供・生成されているものです。末尾に
スラッシュがあると、NGINX はプレフィックスを除去します — そしてブラウザはページ内のリンクを
ドメインルートに対して解決し、location ブロックの外に着地し、すべてが 404 になります。サーバー側で
どれだけ注意を払ってもこれを修正することはできないため、プレフィックスはプロキシを通過して生き残る必要があります。
これを外部から強制するものは何もありませんが、失敗は微妙ではなく明白です。プレフィックスが 設定されている場合、プレフィックスのないリクエストは半分だけ動作するページではなく、単なる 404 になります。
2 つのことが意図的に欠けており、Help 画面にはその理由とともに記載されています:
stop-bots web --set-password を使用してください。また、接続元のアドレスをブロックすることも拒否します。それは元に戻すために使用する コンソールを奪ってしまうからです。
以前は 3 つでした。 ファイアウォールスクリプトの適用が 3 つ目でした。それを実行することが
ホストをネットワークから切断しうる唯一の操作であるという理由からです。これは現在利用可能です — ダッシュボードの
「Apply everything」(TUI では a)、またはファイアウォールパネルの「run it after
writing」ボックス — cron から安全にするガードがボタンからも安全にするからです:
ルールは現在 SSH でログインしているクライアントに対して、スクリプト自体が評価する順序でチェックされ、
そのうちの 1 つをブロックするルールは警告ではなく拒否となります。コンソールを --no-apply で
起動すると、以前の書き込み専用の動作に戻ります。
ログイン試行はスロットリングされます。パスワードが推測可能だからではなく — それは生成された 144 ビットです — 1 つの検証が Argon2id を実行するため、認証されていない呼び出し元が投稿できる限り 速くそれを駆動できるようにすることは、このツールが保護することになっているホストに対する サービス拒否攻撃になるからです。10 回の誤った試行は無料です。それを超えるとクライアントは 指数関数的にバックオフし、グローバルキャップが試行の送信元アドレスの数に関係なく CPU を制限します。
NGINX が Docker 内にあり、その設定がバインドマウント上にある場合、systemctl reload nginx は
何もリロードしません。代わりに 2 つのコマンドをコンテナに向けてください — これは CLI と
TUI にも当てはまります:```
stop-bots set-nginx-commands
--test "docker exec web nginx -t"
--reload "docker exec web nginx -s reload"
コマンドは単語に分割され、直接実行されます。シェルを経由することはないため、`;`、
`|`、`$VAR` は構文ではなく通常の文字として扱われます。
# コントリビューション
コードの構成、テスト方法、および準拠すべきコーディングルールについては
[CONTRIBUTING.md](https://github.com/ivankovic/stop-bots/blob/main/CONTRIBUTING.md) を参照してください。リリースプロセスについては
[RELEASING.md](https://github.com/ivankovic/stop-bots/blob/main/RELEASING.md) を参照してください。
# 連絡先
[[email protected]](mailto:[email protected]) までご連絡いただけます。
# ライセンス
Copyright (C) 2026 Marko Ivankovic
このプログラムはフリーソフトウェアです。Free Software Foundation が公開する
GNU Affero General Public License(ライセンスのバージョン3、または
それ以降のバージョン)の条件に従って、再配布および/または改変することができます。
ライセンスの全文については [LICENSE](https://github.com/ivankovic/stop-bots/blob/main/LICENSE) ファイルを
参照してください。
## AGPL ソフトウェアを使用できない場合
代替ライセンスは **利用できません**。
NOT BLOCKED/BLOCKED(赤で表示)のタグが付きます。Tab/Shift+Tab は Up/Down が作用する 2 つのパネルを切り替えます。f は共有フィルタ(all / not blocked only / blocked only)を循環します。Enter は選択された NOT BLOCKED 行をブロックし、すでに BLOCKED の場合はブロックを解除します。i は選択されたアドレスを検査します。どのレピュテーションフィードがそれを掲載しているか、公開されたクローラーの範囲内にあるかどうか(これが本物の Googlebot と、そう自称するだけのユーザーエージェントを区別するものです)、どの国に属するか、どのアカウントとしてログインを試みたか。すべてこのホストがすでにダウンロードしたリストから得られます — ここには逆引き DNS や whois ルックアップはありません。PTR レコードはアドレスを保持する誰かが書くものであり、権威があるように読める攻撃者提供のテキストになってしまうからです。| ルール | ボット以外に締め出すもの |
|---|
| HTTP/1.0 および HTTP/1.1 | HTTP/2 を話さないクローラーや API クライアント |
Accept ヘッダーなし | 一部の API クライアントは送信しない |
Accept-Language なし | プライバシーツールが削除する |
User-Agent が空/不在 | スクリプトやヘルスチェックがしばしば省略する |
Host が裸の IP | IP でサイトに到達できなくなる |
| TLS 1.0 / 1.1 | ごく古いクライアントのみ |
すべてに 2 つの安全策が適用され、あなたに任されず強制されます:
server ブロックにのみ書き込まれます。ブラウザは TLS なしで HTTP/2 を行わないため、プレーンな listen 80 ブロックではすべてのリクエストが HTTP/1.1 です — ブラウザが HTTPS へ向かう途中で行うリダイレクトも含めて。通常、ポート 80 とポート 443 のブロックは同じ server_name を共有するので、設定は両方に届きますが、これらのルールが付くのは TLS の方だけです。ヘッダー形状ルールはプレーン HTTP でも機能し、両方に書き込まれます。/.well-known/ は常に除外されます。ここは Let's Encrypt が HTTP-01 チャレンジを取得する場所で、HTTP/1.1 で Accept なし、しばしば User-Agent なしです — 除外がなければ、数週間後に証明書の更新が止まります。| オプション | 何のためか |
|---|
403 Forbidden(既定) | ブロックが意図的だったことを伝える。誤って捕まえた人間が対処できる唯一のもの |
404 Not Found | 何かがブロックされたこと自体を隠す |
410 Gone | 行儀の良いクローラーに URL を永久に削除するよう求める — 攻撃者ではなくクローラーを締め出す場合は 403 よりこちらを推奨 |
429 Too Many Requests | 礼儀正しいクライアントにバックオフして再試行するよう伝える |
418 I'm a teapot | RFC 2324 のジョーク。動作はしますが、IANA 登録されておらず、NGINX は空のボディで送信します |
444 close connection | まったく応答しない。最も低コストだが、サーバーダウンと区別がつかない |
Tarpit | 403 を返すがボディを毎秒 1 バイトで細々と流すので、クライアントは先に進む代わりに待たされる |