記事一覧に戻る
Aikido2026年5月21日32分で読めます

無料でOSS WAF「Aikido Zen」をNext.js本番サイトに入れてみた

三層防御の最後の砦として Aikido Zen を本番投入。npm install + 1行設定で導入、Dry mode で影響ゼロ、Node 24 アップグレード必須、無料/有料境界、Simulate Attack Wave での検知デモまで実体験ベースでまとめた。

無料でOSS WAF「Aikido Zen」をNext.js本番サイトに入れてみた

— aikido-community.jp を題材に、In-app Firewall の導入手順・ハマりどころ・無料/有料の境界を全部まとめた話


なぜ Zen か:三層防御の最後の砦

このサイト aikido-community.jp では、Aikido Security の以下のプロダクトを既に使ってる:

  • Aikido Safe Chain — npm install 時のマルウェアパッケージ防御(48時間隔離)
  • Aikido Endpoint Protection — 開発者端末の防御

つまり、コード執筆〜パッケージインストール〜開発者端末までは守られてた状態。

でも、ランタイム(本番で実際に動いてるアプリ)への直接攻撃は別レイヤー。ここの最後の砦が Aikido Zen という In-app Firewall。

普通の WAF(AWS WAF, Cloudflare WAF など)はネットワーク境界で守る。Zen は アプリのプロセス内で動く OSS の WAF。だから:

  • ✅ SSL を Aikido に渡す必要なし(鍵はあなたのまま)
  • ✅ アプリ内部のコンテキストを見て攻撃判定(誤検知少ない)
  • ✅ 月 250K リクエストまで完全無料、その後も Fair Usage Policy(自動課金なし)

今回これを aikido-community.jp の本番環境に投入してみた。


結論から:ダウンタイム 10秒、コスト ¥0 で導入完了

スクリーンショットがすべてを物語ってる:

Apps list with Detection Only badge

  • Production / Node.js / 1 instance = 稼働中
  • Detection Only バッジ = Dry mode で安全に運用中
  • Version 1.8.27 = インストール成功

これだけ揃って、追加コスト ¥0。


1. Aikido ダッシュボードで Zen アプリ作成

app.aikido.dev → Zen Firewall → Add App → 名前を aikido-community で作成。

すると Install Instructions 画面が出る:

Install Instructions - 40+ frameworks

ここで Zen の凄さが一目で分かる:

言語対応フレームワーク
Node.jsExpress, Fastify, Hono, Koa, NestJS, Next.js, Restify, Micro
PythonDjango, Flask, FastAPI, Starlette, Quart, Gunicorn
PHPLaravel, Symfony, Apache/Caddy/FrankenPHP
JavaSpring MVC/Webflux, Javalin
GoChi, Echo, Gin, net/http
.NETASP.NET Core/Framework
RubyRails
ServerlessAWS Lambda, GCP Functions, Pub/Sub

7言語 × 40+ フレームワーク。Zen が「自分のスタック対応してるかな?」のハードルを下げてる設計。

aikido-community.jp は Next.js 15 なので Next.js を選択。


2. インストール手順(Next.js 15 + Docker Compose)

公式ガイドは Next.js standalone モード前提だけど、このサイトは next start で動かす non-standalone 構成。なので公式そのままじゃなく、NODE_OPTIONS で preload する方式を採用した。

ステップ1: パッケージインストール

普通なら:

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" が追加される。

ステップ2: Dockerfile.app に NODE_OPTIONS 一行追加

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 で値を確認しておくと確実。

ステップ3: .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 の最大の安全装置。

ステップ4: ビルド&再起動

docker compose build app
docker compose up -d app

ビルドは2-3分。up -d app で 約10秒のダウンタイム で新コンテナに切り替わる。


Environment(Development / Staging / Production)の選び方

Aikido ダッシュボードで App 作成時、Environment を Development / Staging / Production から選べる。

Environment dropdown

少なくとも今回確認した範囲では、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 ラベルに依存した制約は無いので問題なし。


3. ハマったポイント①:Node 20 では「丸裸警告」

