リモートデスクトップ「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 kernel
ALTQ related functions disabled
Status: Enabled for 2 days 17:03:06           Debug: Urgent

State Table                          Total             Rate
  current entries                        0
  searches                        23851916          101.9/s
  inserts                             1647            0.0/s
  removals                            1647            0.0/s
Counters
  match                           21809386           93.1/s
  bad-offset                             0            0.0/s
  fragment                               0            0.0/s
  short                                  0            0.0/s
  normalize                              0            0.0/s
  memory                                 0            0.0/s
  bad-timestamp                          0            0.0/s
  congestion                             0            0.0/s
  ip-option                           2196            0.0/s
  proto-cksum                            0            0.0/s
  state-mismatch                         0            0.0/s
  state-insert                           0            0.0/s
  state-limit                            0            0.0/s
  src-limit                              0            0.0/s
  synproxy                               0            0.0/s
  dummynet                               0            0.0/s
  invalid-port                           0            0.0/s

ルートのルールセット表示
% sudo pfctl -sr

No ALTQ support in kernel
ALTQ related functions disabled
scrub-anchor "com.apple/*" all fragment reassemble
scrub-anchor "com.apple.internet-sharing" all fragment reassemble
anchor "com.apple/*" all
anchor "com.apple.internet-sharing" all

Appleのシステムアンカー(OS機能用)だけで、ユーザー定義ルールはゼロの素の状態。


4. RustDeskから外部通信を遮断

RustDeskから外への通信を遮断したいので、LuLuのインストールが必要。

pfは「どこから来た通信を受け入れるか」(インバウンド)の設定。
LuLuは「どのアプリが外に出ていくか」(アウトバウンド)の設定。

検索してインストール。
% brew search lulu
% brew install --cask lulu

LuLuアプリを起動。

  1. 通知から「ログイン項目と機能拡張」を開く。
  2. 機能拡張項目のLuLuのインフォマークをクリック。
  3. ネットワーク機能拡張をオン。
  4. 「Appleプログラムを許可」「既存アプリを許可」を選ぶ


LuLuでRustDeskの外部通信をブロック

  1. LuLuアプリ起動 → Rules(ルール)→ View Rules
  2. 上の「3rd-patry Rules」フィルターで絞り込む。
  3. RustDeskを再起動するとリストにAllowで追加される。
  4. それを選択して、BlockでUpdateする。
  5. 「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 " " $2
    match($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 host
        close(cmd)
        cache[ip] = (host == "") ? "-" : host
        host = ""
    }
    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 --server
daiki            99991   0.0  0.0 435299984   1376 s000  S+    9:37AM   0:00.01 grep -i rustdesk
root             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 *:21119
RustDesk   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


▼ 関連記事