install
unmask の置き方 (nginx module か gateway container) と OS を選ぶと、具体的な yum / apt / apk / docker compose コマンドと設定スニペットが表示されます。
0 unmask をどこに置くか
カードをクリックすると下の手順が切り替わります。
nginx native module
いまの nginx に dynamic module を組み込む構成。判定が nginx プロセス内で完結するため最速。
- ✓ 一度認証を通った訪問者は素の nginx と同等の速度 (短期間だけ有効な通過証 cookie をサーバー側で検証するだけ)
- ✓ 1 リクエストあたり ~0.05 ms (同じプロセス内で cookie を検証。サブリクエストなし / IPC なし)
- ✓ rate_limit / honeypot パスも nginx 上で完結
- △ nginx 専用 (それ以外は gateway container へ)
gateway container
module 組み込み済み nginx + unmask のコンテナ一式を、既存の HTTP server の前段に置く構成。後ろ側には一切手を入れない。
- ✓ 任意の HTTP server の前段に置ける (Apache、Caddy、Node、Rails、IIS、別の nginx)
- ✓ 全訪問者の TLS 指紋 (JA4) が取れる (コンテナが TLS を終端し、中で native module が動く)
- ✓ HTTPS はお任せ (Let's Encrypt で自動取得、または購入した証明書を管理画面に貼り付け)
- △ Docker が必要 (コンテナ 1 つ: module 入り nginx と daemon。
docker runでも compose の 1 サービスでも)
Apache などで Docker を使えない場合は、nginx を前に置いて nginx native module の手順で導入してください。
1 環境選択
上の OS リストは CI で 検証済みです。派生 distro (openSUSE / Mint / Pop!_OS 等) の互換情報や全体の対応マトリクスは 対応 distro 一覧 を参照してください。
2 unmask 本体をインストール ?リポジトリ方式: まず unmask-release を 1 回インストールしてリポジトリ設定と GPG 公開鍵を入れる。以降は dnf install unmask / apt install unmask で本体をインストール / アップグレードできる。署名検証はパッケージマネージャーが自動で行う。
インストール直後: unmask の daemon が自動で起動し (127.0.0.1:9477)、パッケージがセットアップトークンを表示して /var/lib/unmask/.setup-token に保存する。セットアップウィザードは section 4 で起動する。
アップグレード: sudo dnf upgrade 'unmask*' (deb は sudo apt upgrade、Alpine は sudo apk upgrade)。daemon の再起動はパッケージが行う。
sudo dnf install -y https://unmask.sh/dl/rpm/unmask-release-latest.noarch.rpm sudo dnf install -y unmask
3 unmask-plugin-nginx (native plugin) をインストール ?前提: nginx は事前にインストールしておきます (section 4 で unmask-web-nginx を入れる際に、依存解決で自動的にインストールもされます)。
postinstall: load_module を distro 慣例のディレクトリ (/usr/share/nginx/modules/ または /etc/nginx/modules-enabled/) に自動で配置します。 15 種類の nginx バージョン × OpenSSL 1.0 / 1.1 / 3 の全 ABI 分の .so を同梱 (1.10 ~ 1.30 系 / glibc) しているため、ホストの nginx のパッチレベルに合ったモジュールを自動で選びます。手動での編集は不要です。
nginx をアップグレードした場合: ABI 不一致で nginx -t がエラーになるので、sudo dnf upgrade unmask-plugin-nginx (deb は sudo apt install --only-upgrade unmask-plugin-nginx) で同じバージョンに揃えます。
sudo dnf install -y unmask-plugin-nginx--with-compat 無しでビルドされているため、module を読み込めません。この手順の前に、同じ AppStream の新しい stream に切り替えてください (インストール済みの nginx 1.14 もこれで更新されます)。9 と 10 はそのままで構いません。
sudo dnf module reset -y nginx sudo dnf module install -y nginx:1.24
4 unmask-web-nginx (Web 連携スニペット) をインストール ?postinstall が upstream のシンボリックリンクと下記の include を配置し、nginx -t で検証してからセットアップウィザードの URL を表示します。動作中の nginx には触りません — ウィザードの URL は、この後ご自身で行う再起動のあとに開けるようになります。
JA4 maps の include は完全に自動: postinstall が /etc/nginx/conf.d/00-unmask.conf から /var/lib/unmask/nginx/http.inc へのシンボリックリンクを配置します。どの distro でも標準で書かれている include /etc/nginx/conf.d/*.conf; (Alpine は /etc/nginx/http.d/) によって自動で読み込まれるため、http {} block の編集は不要です。
sudo dnf install -y unmask-web-nginx
/unmask/admin/setup/ を開く。
- [Recommended] 既存 vhost に 1 行追加 — 普段使っているドメインでセットアップウィザードを開く。対象の
server { }block 内に 青色の 1 行を追加:server { listen 443 ssl http2; server_name example.com; ssl_certificate ...; include /var/lib/unmask/nginx/server.inc; # ← unmask 本体 (challenge 配信・BAN・管理画面) root /var/www/example; }→sudo nginx -t && sudo systemctl restart nginx(RHEL/CentOS 6 はsudo service nginx restart、Alpine はsudo rc-service nginx restart。インストール直後のモジュール読み込みは reload ではなく restart) →https://<your-domain>/unmask/admin/setup/を開く。 - [Direct port] — 同じホスト内なら何も変更不要: そのまま
http://127.0.0.1:9477/unmask/admin/setup/にアクセスできる。別のホストから見たい場合は次の SSH tunnel を使う。 - [SSH tunnel] — ファイアウォールを変更せずに使える万能なフォールバック。
ssh -L 9477:127.0.0.1:9477 your-server -N &
→http://localhost:9477/unmask/admin/setup/を開く。
setup URL で challenge が出ることがありますが、この時点で保護されているのは管理画面 (/unmask/admin/) だけです。サイト本体は、次の手順で protect.inc を追加するまで無保護のままです。
ウィザードは セットアップトークン (unmask パッケージのインストール時に表示。または sudo cat /var/lib/unmask/.setup-token) → データベース (既定の SQLite で十分) → 管理者アカウント作成 → 確認 の順です。完了すると admin top へ遷移し、残りの設定は /unmask/admin/settings/ から行えます。
5 保護したい server {} で challenge を発火 (ON/OFF スイッチ) ?このハイライト行が unmask の ON/OFF スイッチです。追加すれば bot 対策が発火し、外せば ブロック / challenge は即停止して、利用者の通信に影響しなくなります。アクセスログ経由の統計はどちらの状態でも流れ続けるので、「監視 (統計のみ) → 試運転 (1 つの location で発火) → 本番 (全域で発火)」と段階的に進める運用が安全です。
書くのは 2 行だけ: server { } 直下に include /var/lib/unmask/nginx/server.inc;、保護したい場所に include /var/lib/unmask/nginx/protect.inc;。それ以外 (rate-limit zone / challenge 振り分け / JA4 maps) は admin が /var/lib/unmask/nginx/ に生成し、section 4 の conf.d のシンボリックリンク経由で自動的に読み込まれます。
rate / burst / 適用パスは 設定 → rate-limit タブで設定します。admin UI を特定のドメインに限定したい場合は 設定 → ネットワーク → admin_allowed_hosts で設定します。
対象の server {} block (既存 nginx vhost の .conf) に 青色 (ハイライト) の行を追加します。ハイライト以外はあなたの既存の設定です (例は reverse proxy。静的配信 (root + try_files) でも追加する行は同じ)。
既存の location を編集せず、この block を 1 つ追加するだけです。
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate ...;
include /var/lib/unmask/nginx/server.inc; # ← unmask 本体 (challenge 配信・BAN・管理画面)
include /var/lib/unmask/nginx/protect.inc; # ← location 外 (全 location 対象)
location / { # ← user の既存 location は無編集
proxy_pass http://your-upstream;
}
}
編集が終わったら設定を反映します。plugin のインストール後にまだ nginx を restart していない場合は restart します (reload では新しいモジュールを読み込めません)。以降の設定変更は reload で十分です:
sudo nginx -t && sudo systemctl restart nginx
0.1.53 からは、設定を保存した後の reload を自動にもできます: sudo systemctl enable --now unmask-nginx-reload.timer。この timer は unmask-web-nginx に無効のまま同梱されていて、5 分ごとに、書き出しで設定が変わっていて nginx -t が通るときだけ nginx を reload します (10 分に 1 回まで。restart はせず、OS の更新で差し替わったライブラリを nginx がまだ掴んでいるときは reload せずに「restart が要る」と journal に書きます)。systemd の無い環境では /usr/share/unmask/nginx-reload-if-stale.sh を cron で実行してください。
1 compose ファイルを取得 ?ファイル 1 つでコンテナ 1 つ: unmask が gateway です — 公式 nginx イメージ + unmask module に daemon (管理画面、challenge 検証、BAN リスト、統計) を同梱し、1 つの entrypoint が両方を見守ります。イメージは unmask.sh/ から取得され(パッケージと同じ配信元。ghcr.io/unmask-sh/ にもミラー)、例がそのまま動くように仮の app も入っています。
volume は残す: /etc/unmask には描画済みの nginx 設定と通過証 cookie の署名鍵、/var/lib/unmask にはデータベース、/var/cache/nginx/unmask-acme には Let's Encrypt の状態が入ります。アップグレードをまたいで保持してください。
アップグレード: docker compose pull && docker compose up -d。0.1.47 以前 (コンテナ 2 つ) からの移行には追加の手順があり、コンテナ (docs) のイメージタグの節にまとめています。
Docker Engine + Compose v2 の入った Linux ならどの distro でも動きます (macOS / Windows の Docker Desktop も)。OS / distro の選択は不要です。
mkdir unmask && cd unmask curl -fsSLO https://unmask.sh/dl/docker/docker-compose.yml
2 起動してトークンを拾う ?初回起動は自己署名証明書で :443 が上がります (ブラウザは一度警告します)。転送先・ホスト名・本番の証明書はすべて次のステップの管理画面 (設定 → Gateway) で設定するので、compose ファイルを書き換える必要はありません。
gateway は通過したリクエストに Host、X-Real-IP、X-Forwarded-For、X-Forwarded-Proto を付けて転送し、WebSocket の upgrade も通し、body サイズの上限は設けません。
Listen 8080、nginx は listen 8080; に変えて reload (コンテナから届くアドレスに bind する必要があるので 127.0.0.1 は不可。8080 は firewall で外から閉じる)。ここから step 3 で自分のサーバーを転送先に設定するまでの数分間、challenge を通過した訪問者にはサイトの代わりに例の仮アプリ (リクエストをそのまま表示するだけ) が見えます。二段 proxy の詳細は コンテナ (docs)。Nginx Proxy Manager・Traefik・Caddy・Cloudflare Tunnel を既に使っている場合の置き方は FAQ にあります。まっさらなホストならこの段落は読み飛ばして構いません。
docker-compose.yml はそのままで構いません。起動して、ログからセットアップトークンを拾います:
docker compose up -d docker compose logs unmask | grep "setup token"
3 ウィザードを済ませ、Gateway を設定 ?管理画面もサイトと同じ保護の内側にあるので、セットアップ URL を開くとまず短い security check が表示され、通過するとウィザードが続きます。この時点で challenge されるのは /unmask/admin/ だけです。例の compose ファイルは仮アプリを転送先にして起動し、自分のサーバーを設定すればサイトはこれまでどおり配信されます (転送先をまったく設定せずに起動した場合、たとえば素の docker run では、gateway はその旨の案内ページを返します)。
証明書: 設定 → Gateway に、:443 がいま配信している証明書 (発行者、有効期限、名前の一致) が表示されます。Let's Encrypt を選べば連絡先メールを入れるだけ (ホスト名がこのホストに解決し、:80 に到達できること。アカウントは初回取得時に自動作成)。購入した証明書は同じタブに貼り付けます (証明書、チェーン、鍵 — 鍵は他から読めない権限で保存され、二度と表示されません)。更新は新しい組を貼り直すだけです。
https://<このホスト>/unmask/admin/setup/ を開き (自己署名証明書の警告を一度受け入れる)、ウィザードを済ませます — セットアップトークン (上の docker compose logs unmask で表示。log に出るのは初回起動時だけなので、セットアップが終わるまでは docker compose exec unmask cat /var/lib/unmask/.setup-token でいつでも表示できます) → データベース (既定の SQLite で十分) → 管理者アカウント作成 → 確認 の順です。続いて:
設定 → Gateway — 転送先 (upstream) に自分のサーバーを入れます。入力欄の下に 3 つの例 (同じホストのサーバー / 別ホスト / 同じ compose 内のコンテナ) が表示されます。同じホストのサーバーは step 2 で 8080 へ移したもの (http://host.docker.internal:8080) を指します。応答するホスト名 は「すべて」のままでも、訪問者が使うホスト名だけに絞っても OK。証明書 は自己署名から Let's Encrypt か貼り付けに切り替えます。
6 動作確認 + トラブルシュート
# 素の curl — browser の TLS でも JS でもないので challenge が返るはず curl -sk https://example.com/ | grep -oE 'unmask|challenge' | head -1 # → "unmask" が出れば challenge HTML が配信されてる
統計 タブ → 「チャレンジ ファネル」カード。serve / load / pow / captcha が増えていれば成功です。
LB / CDN が TLS を終端する構成では、実クライアントの JA4 を LB 側で抽出し、X-Client-JA4 header で転送する。 LB / CDN ごとの設定手順は LB から JA4 を取る (docs)。 JA4 が取れない場合の動作は JA4 の役割 (docs)。
gitや同期クライアント、スマホアプリが動かなくなった → JavaScript を実行できないクライアントは challenge を通過できません。それらが使うパス (API、WebDAV や git のエンドポイントなど) を 設定 → ホワイトパス で通してください。Git ホスティングには Git over HTTP の preset があり、よく使うアプリのパスは FAQ にあります。- 403 forbidden が出る → settings → ネットワークタブの
admin_allowed_ipsに自分の IP / CIDR を追加 - log の JA4 列が空 →
load_moduleの設定を確認。TLS を LB / CDN で終端している場合は 6.3 (LB のX-Client-JA4header 転送) を確認。verdict が「(none)」なのは正常で、どの fingerprint ルールにも一致しなかったことを表します (普通のブラウザはこれです) - nginx -t でモジュールの ABI 不一致 → nginx だけアップグレードされてモジュールが追従していない状態。nginx を restart してください。systemd のホストでは、plugin が起動のたびにインストール済みの nginx に合うモジュールを選び直します (RHEL/CentOS 6 と Alpine では restart の前に
sudo sh /usr/share/unmask/plugin/place-module.shを実行)。plugin が持っていない新しい nginx の場合は、対応したリリースが出たらunmask-plugin-nginxを更新します - challenge HTML が表示されない → unmask が
127.0.0.1:9477で listen しているか確認 (systemctl status unmask。RHEL/CentOS 6 はservice unmask status、Alpine はrc-service unmask status) - gateway container が 502 を返す → コンテナの中から転送先 (設定 → Gateway の upstream) に届いていない。Docker ホスト上のサーバーなら
http://host.docker.internal:8080と、コンテナから届くアドレスへの bind (127.0.0.1は不可) が必要。「転送先が未設定」の案内ページが出るなら、まず upstream を入れる - gateway の証明書が無い / 違う → 設定 → Gateway に :443 が配信中の証明書が表示される。自動 HTTPS はホスト名がこのホストに解決し、:80 がインターネットから到達できることが条件。購入した証明書は同じタブに貼り付け