最初、ベースイメージが node:20-bookworm-slim のまま動かしたら、起動ログに衝撃の警告:

Zen is NOT protecting warning

┌──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 系へアップグレードした。

解決:Node 20 → 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 で動かしてしまっても、動いてないことを明示してくれるから「動いてるつもり」状態を回避できる。


4. ハマったポイント②:.dockerignore 不備(副産物発見)

途中で気づいたんだけど、.dockerignore がプロジェクトに存在しなかった。

Dockerfile.app の流れは:

COPY workspace/package.json workspace/package-lock.json ./
RUN npm ci                  # ← コンテナで新規インストール
COPY workspace/ .           # ← host の workspace 全コピー(node_modules も含む)

つまり .dockerignore なしだと:

  1. npm ci で正しい依存をコンテナにインストール
  2. その後 COPY workspace/ . で host の node_modules(古い可能性)が上書きされる
  3. .env ファイルもイメージに焼き込まれる(シークレット漏洩リスク)

Zen 導入の副産物として、.dockerignore を整備した。これだけで:

  • ビルドが再現可能になる
  • イメージサイズが小さくなる
  • シークレットがイメージから消える

Zen 入れる作業がトリガーで、長年放置してた構造的問題が露見した。これも面白い。


5. Dry mode で本番投入 = ユーザー影響ゼロ

ここが Zen の 設計思想の白眉。

普通の WAF や IPS は「入れる = いきなり本番ブロック」。誤検知で正規ユーザー弾いて炎上、というのが導入の最大リスク。

Zen は逆:

モードenv var挙動
Dry(検知のみ)AIKIDO_BLOCK=false(デフォルト)攻撃を検知してログに残すだけ。リクエストは普通に通る
Block(本番)AIKIDO_BLOCK=true検知したら 400 で実際に弾く

公式は「2週間 Dry mode で運用してから Block に切り替えろ」と推奨してる。

これにより:

  1. Dry mode で本番投入(ユーザー影響ゼロ)
  2. ダッシュボードで「もし Block だったら誰が弾かれてたか」を観察
  3. 誤検知ゼロを確認 → 環境変数1個 true にして再起動 → 本番ブロック開始

本番 WAF をユーザー影響ゼロで導入できる、というのは結構ヤバい。


6. ダッシュボードで自動 API ディスカバリ

Zen 起動後、しばらくサイトに普通のアクセスがあると、Routes タブに自動的にエンドポイントが並ぶ:

Routes auto-discovered

アクセスされたパスが GET /, GET /<page>, GET /api/<endpoint> のように、HTTPメソッド + ルートの組み合わせで自動的にカタログ化される。すべて Detection Only バッジ付き=Dry mode で監視中。

これ、設定ファイルも何も書いてない。Zen が live traffic を観察して OpenAPI 仕様を自動生成してる。

エンプラ向けの API セキュリティ製品が結構な値段でやってる「API ディスカバリ」機能が、npm install + 1行設定で手に入る。Zen の強みのひとつ。


7. Simulate Attack Wave でリアル検知デモ

これがハイライト。Aikido ダッシュボードに **「Simulate Attack Wave」**機能がある。

Simulate Attack Wave modal

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

  • SQL Injection 系
  • Path Traversal 系
  • Command Injection 系
  • 怪しい User-Agent

数秒後、Events タブを見ると:

Events with Detected Attack Wave

⚠️ 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 の真価。本番に影響ゼロで、リアル攻撃に対する防御力を可視化できる。


8. ログはどこに出るのか?— Zen のサイレント設計

「Docker ログを grep aikido しても何も出ないんだけど?」と思うかもしれない。

これは 仕様。Zen は本番運用を考えて、通常運転時は console に何も出さない設計:

  • 攻撃検知ログ → Aikido ダッシュボード(集約・分析)
  • アプリケーションログ → Docker stdout(業務ログのみ)

理由:

  1. 大量検知でも stdout を汚さない
  2. 業務ログとセキュリティログを分離
  3. 複数インスタンス横断でダッシュボード集約

つまり「Docker ログにあるべき場所にはない」のではなく「ダッシュボードにある」が正解。

