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本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
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
$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. 下の青いボタンを押して
routeros-hotspot.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
routeros-hotspotフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 3
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
RouterOS ホットスポット
ホットスポットチェーンの仕組み
ホットスポットのトラフィックインターセプトは、通常のファイアウォールの入力/転送チェーンより前に実行されます。これは、理解すべき最も重要な事実です。
/ip/hotspotはブリッジまたはインターフェースにバインドされます。そのインターフェース上のすべてのトラフィックは、最初にホットスポットチェーンに入ります。- ホットスポットインターフェースからの TCP 80/443 をブロックするファイアウォールルールは、キャプティブポータルのログインページをブロックしません。ホットスポットがファイアウォールがそれを見る前に処理します。
- RouterOS は動的なファイアウォールルール(
hs-unauth、hs-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.html、flogin.html(ログイン失敗)、alogin.html(ログイン成功後)、status.html、logout.html、error.html、redirect.html、rlogin.html、rstatus.html、fstatus.html、flogout.html、radvert.html、md5.js、errors.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/hotspotbinds 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-authchains) — 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_0to imported certificate names)nas-port-type=— useethernetfor wired hotspots andwireless-ieee-802-11-gfor wireless hotspotshtml-directory-override=— must match the exact folder name on the router's filesystemlogin-by=https— serves the login page over HTTPS; requireswww-sslservice enabled with the same certificateuse-radius=yes— when set, local/ip/hotspot/userentries 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 basicsrouteros-certificates(in backlog) — for the full certificate chain handling pattern
MCP tools:
rosettaMCP server —/tool/ping,/ip/hotspotcommand tree inspection (routeros_search,routeros_get_page)
MikroTik docs:
- HotSpot — official reference
- DHCP Server — option 114 configuration
RADIUS Integration
See references/radius-client.md for RADIUS client configuration patterns.
同梱ファイル
※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。
- 📄 SKILL.md (11,597 bytes)
- 📎 references/radius-client.md (2,206 bytes)
- 📎 references/template-variables.md (10,459 bytes)