三層防御の最後の砦として Aikido Zen を本番投入。npm install + 1行設定で導入、Dry mode で影響ゼロ、Node 24 アップグレード必須、無料/有料境界、Simulate Attack Wave での検知デモまで実体験ベースでまとめた。
— aikido-community.jp を題材に、In-app Firewall の導入手順・ハマりどころ・無料/有料の境界を全部まとめた話
このサイト aikido-community.jp では、Aikido Security の以下のプロダクトを既に使ってる:
npm install 時のマルウェアパッケージ防御(48時間隔離)つまり、コード執筆〜パッケージインストール〜開発者端末までは守られてた状態。
でも、ランタイム(本番で実際に動いてるアプリ)への直接攻撃は別レイヤー。ここの最後の砦が Aikido Zen という In-app Firewall。
普通の WAF(AWS WAF, Cloudflare WAF など)はネットワーク境界で守る。Zen は アプリのプロセス内で動く OSS の WAF。だから:
今回これを aikido-community.jp の本番環境に投入してみた。
スクリーンショットがすべてを物語ってる:

これだけ揃って、追加コスト ¥0。
app.aikido.dev → Zen Firewall → Add App → 名前を aikido-community で作成。
すると Install Instructions 画面が出る:

ここで Zen の凄さが一目で分かる:
| 言語 | 対応フレームワーク |
|---|---|
| Node.js | Express, Fastify, Hono, Koa, NestJS, Next.js, Restify, Micro |
| Python | Django, Flask, FastAPI, Starlette, Quart, Gunicorn |
| PHP | Laravel, Symfony, Apache/Caddy/FrankenPHP |
| Java | Spring MVC/Webflux, Javalin |
| Go | Chi, Echo, Gin, net/http |
| .NET | ASP.NET Core/Framework |
| Ruby | Rails |
| Serverless | AWS Lambda, GCP Functions, Pub/Sub |
7言語 × 40+ フレームワーク。Zen が「自分のスタック対応してるかな?」のハードルを下げてる設計。
aikido-community.jp は Next.js 15 なので Next.js を選択。
公式ガイドは Next.js standalone モード前提だけど、このサイトは next start で動かす non-standalone 構成。なので公式そのままじゃなく、NODE_OPTIONS で preload する方式を採用した。
普通なら:
cd workspace
npm install --save-exact @aikidosec/firewall
でいいんだけど、Docker ベースで動かしてる構成だと host の node_modules が container 権限で残ってることが多くて permission エラーが出る。
ここで .dockerignore の有無を確認。ない場合は副産物として作っとくと良い:
# Build context がリポジトリ root で workspace/ を COPY する構成の場合
cat > .dockerignore << 'EOF'
workspace/node_modules
workspace/.next
workspace/.git
workspace/.env
EOF
⚠️ 注意:上記は Docker build context がリポジトリ root の構成(
docker-compose.ymlのcontext: .でCOPY workspace/ .する場合)が前提。もしworkspace/ディレクトリ内でdocker buildする構成なら、.dockerignoreはworkspace/直下に置いて、相対パスでこう書く:node_modules .next .git .env
workspace/.env を .dockerignore に入れるのは地味に重要。これしないと .env のシークレットが Docker イメージに焼き込まれる。
そして、host を汚さずに package.json + package-lock.json だけ更新したいので、ワンショットコンテナで実行:
docker run --rm \
-v "$PWD/workspace:/workspace" \
-w /workspace \
node:20-bookworm-slim \
npm install --save-exact --package-lock-only @aikidosec/firewall
sudo chown $(id -u):$(id -g) workspace/package.json workspace/package-lock.json
これで package.json に "@aikidosec/firewall": "1.8.27" が追加される。
CMD ["npm", "start"] の直前に:
ENV NODE_OPTIONS="-r @aikidosec/firewall/instrument"
CMD ["npm", "start"]
これで Next.js 起動前に Zen が preload される。
⚠️ 注意:既に
NODE_OPTIONSを別の用途で使ってる場合、上のように書くと既存値を上書きしてしまう。その場合は既存値を活かす形で追加するのが安全:ENV NODE_OPTIONS="${NODE_OPTIONS} -r @aikidosec/firewall/instrument"Dockerfile の変数展開は環境によって挙動が違うので、
docker compose build後にdocker exec community-app env | grep NODE_OPTIONSで値を確認しておくと確実。
.env にトークン追加ダッシュボードの App Settings → Token Settings から AIK_RUNTIME_... トークンをコピーして:
cat >> workspace/.env << 'EOF'
# Aikido Zen Runtime Firewall (dry mode for first 2 weeks)
AIKIDO_TOKEN=AIK_RUNTIME_xxxxxxxxxx
AIKIDO_BLOCK=false
EOF
AIKIDO_BLOCK=false がポイント(Dry mode=検知のみ、ブロックしない)。後述するけどここが Zen の最大の安全装置。
docker compose build app
docker compose up -d app
ビルドは2-3分。up -d app で 約10秒のダウンタイム で新コンテナに切り替わる。
Aikido ダッシュボードで App 作成時、Environment を Development / Staging / Production から選べる。