デバッグ用に詳細ログを stdout に出したい場合

.env に1行追加:

AIKIDO_DEBUG=true

これで起動時のロード状況、ハートビート送信、ルート検知などの詳細メッセージが stdout に出るようになる。トラブルシュート用に一時的に使うのが正解。


9. 無料/有料の境界 ― 何がタダで何が課金か

ここが多分一番気になる部分。整理する。

📅 本セクションの料金・上限・機能の対応関係は 2026年5月時点の Aikido Pricing ページを参照したもの。プランは将来変更される可能性があるため、本番導入前には必ず最新情報を確認すること。

🎁 無料 (Free / Developer プラン) で使える Zen 機能

ローカル防御は全部入り:

  • ✅ SQL / NoSQL Injection ブロック
  • ✅ SSRF ブロック
  • ✅ Path Traversal ブロック
  • ✅ Shell / Command Injection ブロック
  • ✅ レート制限(ルート単位、IP/User/グループ)
  • ✅ ユーザー/IPブロック
  • ✅ 自動 API ディスカバリ
  • ✅ アウトバウンド通信監視
  • ✅ Node.js / Python / PHP / .NET / Java / Ruby / Go 全言語対応
  • ✅ Dry / Block 両モード
  • ✅ ダッシュボード可視化(月 250K リクエストまで)

💰 有料 (Basic 以上) で追加されるもの

  • 月リクエスト上限が 10M / 20M / 50M に拡張
  • Bot Protection(CrowdSec 連携で Tor / スクレイパー / 悪性IP の自動ブロック)
  • AI Monitoring(LLM 利用追跡、トークンコスト可視化)
  • Device Protection
  • Custom Rules
  • カントリーブロック等の高度トラフィック制御

250K リクエストを超えるとどうなる?

ダッシュボードに既に書いてある 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 から連絡が来る(Fair Usage ベースの相談運用) Zen の設計思想として、セキュリティチェックは各アプリ内ローカルで完結する(クラウド送信は集約とテレメトリ目的)。

なお、トラブルシュート時には AIKIDO_DEBUG=true を .env に追加することで、起動状況や検知モードなどの詳細を stdout で確認できる(あくまでデバッグ出力で、ダッシュボードの代替ログ基盤ではない点に注意)。

⚠️ ただし、プラン条件・上限・運用ポリシーは Aikido 側で変更される可能性があるため、本番利用前には最新の Pricing ページを必ず確認すること。本記事の料金・上限の数値は 2026年5月時点のもの。

Mode と Tier は完全に独立した軸

ここがよく混同される:

Free tier有料
Dry mode✅ 使える✅ 使える
Block mode✅ 使える✅ 使える

つまり Free でも本番ブロック(Block mode)が動く。これが Zen の核心。

aikido-community.jp の場合、GA4 で月アクティブ 255、月リクエスト 3〜5万。Free 枠 250K の 1/5 以下。この規模なら、当面は Free 枠内で本番 WAF が動く規模感。


10. まとめ ― 何が手に入ったか

項目値
所要時間約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 の体験。


11. 次回予告:2週間後に Block mode 切り替え

公式推奨通り、aikido-community.jp は今後2週間 Dry mode で運用する:

  • 誤検知(false positive)が出ないか確認
  • 既存の POST /api/articles(Bearer 認証の内部投稿API)が誤って弾かれないか観察
  • 攻撃ログの傾向を蓄積

2週間後(2026-06-04頃)、.env で AIKIDO_BLOCK=true に変更して再起動。「丸裸 → 監視 → 守備」シリーズの第3弾として、Block mode 切り替え+実攻撃ブロック実演の記事を書く予定。


参考リンク


この記事は aikido-community.jp への Aikido Zen 導入を題材にした実体験記です。コード片・コマンドはすべて実際に実行・検証したものです。

A

Aikido Community Japan

公開日: 2026/5/21

最終更新: 2026/5/21

シェア:

ニュースを購読

セキュリティの最新情報をお届けします。

Aikido Community Japan からのお知らせの受信に同意します。詳しくはプライバシーポリシーをご確認ください。