rustdesk-doctor について
rustdesk-doctorは、RustDeskクライアントの接続障害を調べるスキルで、リモート接続のトラブルを診断するユーザー向けです。クライアント、Clash/TUN、ネットワークポート、接続可能なサーバーを順に確認し、判定表で原因を整理します。診断操作は読み取り専用です。
主な機能
- 01RustDeskのプロセス、設定、ログの収集
- 02Clash、Mihomo、TUNルーティングの影響確認
- 03サーバーのDNSとネットワークポートの疎通テスト
- 04許可があり接続可能な場合のSSHサーバー状態確認
- 05判定表に基づく原因の整理
- 06診断は読み取り専用、変更前に確認
活用シーン
- 01プロキシやTUNが関わるRustDesk接続障害の調査
- 02ファイアウォールやクラウドセキュリティグループによるポート遮断の判定
- 03DNS fake-IPやTUNによるローカルIP汚染の確認
- 04クライアント設定とサーバー側の障害の切り分け
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ majiayu000/ spellbook --skill rustdesk-doctorインストール後、Claude Code で/rustdesk-doctorを入力して読み込まれたか確認します。
詳細
RustDesk 接続診断ツール
RustDesk クライアントがサーバーに接続できない問題を診断します。Clash/TUN プロキシの干渉、サーバー側の設定、クラウドセキュリティグループなど、よくある根本原因を調査します。
ユーザーから渡されたパラメーター(ある場合):$ARGUMENTS
診断フロー
以下の手順を厳守し、各手順を実行して結果を記録してから、総合診断を提示してください。
第一步:クライアントの状態を収集
以下のチェックを並行して実行します:
- RustDesk のプロセスとネットワーク接続
ps aux | grep -i rustdesk | grep -v grep
echo "=== 网络连接 ==="
lsof -i -P -n 2>/dev/null | grep -i rustdesk
- RustDesk の設定ファイル
CONFIG_DIR="$HOME/Library/Preferences/com.carriez.RustDesk"
echo "=== RustDesk2.toml ==="
cat "$CONFIG_DIR/RustDesk2.toml" 2>/dev/null || echo "文件不存在"
echo "=== RustDesk_local.toml ==="
cat "$CONFIG_DIR/RustDesk_local.toml" 2>/dev/null || echo "文件不存在"
- RustDesk の最新ログ(重要な行)
LOG="$HOME/Library/Logs/RustDesk/RustDesk_rCURRENT.log"
cat "$LOG" 2>/dev/null || echo "日志不存在"
第二步:Clash/プロキシの干渉を確認
以下のチェックを並行して実行します:
- Mihomo における RustDesk の接続とルールの一致
SOCKET="/var/tmp/verge/verge-mihomo.sock"
if [ -S "$SOCKET" ]; then
curl -s --unix-socket "$SOCKET" http://localhost/connections 2>/dev/null | python3 -c "
import sys,json
data=json.load(sys.stdin)
conns=data.get('connections',[])
found=False
for c in conns:
meta=c.get('metadata',{})
proc=meta.get('process','').lower()
host=meta.get('host','').lower()
dst=meta.get('destinationIP','')
if 'rustdesk' in proc or 'rustdesk' in host or '21116' in meta.get('destinationPort','') or '21115' in meta.get('destinationPort',''):
chains=c.get('chains',[])
rule=c.get('rule','')
rp=c.get('rulePayload','')
net=meta.get('network','')
dp=meta.get('destinationPort','')
print(f'{meta.get(\"process\",\"\")} | {net} | {host or dst}:{dp} | rule={rule} {rp} | chains={chains}')
found=True
if not found:
print('Mihomo 中没有 RustDesk 相关连接')
"
else
echo "Mihomo unix socket 不存在,Clash 可能未运行"
fi
- Mihomo における RustDesk 関連ルール
SOCKET="/var/tmp/verge/verge-mihomo.sock"
if [ -S "$SOCKET" ]; then
curl -s --unix-socket "$SOCKET" http://localhost/rules 2>/dev/null | python3 -c "
import sys,json
rules=json.load(sys.stdin).get('rules',[])
for r in rules:
p=str(r.get('payload','')).lower()
if 'rustdesk' in p:
print(f\"{r.get('type')},{r.get('payload')},{r.get('proxy')}\")
" || echo "无法获取规则"
echo "=== TUN 配置 ==="
curl -s --unix-socket "$SOCKET" http://localhost/configs 2>/dev/null | python3 -c "
import sys,json
c=json.load(sys.stdin)
tun=c.get('tun',{})
print('TUN enabled:', tun.get('enable'))
rea=tun.get('route-exclude-address',[])
if rea:
print('route-exclude-address:', rea)
"
fi
- DNS 解決の確認(fake-ip の検出)
RustDesk サーバーのドメインを DNS 解決し、fake-ip(198.18.x.x)が返されるか確認します:
# 如果配置了自建服务器(IP 地址),跳过域名解析
# 如果使用默认公共服务器,检查 rs-ny.rustdesk.com
nslookup rs-ny.rustdesk.com 2>&1
nslookup rustdesk.com 2>&1
- ルートの確認
RustDesk サーバー IP のルート経路(TUN utun1024 を経由するかどうか)を確認します:
# 对配置中的服务器 IP 执行 route get
# 如果走 utun1024 → TUN 拦截
# 如果走 en0 → 直连
route -n get <服务器IP> 2>&1 | head -6
- Clash Verge profiles 内の RustDesk 設定
PROFILES_DIR="$HOME/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/profiles"
grep -ril "rustdesk" "$PROFILES_DIR/"*.yaml "$PROFILES_DIR/"*.js 2>/dev/null | while read f; do
echo "=== $(basename $f) ==="
grep -in "rustdesk" "$f"
done
第三步:ネットワーク接続テスト
設定されているサーバー(自前のサーバーまたはデフォルトの公開サーバー)に対して実行します:
SERVER="<服务器IP或域名>"
echo "=== TCP 21115 (NAT test) ==="
nc -z -w5 $SERVER 21115 2>&1 && echo "OK" || echo "FAIL"
echo "=== TCP 21116 (rendezvous) ==="
nc -z -w5 $SERVER 21116 2>&1 && echo "OK" || echo "FAIL"
echo "=== TCP 21117 (relay) ==="
nc -z -w5 $SERVER 21117 2>&1 && echo "OK" || echo "FAIL"
echo "=== UDP 21116 ==="
nc -z -w5 -u $SERVER 21116 2>&1 && echo "OK" || echo "FAIL(UDP 结果可能不准确)"
echo "=== 路由走向 ==="
route -n get $SERVER 2>&1 | head -6
第四步:サーバー側の確認(SSH 接続が可能な場合)
ユーザーが自前のサーバー IP を提供し、SSH 接続が可能な場合は、以下のチェックを実行します:
SERVER="<服务器IP>"
ssh -o ConnectTimeout=10 root@$SERVER "
echo '=== Docker 容器状态 ==='
docker ps | grep -i rust
echo '=== hbbs 日志(最后 20 行)==='
docker logs hbbs --tail 20 2>&1
echo '=== hbbr 日志(最后 10 行)==='
docker logs hbbr --tail 10 2>&1
echo '=== 端口监听 ==='
ss -ulnp | grep 21116
ss -tlnp | grep -E '2111[5-9]'
echo '=== 公钥 ==='
cat /root/id_ed25519.pub 2>/dev/null || find / -name 'id_ed25519.pub' 2>/dev/null | head -1 | xargs cat 2>/dev/null
echo '=== UFW 状态 ==='
ufw status 2>/dev/null | head -15
echo '=== 云安全组防火墙链 ==='
iptables -L INPUT -n 2>/dev/null | head -5
echo '=== 抓包测试(10秒)==='
timeout 10 tcpdump -i eth0 -c 5 udp port 21116 2>&1
"
第五步:local-ip-addr の確認
RustDesk が TUN ゲートウェイ IP をローカル IP として認識していないか確認します:
CONFIG="$HOME/Library/Preferences/com.carriez.RustDesk/RustDesk2.toml"
LOCAL_IP=$(grep 'local-ip-addr' "$CONFIG" 2>/dev/null | awk -F"'" '{print $2}')
if [ "$LOCAL_IP" = "198.18.0.1" ]; then
echo "WARNING: local-ip-addr = 198.18.0.1 (TUN 网关假 IP)"
echo "RustDesk 启动时检测到 TUN 虚拟网卡 IP,需要在 TUN 关闭时启动 RustDesk"
REAL_IP=$(ifconfig en0 2>/dev/null | grep 'inet ' | awk '{print $2}')
echo "真实 IP 应该是: $REAL_IP"
elif [ -n "$LOCAL_IP" ]; then
echo "local-ip-addr = $LOCAL_IP"
else
echo "local-ip-addr 未设置(自动检测)"
fi
総合診断
収集したすべての情報に基づき、以下の判定表を使って分析します:
よくある問題の判定表
| ログの重要な行 | ネットワーク状態 | Clash の状態 | 診断 |
|---|---|---|---|
register_pk ... key not confirmed の再試行が続く | ポートに接続できない | DIRECT 経由 | TUN の DIRECT UDP 転送異常、またはサーバーに到達できない |
register_pk ... key not confirmed の再試行が続く | ポートに接続できる | Proxies 経由 | プロキシノードが RustDesk の UDP プロトコルに対応していない |
register_pk ... key not confirmed + サーバーの tcpdump にパケットがない | SSH 接続は可能、その他のポートには接続できない | - | クラウドセキュリティグループで 21115-21117/tcp と 21116/udp が許可されていない |
Got nat response の応答はあるが register_pk に失敗 | UDP は通るが TCP 21115 は通らない | Proxies 経由 | プロキシの通常の TCP 転送が不完全です。IP-CIDR ルールの追加が必要です |
Failed to connect to ...:21115 | TCP に接続できない | - | TCP 21115 がブロックされている(プロキシ/ファイアウォール/セキュリティグループ) |
local-ip-addr = 198.18.0.1 | - | TUN が有効 | TUN の偽 IP による汚染です。TUN を無効にして RustDesk を再起動するか、このフィールドを空にしてください |
error sending request for url (https://api.rustdesk.com/...) | HTTPS に接続できない | DIRECT 経由 | RustDesk 公式 API がブロックされています。プロキシ経由にする必要があります |
| DNS 解決で 198.18.x.x が返される | - | fake-ip モード | rustdesk.com を fake-ip-filter に追加するか、+.rustdesk.com を使用してください |
よくある解決策
解決策 A:TUN モードで DIRECT UDP が通らない
TUN の DIRECT 出口では UDP を正しく転送できない場合があります。対処方法:
- Merge.yaml に
route-exclude-addressを追加し、サーバー IP が TUN を完全に迂回するようにします:
tun:
route-exclude-address:
- <服务器IP>/32
- または、RustDesk の通信をプロキシ経由にします(サブスクリプション内の DIRECT ルールを削除します)。
解決策 B:サブスクリプション設定に rustdesk.com の DIRECT ルールが含まれている
サブスクリプションに DOMAIN-SUFFIX,rustdesk.com,DIRECT が含まれている場合があります。プロキシ経由にするには:
ルール profile の delete セクションに追加します:
delete:
- DOMAIN-SUFFIX,rustdesk.com,DIRECT
解決策 C:クラウドセキュリティグループでポートが開放されていない
Tencent Cloud/Alibaba Cloud などのセキュリティグループはクラウドプラットフォーム層で通信をフィルタリングするため、iptables や UFW では確認できません。クラウドコンソールで次のルールを追加してください:
| プロトコル | ポート | 接続元 |
|---|---|---|
| TCP | 21115-21117 | 0.0.0.0/0 |
| UDP | 21116 | 0.0.0.0/0 |
解決策 D:local-ip-addr が TUN の偽 IP に汚染されている
RustDesk は起動時にネットワークインターフェースの IP を検出します。TUN モードでは 198.18.0.1 を取得する場合があります。対処方法:
- TUN を無効にして RustDesk を起動し(実際の IP を検出させてから)、TUN を再度有効にします
- または、
RustDesk2.tomlのlocal-ip-addrを手動で空にします:
[options]
local-ip-addr = ''
解決策 E:プロキシノードが RustDesk のプロトコルに対応していない
RustDesk は UDP と通常の TCP(HTTP/TLS ではない)を使用するため、一部のプロキシノードは対応していません。対処方法:
- UDP に対応したプロキシノードに切り替えます
- 通常の TCP ポート(21115)については、Mihomo がルーティングできるよう IP-CIDR ルールを追加します:
prepend:
- IP-CIDR,<服务器IP>/32,Proxies,no-resolve
RustDesk のポート説明
| ポート | プロトコル | 用途 |
|---|---|---|
| 21114 | TCP | API/Web コンソール(新バージョン) |
| 21115 | TCP | NAT タイプの検出 |
| 21116 | TCP+UDP | ランデブーサーバー(登録、シグナリング) |
| 21117 | TCP | リレー転送 |
| 21118 | TCP | WebSocket |
| 21119 | TCP | WebSocket リレー |
注意事項
- 診断操作はすべて読み取り専用で、設定は変更しません
- 設定を変更する前にユーザーへ伝え、確認を取ります
- サーバーに SSH 接続する前に、ユーザーの許可を確認します
- 優先して確認する項目:クラウドセキュリティグループ > プロキシ/TUN の干渉 > サーバー側 > クライアント設定
- 診断情報はすべて中国語で出力します