リモートデスクトップ「RustDesk」をMac miniにインストール
Mac miniにWindows11からVNCで操作していると、遅延があるのが気になるので評判がいいRustDeskを試したときの覚書。
Claude Fable 5と対話。
環境: Mac mini 2024 メモリ24GB, Tahoe 26.5.2
使ってみて、ほぼ遅延がなく快適なのでVNCから乗り換えた。
1. RustDeskとは?
RustDeskは、TeamViewerやAnyDeskの代替として開発されたオープンソースのリモートデスクトップソフト。
名前の通りコア部分がRust言語で書かれており、GUIにはFlutterを採用。
Windows・macOS・Linux・iOS・Androidに対応し、ライセンスはAGPL-3.0で公開されている。
開発のきっかけは2020年、開発者がTeamViewerの商用ライセンスの価格に驚き「自分で作る」と決めたこと。
2021年のGitHub公開以降、スター数11万超まで成長した人気プロジェクト。
特徴
- 無料で無人アクセス可能 — 時間制限や商用判定によるブロックがない
- セルフホスト対応 — 接続を仲介するサーバー(hbbs/hbbr)を自前で運用でき、外部インフラに依存しない構成が組める
- LAN内ならIP直接続 — サーバーすら不要で、IPアドレス指定だけで低遅延に接続できる
映像はVP8/VP9/AV1とH.264/H.265に対応し、VNCと比べて描画は圧倒的に滑らか。
通信はNaClベースのエンドツーエンド暗号化。
なお、開発元の透明性については過去に議論があったソフト。
ただし、クライアントとOSSサーバーはコードが完全公開されており、LAN内利用や外部通信の遮断といった構成を取れば、この種の懸念は技術的にコントロール可能。
rustdeskとrustdesk-serverの違い
RustDeskはVNCと違い、1つのバイナリが「操作する側(ビューア)」と「操作される側(被制御)」の両方の機能を持っていて、役割は固定されていない。
rustdesk-serverは接続の仲介インフラ。
インターネット越しに互いを見つけるための電話帳+中継局。
2. Mac miniにRustDeskをインストール
caskオプションを付けてGUIアプリとしてインストール実行。
% brew install --cask rustdesk
rustdesk 1.4.9がインストールされた。
RustDeskを起動。
左下の設定をクリック。
(設定後、左下のメッセージが切り替わるのでそこから再度設定)
RustDesk画面の右上のメニューをクリック → プライバシーとセキュリティで以下3つを許可:
- 画面収録とシステムオーディオ録音: 画面を映す(必須)
- アクセシビリティ: マウス・キーボード操作(必須)
- 入力監視: キー入力の送信
自動起動するようにサービスをインストールした。
RustDeskの設定(Mac mini側)
RustDeskの設定 → セキュリティで下記設定。
- 固定パスワードを設定
- IP直接アクセスを有効化:これでLAN内からID・公式サーバー不要で接続可能(待受はTCP 21118)
Windows11にRustDeskをインストールして接続
scoopでインストールした。
PS> scoop search rustdesk
PS> scoop install rustdesk
起動してMac miniのIPv4アドレスを入れて接続。
3. Mac miniのファイヤーウォール設定
macOSのファイアウォールALF(Application Layer Firewall)が動いているか確認。
% sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
Firewall is enabled. (State = 1)
ALFはアプリ単位で着信接続の許可/拒否を判定する。
pf(Packet Filter)も利用しているようなので状態を確認する。
% sudo pfctl -s info
No ALTQ support in kernelALTQ related functions disabledStatus: Enabled for 2 days 17:03:06 Debug: UrgentState Table Total Ratecurrent entries 0searches 23851916 101.9/sinserts 1647 0.0/sremovals 1647 0.0/sCountersmatch 21809386 93.1/sbad-offset 0 0.0/sfragment 0 0.0/sshort 0 0.0/snormalize 0 0.0/smemory 0 0.0/sbad-timestamp 0 0.0/scongestion 0 0.0/sip-option 2196 0.0/sproto-cksum 0 0.0/sstate-mismatch 0 0.0/sstate-insert 0 0.0/sstate-limit 0 0.0/ssrc-limit 0 0.0/ssynproxy 0 0.0/sdummynet 0 0.0/sinvalid-port 0 0.0/s
ルートのルールセット表示
% sudo pfctl -sr
No ALTQ support in kernelALTQ related functions disabledscrub-anchor "com.apple/*" all fragment reassemblescrub-anchor "com.apple.internet-sharing" all fragment reassembleanchor "com.apple/*" allanchor "com.apple.internet-sharing" all
Appleのシステムアンカー(OS機能用)だけで、ユーザー定義ルールはゼロの素の状態。
4. RustDeskから外部通信を遮断
RustDeskから外への通信を遮断したいので、LuLuのインストールが必要。
pfは「どこから来た通信を受け入れるか」(インバウンド)の設定。
LuLuは「どのアプリが外に出ていくか」(アウトバウンド)の設定。
検索してインストール。
% brew search lulu
% brew install --cask lulu
LuLuアプリを起動。
- 通知から「ログイン項目と機能拡張」を開く。
- 機能拡張項目のLuLuのインフォマークをクリック。
- ネットワーク機能拡張をオン。
- 「Appleプログラムを許可」「既存アプリを許可」を選ぶ
LuLuでRustDeskの外部通信をブロック
- LuLuアプリ起動 → Rules(ルール)→ View Rules
- 上の「3rd-patry Rules」フィルターで絞り込む。
- RustDeskを再起動するとリストにAllowで追加される。
- それを選択して、BlockでUpdateする。
- 「3rd-patry Rules」から消えて「User-created Rules」に移動される。
LuLuのログを監視するワンラインコマンド。
log stream --predicate 'subsystem == "com.objective-see.lulu"' --level debug 2>/dev/null | awk '/setting verdict to:/ { v = $NF }/\[LULU\] PROCESS:/ {if (v != "BLOCK") { next }ts = $1 " " $2match($0, /PROCESS: [^,]+/)path = substr($0, RSTART + 9, RLENGTH - 9)n = split(path, a, "/"); app = a[n]match($0, /FLOW \(endpoint\): [^,]+/)ep = substr($0, RSTART + 17, RLENGTH - 17)ip = ep; sub(/:[0-9]+$/, "", ip)if (!(ip in cache)) {cmd = "dig +short -x " ip " 2>/dev/null | head -1"cmd | getline hostclose(cmd)cache[ip] = (host == "") ? "-" : hosthost = ""}printf "%s %s -> %s (%s)\n", ts, app, ep, cache[ip]fflush()v = ""}'
試しにGoogle Chromeの通信を拒否してみて動作確認。
5. RustDeskを再起動して状態確認
RustDeskのプロセスを確認。
% ps aux | grep -i "rustdesk"
RustDeskは2階層で動いている。
- LaunchDaemon(root):com.carriez.RustDesk_service → serviceプロセス
- LaunchAgent(daiki):com.carriez.RustDesk_server → RustDesk --serverプロセス
まずはRustDeskを停止する。
LaunchDaemon(rootのserviceプロセス)を停止。
% sudo launchctl bootout system/com.carriez.RustDesk_service
LaunchAgent(--serverプロセス)を停止
% launchctl bootout gui/$(id -u)/com.carriez.RustDesk_server
RustDeskのプロセスを確認。
% ps aux | grep -i "rustdesk"
WindowsのRustDeskから接続できないことを確認。
RustDeskを起動。
LaunchDaemonを再登録。
% sudo launchctl bootstrap system /Library/LaunchDaemons/com.carriez.RustDesk_service.plist
LaunchAgentを再登録
% launchctl bootstrap gui/$(id -u) /Library/LaunchAgents/com.carriez.RustDesk_server.plist
RustDeskのプロセスを確認。
% ps aux | grep -i "rustdesk"
daiki 99981 0.1 0.3 35677300 64208 ?? S 9:36AM 0:00.66 /Applications/RustDesk.app/Contents/MacOS/RustDesk --serverdaiki 99991 0.0 0.0 435299984 1376 s000 S+ 9:37AM 0:00.01 grep -i rustdeskroot 99976 0.0 0.0 34665992 12128 ?? Ss 9:35AM 0:00.12 /Applications/RustDesk.app/Contents/MacOS/service
WindowsのRustDeskから接続できることを確認。
開いているファイルの一覧(lsof = LiSt Open Files)で確認。
% sudo lsof -i -P | grep -i rustdesk
RustDesk 1520 daiki 19u IPv6 0xa0c1d08078d4649f 0t0 TCP 192.168.10.105:21118->192.168.10.106:60816 (ESTABLISHED)RustDesk 1520 daiki 25u IPv4 0x3bd11a42bc10e67f 0t0 UDP *:21119RustDesk 1520 daiki 32u IPv6 0xe39dbb7038e8030 0t0 TCP *:21118 (LISTEN)
オプション解説
- -i(internet): ネットワークソケットを持つファイルだけに絞り込み。
- -P(Port numbers): ポート番号をサービス名に変換せず数字のまま表示。
出力列の意味
|
列 |
値 |
意味 |
|
COMMAND |
RustDesk |
プロセス名 |
|
PID |
1520 |
プロセスID |
|
USER |
daiki |
実行ユーザー |
|
FD |
19u |
ファイルディスクリプタ番号+モード(u=読み書き、r=読み、w=書き) |
|
TYPE |
IPv6 |
ソケット種別 |
|
DEVICE |
0xa0c1... |
カーネル内のソケット識別子 |
|
SIZE/OFF |
0t0 |
オフセット(ソケットでは実質意味なし) |
|
NODE |
TCP |
プロトコル |
|
NAME |
192.168...(ESTABLISHED) |
接続情報と状態 |
コマンド結果解説
RustDesk 1520 daiki 19u IPv6 ... TCP 192.168.10.105:21118->192.168.10.106:60816 (ESTABLISHED)
- 192.168.10.105:21118(Mac mini、IP直接アクセスの待受ポート)と192.168.10.106:60816(Windows機、送信元はエフェメラルポート)の間でTCP接続が確立済み(ESTABLISHED)
- 矢印の向きがMac:21118 -> Windowsとなっているが、これはlsofの表記上ローカル側を左に書くだけで、接続を開始したのはWindows側(インバウンド接続)
RustDesk 1520 daiki 25u IPv4 ... UDP *:21119
- IP直接アクセスの補助用にUDP 21119も開いている。
- *:21119はすべてのインターフェースで待ち受けの意味。
RustDesk 1520 daiki 32u IPv6 ... TCP *:21118 (LISTEN)
- 新規接続を受け付けるためのLISTEN状態。
- 1行目のESTABLISHEDはこのLISTENから派生したもの。
- IPv6ソケットだが、macOSではIPv4接続もこのIPv6ソケットで受けられる(デュアルスタック)。
ちなみに待ち受けポート一覧コマンド
% sudo lsof -i -P -n | grep LISTEN