少なくとも今回確認した範囲では、Environment は主にダッシュボード上の分類・フィルタリング用途として使われており、Zen の基本的な防御機能そのものが変わるものではなかった。同じ Zen がインストールされ、同じ検知機能が動く。
ただし運用パターンとして公式が推奨してるのは:
| Environment | 用途 | モード |
|---|---|---|
| Staging | 本番投入前の検証 | Dry mode で2週間運用 |
| Production | 本番 | Block mode(または Dry mode から段階的移行) |
つまり「Staging で誤検知ゼロを確認 → Production に同じ設定で展開」が王道。
aikido-community.jp のような 個人〜小規模サイトで Staging 環境を持たない場合は、Production を一旦 Dry mode で運用することで Staging 環境と同等の安全な検証ができる。Aikido の設計上、Environment ラベルに依存した制約は無いので問題なし。
最初、ベースイメージが node:20-bookworm-slim のまま動かしたら、起動ログに衝撃の警告:

┌──AIKIDO────────────────────────────────────────────────────────────┐
│ │
│ Zen is NOT protecting your application. Your Node.js version │
│ does not support module.registerHooks. Upgrade Node.js and see │
│ https://github.com/AikidoSec/firewall-node/blob/main/docs/esm.md │
│ │
└────────────────────────────────────────────────────────────────────┘
つまり「インストールはしたけど守れてないよ」というオレンジバッジ状態。
Zen の /instrument エントリーポイントは Node.js の module.registerHooks API を使う。これは Node.js 公式ドキュメントでも v22.15.0 / v23.5.0 で追加されたと記載されてる新しい API。
理論上は Node 22.15+ なら動くはずだが、今回は Aikido 公式の警告メッセージにそのまま従い、執筆時点では安全側として Node 24 系へアップグレードした。
Dockerfile.app の1行を変えるだけ:
FROM node:24-bookworm-slim
リビルドして再起動。今度は警告枠が完全に消えた → Zen サイレント稼働中=成功。
このアップグレード自体、aikido-community.jp の Next.js 15 / Prisma 5 / React 18 構成では何も壊れなかった。最新スタックは Node 24 と相性良し。
小技:警告メッセージの存在自体が Zen の親切設計。古い Node で動かしてしまっても、動いてないことを明示してくれるから「動いてるつもり」状態を回避できる。
.dockerignore 不備(副産物発見)途中で気づいたんだけど、.dockerignore がプロジェクトに存在しなかった。
Dockerfile.app の流れは:
COPY workspace/package.json workspace/package-lock.json ./
RUN npm ci # ← コンテナで新規インストール
COPY workspace/ . # ← host の workspace 全コピー(node_modules も含む)
つまり .dockerignore なしだと:
npm ci で正しい依存をコンテナにインストールCOPY workspace/ . で host の node_modules(古い可能性)が上書きされる.env ファイルもイメージに焼き込まれる(シークレット漏洩リスク)Zen 導入の副産物として、.dockerignore を整備した。これだけで:
Zen 入れる作業がトリガーで、長年放置してた構造的問題が露見した。これも面白い。
ここが Zen の 設計思想の白眉。
普通の WAF や IPS は「入れる = いきなり本番ブロック」。誤検知で正規ユーザー弾いて炎上、というのが導入の最大リスク。
Zen は逆:
| モード | env var | 挙動 |
|---|---|---|
| Dry(検知のみ) | AIKIDO_BLOCK=false(デフォルト) | 攻撃を検知してログに残すだけ。リクエストは普通に通る |
| Block(本番) | AIKIDO_BLOCK=true | 検知したら 400 で実際に弾く |
公式は「2週間 Dry mode で運用してから Block に切り替えろ」と推奨してる。
これにより:
true にして再起動 → 本番ブロック開始本番 WAF をユーザー影響ゼロで導入できる、というのは結構ヤバい。
Zen 起動後、しばらくサイトに普通のアクセスがあると、Routes タブに自動的にエンドポイントが並ぶ:

アクセスされたパスが GET /, GET /<page>, GET /api/<endpoint> のように、HTTPメソッド + ルートの組み合わせで自動的にカタログ化される。すべて Detection Only バッジ付き=Dry mode で監視中。
これ、設定ファイルも何も書いてない。Zen が live traffic を観察して OpenAPI 仕様を自動生成してる。
エンプラ向けの API セキュリティ製品が結構な値段でやってる「API ディスカバリ」機能が、npm install + 1行設定で手に入る。Zen の強みのひとつ。
これがハイライト。Aikido ダッシュボードに **「Simulate Attack Wave」**機能がある。

URL https://aikido-community.jp を入れて Simulate Attack ボタン押すと、Aikido の EU インフラ(AWS Dublin)から実際の攻撃トラフィックが撃ち込まれる:
数秒後、Events タブを見ると:

⚠️ Detected Attack Wave from 52.50.198.227 🇮🇪 Medium 2s ago
⚠️ Detected Attack Wave from 52.51.98.186 🇮🇪 Medium 2s ago
ℹ️ Application Started Info 14m ago
ベルギーの Aikido 本社から、アイルランド経由で攻撃シミュレーションが来た(IP の 52.50.x / 52.51.x は AWS Dublin リージョン)。Zen がそれを正確に検知してダッシュボードに記録。
これが Dry mode の真価。本番に影響ゼロで、リアル攻撃に対する防御力を可視化できる。
「Docker ログを grep aikido しても何も出ないんだけど?」と思うかもしれない。
これは 仕様。Zen は本番運用を考えて、通常運転時は console に何も出さない設計:
理由:
つまり「Docker ログにあるべき場所にはない」のではなく「ダッシュボードにある」が正解。
.env に1行追加:
AIKIDO_DEBUG=true
これで起動時のロード状況、ハートビート送信、ルート検知などの詳細メッセージが stdout に出るようになる。トラブルシュート用に一時的に使うのが正解。
ここが多分一番気になる部分。整理する。
📅 本セクションの料金・上限・機能の対応関係は 2026年5月時点の Aikido Pricing ページを参照したもの。プランは将来変更される可能性があるため、本番導入前には必ず最新情報を確認すること。
ローカル防御は全部入り:
ダッシュボードに既に書いてある Fair Usage Policy がポイント:
"Don't worry about occasional spikes in usage - Aikido will never bill surcharges automatically. If you consistently exceed your plan's limits, we'll reach out to find the best solution together."
つまり:
なお、トラブルシュート時には AIKIDO_DEBUG=true を .env に追加することで、起動状況や検知モードなどの詳細を stdout で確認できる(あくまでデバッグ出力で、ダッシュボードの代替ログ基盤ではない点に注意)。
⚠️ ただし、プラン条件・上限・運用ポリシーは Aikido 側で変更される可能性があるため、本番利用前には最新の Pricing ページを必ず確認すること。本記事の料金・上限の数値は 2026年5月時点のもの。
ここがよく混同される:
| Free tier | 有料 | |
|---|---|---|
| Dry mode | ✅ 使える | ✅ 使える |
| Block mode | ✅ 使える | ✅ 使える |
つまり Free でも本番ブロック(Block mode)が動く。これが Zen の核心。
aikido-community.jp の場合、GA4 で月アクティブ 255、月リクエスト 3〜5万。Free 枠 250K の 1/5 以下。この規模なら、当面は Free 枠内で本番 WAF が動く規模感。
| 項目 | 値 |
|---|---|
| 所要時間 | 約2時間(環境調査含む、ガチ作業30分) |
| ダウンタイム | 合計20秒(build後の up を2回 = 10秒×2) |
| 追加コスト | ¥0(Free tier、月250K上限の中) |
| 効果 | SQLi / SSRF / Path traversal / Command Injection の本番防御 + 自動 API ディスカバリ |
| 副産物 | .dockerignore 整備でシークレット漏洩リスク解消 + Node 24 へモダン化 |
つまり:
「無料で本番 WAF を入れた」+「副産物で設計改善」+「Dry mode で誰も傷つけない」
これが Aikido Zen の体験。
公式推奨通り、aikido-community.jp は今後2週間 Dry mode で運用する:
POST /api/articles(Bearer 認証の内部投稿API)が誤って弾かれないか観察2週間後(2026-06-04頃)、.env で AIKIDO_BLOCK=true に変更して再起動。「丸裸 → 監視 → 守備」シリーズの第3弾として、Block mode 切り替え+実攻撃ブロック実演の記事を書く予定。
この記事は aikido-community.jp への Aikido Zen 導入を題材にした実体験記です。コード片・コマンドはすべて実際に実行・検証したものです。
Aikido Community Japan
公開日: 2026/5/21
最終更新: 2026/5/21
セキュリティの最新情報をお届けします。