jpskill.com
📦 その他 コミュニティ

routeros-hotspot

RouterOS搭載機器で、有線/無線LANのアクセス制御に使うホットスポット機能の設定、認証画面の作成、RADIUS連携などを行い、特定のウェブサイトへのアクセスを許可するウォールドガーデンを設定するSkill。

📜 元の英語説明(参考)

RouterOS hotspot captive portal for wired/wireless access control. Use when: configuring hotspot on RouterOS, setting up captive portal, writing hotspot profiles or instances, configuring walled garden, setting DHCP option 114 (RFC 8910 captive portal URI), integrating RADIUS with hotspot, or when the user mentions /ip/hotspot, walled-garden, hotspot profile, or captive portal on MikroTik.

🇯🇵 日本人クリエイター向け解説

一言でいうと

RouterOS搭載機器で、有線/無線LANのアクセス制御に使うホットスポット機能の設定、認証画面の作成、RADIUS連携などを行い、特定のウェブサイトへのアクセスを許可するウォールドガーデンを設定するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o routeros-hotspot.zip https://jpskill.com/download/20954.zip && unzip -o routeros-hotspot.zip && rm routeros-hotspot.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/20954.zip -OutFile "$d\routeros-hotspot.zip"; Expand-Archive "$d\routeros-hotspot.zip" -DestinationPath $d -Force; ri "$d\routeros-hotspot.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して routeros-hotspot.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → routeros-hotspot フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
3

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

RouterOS ホットスポット

ホットスポットチェーンの仕組み

ホットスポットのトラフィックインターセプトは、通常のファイアウォールの入力/転送チェーンより前に実行されます。これは、理解すべき最も重要な事実です。

  • /ip/hotspot はブリッジまたはインターフェースにバインドされます。そのインターフェース上のすべてのトラフィックは、最初にホットスポットチェーンに入ります。
  • ホットスポットインターフェースからの TCP 80/443 をブロックするファイアウォールルールは、キャプティブポータルのログインページをブロックしません。ホットスポットがファイアウォールがそれを見る前に処理します。
  • RouterOS は動的なファイアウォールルール(hs-unauthhs-auth チェーン)を自動的に挿入します。これらのホットスポット管理ルールを手動で作成、削除、または干渉しないでください。

よくある間違い: bridge-hotspot からポート 443 への DROP ルールを追加して「セキュリティギャップを修正する」こと。これは HTTPS ログインページをサイレントに壊します。

ホットスポットプロファイル

/ip/hotspot/profile/add \
  name=my-profile \
  hotspot-address=10.20.0.1 \
  login-by=https,mac,http-pap \
  mac-auth-mode=mac-as-username-and-password \
  dns-name=login.example.com \
  ssl-certificate=login.example.com.crt_0 \
  nas-port-type=ethernet \
  use-radius=yes \
  radius-accounting=yes \
  html-directory-override=hotspot-files

主なプロパティ:

  • ssl-certificate= — インポート後の名前を参照します(RouterOS はインポートされた証明書名に _0 を追加します)。
  • nas-port-type= — 有線ホットスポットには ethernet を、無線ホットスポットには wireless-ieee-802-11-g を使用します。
  • html-directory-override= — ルーターのファイルシステム上の正確なフォルダー名と一致する必要があります。
  • login-by=https — HTTPS 経由でログインページを提供します。同じ証明書で www-ssl サービスが有効になっている必要があります。
  • use-radius=yes — これが設定されている場合、ローカルの /ip/hotspot/user エントリはバイパスされます。それらを追加しても効果はありません。

ホットスポットインスタンス

/ip/hotspot/add \
  name=hotspot1 \
  interface=bridge-hotspot \
  profile=my-profile \
  address-pool=pool-hotspot \
  addresses-per-mac=2 \
  idle-timeout=5m \
  keepalive-timeout=none \
  disabled=no

注: keepalive-timeout=none はキープアライブを無効にします。keepalive-timeout=0 は有効ではありません。無視されます。

注: RouterOS ホットスポットは NAT に依存しており、IPv4 のみです。IPv6 クライアントはホットスポットサブシステムではサポートされていません。

DHCP オプション 114 — キャプティブポータル API (RFC 8910)

オプション 114(2020 年に標準化、RFC 8910)は、キャプティブポータルの URI をクライアントに通知します。LLM トレーニングデータでは過小評価されています。

# force=yes は必須です。これがないと、DHCP パラメータリクエスト
# リストにコード 114 が含まれていないクライアント(例: iOS、Android)は、
# オプションをサイレントにスキップします。
/ip/dhcp-server/option/add \
  name=captive-portal \
  code=114 \
  force=yes \
  value="'https://login.example.com/api'"

/ip/dhcp-server/option/sets/add \
  name=captive-portal-set \
  options=captive-portal

/ip/dhcp-server/set my-dhcp-server dhcp-option-set=captive-portal-set

オプション値の構文: 外側の二重引用符、内側の一重引用符 — "'https://...'"。内側の引用符がないと、オプションは文字列 URI ではなくバイナリブロブとして送信されます。

api.json のタイミング: RouterOS は、ホットスポット有効化時ではなく、最初のクライアント CAPPORT プローブ後にのみ hotspot/api.json を作成します。最初のクライアントが接続した後、html-directory-override フォルダーに移動してください。

# flash/ と非 flash ストレージレイアウトの両方を処理します
:local srcPath "hotspot/api.json"
:local dstPath "hotspot-files/api.json"
:if ([:len [/file find name="flash"]] > 0) do={
  :set srcPath "flash/hotspot/api.json"
  :set dstPath "flash/hotspot-files/api.json"
}
:if ([:len [/file find name=$srcPath]] > 0) do={
  /file set [find name=$srcPath] name=$dstPath
} else={
  :log warning "api.json not yet created — run after first client CAPPORT probe"
}

ウォールドガーデン

冪等な追加/削除のために、一貫した comment= タグを使用してください。これがないと、スクリプトを繰り返し実行すると重複エントリが蓄積されます。

# 手動で追加されたものではなく、独自のエントリのみを削除します
/ip/hotspot/walled-garden/ip/remove [find comment="my-wg"]

/ip/hotspot/walled-garden/ip/add dst-host=example.com   action=accept comment="my-wg"
/ip/hotspot/walled-garden/ip/add dst-host=*.example.com action=accept comment="my-wg"

IP と HTTP ウォールドガーデン:

  • /ip/hotspot/walled-garden/ip — 認証に適用される、宛先ホストによるレイヤー 3 マッチ。HTTPS 宛先に使用します。
  • /ip/hotspot/walled-garden — HTTP を必要とするレイヤー 7 URL パターンマッチ。HTTPS では機能しません

SSL 証明書に関する注意

ホットスポットプロファイルは ssl-certificate=name.crt_0 を参照します(RouterOS はインポート時に _0 を追加します)。同じ証明書で www-ssl を有効にしてください。

/ip/service/set www-ssl disabled=no certificate=login.example.com.crt_0 tls-version=only-1.2

クイックインポートパターン:

/certificate import file-name=login.example.com.crt passphrase=""
/certificate import file-name=login.example.com.key passphrase=""
# インポート後、証明書は login.example.com.crt_0 として表示されます

外部キャプティブポータル — HTML テンプレート変数

RouterOS は、html-directory-override 内の任意のファイルで、提供する前にサーバー側で $(variable) を置換します。これらは JavaScript 変数ではありません。ブラウザがページを受信する前に埋め込まれます。

RouterOS が提供するサーブレットページ(上書きするために独自のものをドロップしてください): login.htmlflogin.html(ログイン失敗)、alogin.html(ログイン成功後)、status.htmllogout.htmlerror.htmlredirect.htmlrlogin.htmlrstatus.htmlfstatus.htmlflogout.htmlradvert.htmlmd5.jserrors.txt。ほとんどの外部 CP セットアップでは、login.html + alogin.html + status.html のみが必要です。

外部 CP で最もよく使用される変数:

変数 説明
$(link-login-only) ?dst= なしのログイン POST エンドポイント — 外部認証に推奨(二重エンコーディングを回避)
$(link-login) ?dst= リダイレクトが追加されたログイン URL
$(link-orig) / $(link-orig-esc) クライアントが要求した元の URL。別の URL に補間する場合は -esc を使用します
$(server-name) ホットスポットインスタンス名
$(mac) / $(mac-esc) クライアント MAC(生 / URL-es

(原文がここで切り詰められています)

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

RouterOS Hotspot

How Hotspot Chains Work

Hotspot traffic intercept runs before the regular firewall input/forward chains. This is the single most important fact to internalize:

  • /ip/hotspot binds to a bridge or interface — all traffic on that interface enters the hotspot chain first
  • Firewall rules blocking TCP 80/443 from the hotspot interface do NOT block the captive portal login page — hotspot handles it before the firewall sees it
  • RouterOS automatically injects dynamic firewall rules (hs-unauth, hs-auth chains) — do not manually create, remove, or interfere with these hotspot-managed rules

Common mistake: Adding a DROP rule for port 443 from bridge-hotspot to "fix a security gap" — this breaks the HTTPS login page silently.

Hotspot Profile

/ip/hotspot/profile/add \
  name=my-profile \
  hotspot-address=10.20.0.1 \
  login-by=https,mac,http-pap \
  mac-auth-mode=mac-as-username-and-password \
  dns-name=login.example.com \
  ssl-certificate=login.example.com.crt_0 \
  nas-port-type=ethernet \
  use-radius=yes \
  radius-accounting=yes \
  html-directory-override=hotspot-files

Key properties:

  • ssl-certificate= — reference the name after import (RouterOS appends _0 to imported certificate names)
  • nas-port-type= — use ethernet for wired hotspots and wireless-ieee-802-11-g for wireless hotspots
  • html-directory-override= — must match the exact folder name on the router's filesystem
  • login-by=https — serves the login page over HTTPS; requires www-ssl service enabled with the same certificate
  • use-radius=yes — when set, local /ip/hotspot/user entries are bypassed; adding them has no effect

Hotspot Instance

/ip/hotspot/add \
  name=hotspot1 \
  interface=bridge-hotspot \
  profile=my-profile \
  address-pool=pool-hotspot \
  addresses-per-mac=2 \
  idle-timeout=5m \
  keepalive-timeout=none \
  disabled=no

Note: keepalive-timeout=none disables the keepalive. keepalive-timeout=0 is NOT valid — it is ignored.

Note: RouterOS hotspot relies on NAT and is IPv4-only. IPv6 clients are not supported by the hotspot subsystem.

DHCP Option 114 — Captive Portal API (RFC 8910)

Option 114 (standardized 2020, RFC 8910) signals the captive portal URI to clients. It is underrepresented in LLM training data.

# force=yes is REQUIRED — without it, clients whose DHCP Parameter Request
# List does not include code 114 (e.g. iOS, Android) silently skip the option
/ip/dhcp-server/option/add \
  name=captive-portal \
  code=114 \
  force=yes \
  value="'https://login.example.com/api'"

/ip/dhcp-server/option/sets/add \
  name=captive-portal-set \
  options=captive-portal

/ip/dhcp-server/set my-dhcp-server dhcp-option-set=captive-portal-set

Option value syntax: outer double quotes, inner single quotes — "'https://...'". Missing inner quotes cause the option to be sent as a binary blob, not a string URI.

api.json timing: RouterOS creates hotspot/api.json only after the first client CAPPORT probe — not at hotspot enable time. Move it to the html-directory-override folder after first client connects:

# Handles both flash/ and non-flash storage layouts
:local srcPath "hotspot/api.json"
:local dstPath "hotspot-files/api.json"
:if ([:len [/file find name="flash"]] > 0) do={
  :set srcPath "flash/hotspot/api.json"
  :set dstPath "flash/hotspot-files/api.json"
}
:if ([:len [/file find name=$srcPath]] > 0) do={
  /file set [find name=$srcPath] name=$dstPath
} else={
  :log warning "api.json not yet created — run after first client CAPPORT probe"
}

Walled Garden

Use a consistent comment= tag for idempotent add/remove. Without it, repeated script runs accumulate duplicate entries.

# Remove only our entries, not manually-added ones
/ip/hotspot/walled-garden/ip/remove [find comment="my-wg"]

/ip/hotspot/walled-garden/ip/add dst-host=example.com   action=accept comment="my-wg"
/ip/hotspot/walled-garden/ip/add dst-host=*.example.com action=accept comment="my-wg"

IP vs HTTP walled garden:

  • /ip/hotspot/walled-garden/ip — layer 3 match by destination host, applied BEFORE authentication. Use for HTTPS destinations.
  • /ip/hotspot/walled-garden — layer 7 URL pattern match, requires HTTP. Does NOT work for HTTPS.

SSL Certificate Note

The hotspot profile references ssl-certificate=name.crt_0 (RouterOS appends _0 on import). Enable www-ssl with the same certificate:

/ip/service/set www-ssl disabled=no certificate=login.example.com.crt_0 tls-version=only-1.2

Quick import pattern:

/certificate import file-name=login.example.com.crt passphrase=""
/certificate import file-name=login.example.com.key passphrase=""
# After import, the certificate appears as login.example.com.crt_0

External Captive Portal — HTML Template Variables

RouterOS substitutes $(variable) server-side in any file under html-directory-override before serving it. These are not JavaScript variables — they are filled before the browser receives the page.

Servlet pages RouterOS serves (drop your own to override): login.html, flogin.html (failed-login), alogin.html (post-success), status.html, logout.html, error.html, redirect.html, rlogin.html, rstatus.html, fstatus.html, flogout.html, radvert.html, md5.js, errors.txt. Most external-CP setups only need login.html + alogin.html + status.html.

Most-used variables for external CP:

Variable Description
$(link-login-only) Login POST endpoint without ?dst= — preferred for external auth (avoids double-encoding)
$(link-login) Login URL with ?dst= redirect appended
$(link-orig) / $(link-orig-esc) Original URL the client requested. Use -esc when interpolating into another URL
$(server-name) Hotspot instance name
$(mac) / $(mac-esc) Client MAC (raw / URL-escaped)
$(ip) Client IP
$(host-ip) IP from hotspot host table (differs from $(ip) under one-to-one NAT)
$(interface-name), $(vlan-id) Useful for tenant-aware external auth
$(error) / $(error-orig) Localized vs raw error from previous auth attempt
$(logged-in) yes if client is already authenticated
$(trial) yes if trial access still available for this MAC
$(username) / $(username-esc) Authenticated username (status page)
$(bytes-in[-nice]), $(bytes-out[-nice]), $(uptime[-secs]), $(session-time-left[-secs]) Status-page counters
$(radius<id>[u]), $(radius<id>-<vnd-id>[u]) Pass-through of RADIUS Access-Accept attributes — text or unsigned int. Empty / "0" when local-DB auth (use-radius=no)
$(http-header-<Name>) Read an incoming request header — e.g. $(http-header-User-Agent), $(http-header-Accept-Language)
$(if http-status == XYZ)MSG$(endif) Set the HTTP response status code
$(if http-header == NAME)VALUE$(endif) Set a custom response header (different syntax from the read pattern above)

Always pick the -esc variant ($(link-orig-esc), $(mac-esc), $(username-esc)) when embedding a value into a URL or query string. The non-escaped variants will break parsing or open injection paths if the value contains &, =, ?, #.

POST form fields RouterOS accepts at $(link-login-only): username, password, domain, dst, popup, session-id, var, erase-cookie, target (multi-language subdir).

Conditional syntax (server-side, not JavaScript):

$(if logged-in == "yes")
  <a href="$(link-logout)">Logout</a>
$(else)
  <form action="$(link-login-only)" method="post">...</form>
$(endif)

Operators: presence ($(if VAR)), ==, !=. Also $(elif ...). No nested arithmetic / string ops.

Generic login.html pattern for external captive portal:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="pragma" content="no-cache">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- External auth provider loads redirect logic -->
  <script src='https://auth.example.com/snippets/router-os/redirect'></script>
</head>
<body>
  <div id="entryPoint">Redirecting...</div>
  <script>
    window.addEventListener('load', function () {
      ExternalAuth_redirect(
        '$(server-name)', '$(mac-esc)', '$(link-login-only)',
        '$(link-orig-esc)', '$(error-orig)', '$(logged-in)', '$(ip)'
      );
    });
  </script>
</body>
</html>

The external provider authenticates the user and redirects the browser back to $(link-login-only) with username + password + dst POST fields. RouterOS validates (local DB or RADIUS), issues the auth cookie, and redirects to dst.

Walled-garden must include the external auth host (and any CDN/asset hosts) — otherwise the unauthenticated browser cannot reach the redirect script in step 2.

Full variable reference, all servlet pages, RADIUS pass-through patterns, multi-language target= mechanics, and HTTP response control: see references/template-variables.md.

Common LLM Mistakes

Mistake Correct behavior
DROP TCP 443 from hotspot interface Hotspot chain runs before firewall — breaks the HTTPS login page
keepalive-timeout=0 to disable keepalive Use keepalive-timeout=none
Option 114 value= without inner single quotes Must be "'https://...'" — outer double, inner single
Option 114 without force=yes iOS/Android silently skip option if not in their DHCP PRL
Adding /ip/hotspot/user when use-radius=yes Local users are bypassed when RADIUS is active
Wildcard HTTPS domains in /ip/hotspot/walled-garden Use /ip/hotspot/walled-garden/ip for HTTPS (layer 3 match)
Hotspot on dual-stack network with IPv6 Hotspot is IPv4-only — IPv6 not supported
$(link-login) treated as JavaScript variable It is RouterOS server-side substitution, not JS
Embedding $(link-orig) / $(mac) / $(username) into another URL Use the -esc variant — non-esc breaks parsing on &, =, ? and may enable injection
Hotspot with PCC / multiple routing tables Hotspot uses only the default routing table — split-WAN setups need explicit /ip route rule for hotspot traffic

Additional Resources

Related skills:

  • routeros-fundamentals — RouterOS CLI syntax, REST API, scripting basics
  • routeros-certificates (in backlog) — for the full certificate chain handling pattern

MCP tools:

  • rosetta MCP server — /tool/ping, /ip/hotspot command tree inspection (routeros_search, routeros_get_page)

MikroTik docs:

RADIUS Integration

See references/radius-client.md for RADIUS client configuration patterns.

同梱ファイル

※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。