---
title: macOSランナーにVNCできるまで
tags: 
author: [DeNA_Tech](https://www.docswell.com/user/DeNA_Tech)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/4EQVGYQNJP.jpg?width=480
description: 2025/10/23に開催されたイベント「CI/CD Test Night #8」の登壇スライドです。 イベント概要：https://testnight.connpass.com/event/369890/ 「CI/CD Test Night #8」アーカイブ動画：https://youtu.be/lBD1JADqL5k
published: October 24, 25
canonical: https://www.docswell.com/s/DeNA_Tech/K37QVL-macOS_VNC
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/4EQVGYQNJP.jpg)

macOSランナーに
VNCできるまで
前田 薫
DeNA SWET 1G
2025/10/23 CI/CD Test Night #8
© DeNA Co., Ltd.
1


# Page. 2

![Page Image](https://bcdn.docswell.com/page/KJ4M5WN3E1.jpg)

自己紹介
● 前田 薫 @mad_p, GitHub: mad-p
○
DeNA 2017年入社
● HHKB (尊師スタイル)
● 漢字直接入力 (T-Code, MacTcode)
● ルービックキューブ (公式記録)
● Splatoon3 (5000時間)
© DeNA Co., Ltd.
2
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/LE18WY5Z7G.jpg)

background
●
DeNAでは社内向けにActionsセルフホストランナーを提供している
●
macOSランナーをベータ提供中
○
●
uptermを利用したsshログインを提供済み
■
uptermdを社内向けにホスティング
■
owenthereal/action-upterm を改造し、社内uptermdに向けている
「VNCを使いたくなるのではないか?」という指摘があった
© DeNA Co., Ltd.
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/GEWZ6G56E2.jpg)

why VNC
VNC接続に成功したところ
●
なぜVNCしたいのか
○
アプリ署名時、keychain
ダイアログで止まりがち
●
これまではどうしていた?
○
オンプレの物理マシンなので
VNCできていた
●
なぜrunnerにVNCできないのか
○
マシンは動的に割当て、
固定IPアドレスはない
○
自分以外のジョブ実行中の
runnerにログインできてはいけない
© DeNA Co., Ltd.
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/47Z1YLNRJ3.jpg)

how
●
debug-action (次で説明)
○
●
runnerにsshできる機能
uptermを使ってsshログイン
できる
○
認証つきリンク+自分の
GitHub用SSH鍵
●
tmuxにつながる
© DeNA Co., Ltd.
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/YJ6LDW81EV.jpg)

how
runner
●
debug-actionの仕組み
●
OSSを改造して利用している
○
●
tmux
job
tmux
upterm
sh
sshd
tmux attach
owenthereal/action-upterm
tmuxでセッションを作り、
ssh後にセッションにアタッチ
●
ジョブ進行と独立にuptermを起動する
目的でもtmuxを使っている
client (your pc)
terminal
ssh
© DeNA Co., Ltd.
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/GJ513M9L74.jpg)

how
●
sshできる環境なら、通常はport forwardingを使ってVNCできるはず
○
ssh -L5901:127.0.0.1:5900 -l account host
○
VNCはTCP 5900を使って接続するので、リモートの5900向けの接続を
ローカルの5901からできるようにforwarding
●
upterm経由ではport forwardingが未実装、実行コマンドもtmuxに固定
●
標準入出力を使ってport forwardingできるツールを使えないか?
○
nc (netcat)
○
socat (SOcket CAT)
■
socatで通常のssh経由でVNCトンネルする場合
■
socat TCP-LISTEN:5901,fork,bind=127.0.0.1 \
&quot;SYSTEM:ssh host &#039;socat STDIO TCP:127.0.0.1:5900&#039; &quot;
© DeNA Co., Ltd.
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/9E21Z923JR.jpg)

try
●
debug-action改造しリモートでsocatを動かす
runner
tmux
job
VNC
server
upterm
5900
command: &quot;socat STDIO TCP:127.0.0.1:5900&quot;
●
手元ではsocatからsshを起動
socat
sshd
socat \
TCP-LISTEN:5901,fork,bind=127.0.0.1 \
&quot;SYSTEM:ssh -tt \
&#039;～～:～～@actions-uptermd.dena.com&#039; &quot;
●
この状態でVNCを起動
open vnc://localhost:5901/
●
client (your pc)
VNC
client
socat
ssh
5901
VNC接続できない
© DeNA Co., Ltd.
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/D7YZR4Y8JM.jpg)

investigate
●
通信をWiresharkで見てみる。sshトンネルでVNCできた場合と比較すると
debug-action経由
VNCできない場合
sshトンネルでVNCできた場合の
リモートからの通信内容
© DeNA Co., Ltd.
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/VEN3DYP9E8.jpg)

investigate
●
通信をWiresharkで見てみる。直接VNCする場合と比較すると
debug-action経由
VNCできない場合
0a が 0d 0a に
化けている!
sshトンネルでVNCできた場合
© DeNA Co., Ltd.
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/Y799GP3373.jpg)

understand
●
なぜ化けるのか
●
uptermの仕組み
© DeNA Co., Ltd.
○
https://upterm.dev/ より
○
とくに化けそうな要素はない
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/G789VDMLJD.jpg)

understand
●
なぜ化けるのか
●
uptermの仕組み
○
https://upterm.dev/ より
○
とくに化けそうな要素はない
host
sshd
upterm host bash
ssh client
tunnel
tunnel
uptermd
proxy
sshd
client
ssh client
© DeNA Co., Ltd.
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/L7LW5M3QER.jpg)

understand
runner
●
tmux
debug-actionの仕組み再掲
job
●
どこで化けるのか
tmux
upterm
sh
sshd
tmux attach
client (your pc)
terminal
ssh
© DeNA Co., Ltd.
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/4EM93YMK7W.jpg)

reason
runner
●
どこで化けるのか
●
ptyが介在している
●
pty (一般的にtty)がする仕事
●
○
0a を 0d 0a にしてくれる
○
行編集
○
エコーバック
○
Control-CをSIGINTに変換
ttyの挙動はsttyコマンドで変えられる
○
© DeNA Co., Ltd.
stty -icanon -echo -nlcr -isig
tmux
job
tmux
upterm
sh
pty
sshd
tmux attach
pty
client (your pc)
terminal
ssh
pty
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/PERGQ9V679.jpg)

reason
runner
●
debug-action改造でsocatを動かす
○
●
●
tmux
使っていないtmuxのために
job
VNC
server
upterm
uptermの制約でsshにptyが必要
○
gosshを使ってsshdを自作している
○
ssh -tt ～～@～.dena.com
sshd
socat
pty
socat実行直前にstty -icanon -echo -nlcrなど試したがダメ
○
なぜダメだったのかはナゾ
pty変換に耐性のあるsocatもどきを
client (your pc)
VNC
client
socat
ssh
自作すればいいじゃない!
© DeNA Co., Ltd.
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/P7XX5QZD7X.jpg)

vibe
●
ttyで化けそうなバイトをエスケープするトンネル
○
transと命名
■
○
github.com/mad-p/trans
trans := transparent + transport
●
encode/decode
ソ
ケ
ッ
ト
パ
イ
プ
●
encode
decode
ssh
tty
Claude Codeで瞬殺
○
© DeNA Co., Ltd.
プロンプト trans.txt
標
準
入
出
力
encode
decode
ソ
ケ
ッ
ト
以下のようなプログラムを考えます。 sttyによって cr/lfなどが混
乱する通信路を使って、 byte-transparentなTCPトンネルを提供し
ます
- 変換
- データのうち特定のバイト値にあるものをエスケープする
- 変換方法 1
- uuencode/uudecodeによって変換する
- 変換方法 2
- エンコード側 : 0x0d, 0x0a, 0x1c, 0x7f, 0x5cが
あったら、 0x5cの後にそのバイトを 16進数 2桁のアスキーコードで
出力する
- デコード側 : 0x5cが来たら、その後の 2バイトを 16進ア
スキーと見なし、元のバイトを復元する
- 送信側
- 指定された TCPポートで listenし、接続があったら acceptす
る
- TCPポートとの入出力を変換し、標準入出力へつなぐ
- 受信側
- 指定された TCPポートへ接続する
- TCPポートとの入出力を変換し、標準入出力へつなぐ
- TCPポートとの入出力は、 forkによって 2つのプロセスで実装して
もよい
- 送信 /受信の別、 TCPポート番号、変換方法はコマンド行オプショ
ンで指定する
このようなプログラムを Cで書いてください。
エンコード /デコード部分は単体テストも書いてください。
---- systemするオプションを追加してください
- ポートに転送する標準入出力を外部コマンドに接続できるよ
うにしてください
- 外部コマンドは execveするのではなく、 systemのように
シェル経由がよいです
- 標準エラー出力はそのまま、現在の stderrに出力でよいです
- 動作モードのエイリアスとして to、fromを追加してください。 to
はconnectする側、 fromがlistenする側です
- --hostのデフォルト値を `127.0.0.1` としてください
- recvは、ポートに新しい connectionが来るたびに、新しく
acceptしたソケットに対してコマンドを起動するように修正してく
ださい
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/37KW698D7D.jpg)

socket &amp; pipe
●
●
ソケットとパイプを使う場合のコツ
○
バッファリングがある
○
入出力はブロックするかもしれない
4つのfd入出力を監視
めんどう。バグの元 ssh側
VNC側
ソ
ケ
ッ
ト
selectでどのfdが準備OKか見て
送信と受信を別プロセスでやるとよい
○
2回forkする
○
fork後は使わないfdのcloseを
忘れないこと
© DeNA Co., Ltd.
パ
イ
プ
fork
利用
処理するのは大変
○
encode
decode
VNC側
ソ
ケ
ッ
ト
ssh側
encode
decode
パ
イ
プ
2つのfd、2組
単方向でシンプル
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/LJ316W2PE5.jpg)

struggle
●
sshで実験するとつながらない
●
調査のため、16進ダンプログ機能追加
●
○
ダンプログ比較ツール作成
○
8つのストリームは2つずつ一致するはず
VNC
server
5900
sshd
trans
pty
encode/decodeが逆!
○
●
開発PC1
プロンプトに方向明示してなかった
byte transparentになっていないことが判明
© DeNA Co., Ltd.
○
いったんVNCは忘れて透過性を確保
○
trans経由でsshできることをゴールに
開発PC2
VNC
client
trans
ssh
5901
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/8JDXVKZ37G.jpg)

struggle
開発PC
●
いったんVNCは忘れて透過性を確保
○
●
trans経由でsshできることをゴールに
sshd
●
./trans -m from -p 20022
-s &quot;ssh -tt -e none localhost
&#039;stty raw -icanon -echo; \
./trans -q -m to -p 22 -d 1&#039; &quot;
ssh -p 20022 localhost
●
PCが1台で開発を進められる
●
sshは暗号化するのでバイト値0～255がまんべんなく来そう
○
© DeNA Co., Ltd.
trans
pty
22
直接ssh
trans経由
ssh
ssh
-p 20022
trans
ssh -tt
20022
byte透過でないと復号に失敗し、sshが切れてくれるので検出しやすい
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/VEPPVKDPE8.jpg)

trouble shooting
開発PC
1.
○
2.
3.
④
blocking I/O: 短い送信が来ないで止まる
sshd
エスケープシーケンスとバッファ境界で化け
22
リモートのstty設定前にechoされる (右図)
○
ローカルsshは①接続後すぐしゃべる
○
リモートは③でstty設定変更するが、
それ以前に届いた分がechoされちゃう
○
解決: ローカル側transで数秒待つ
○
./trans -m from -p 20022 -d 8
trans
pty
⑤
O_NONBLOCKとpollを利用
直接ssh
trans経由
ssh
ssh
-p 20022
③
trans
①20022
ssh -tt
②
-s &quot;ssh -tt -e none localhost &#039;stty raw -icanon -echo; ./trans -q -m to -p 22 -d 1&#039; &quot;
sshできた == byte transparent
© DeNA Co., Ltd.
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/27V2ZV1V7Q.jpg)

VNC protocol
VNC
client
●
やっぱりなんかつながらない
○
VNCはTCP接続を3往復している (右図)
●
transでは接続のたびにsshし(8秒待って)
トンネルを作っている
○
接続
パスワード入力画面までは進む
●
●
VNC
server
めんどくさい
解決: transを使ってsshを通し、
そのsshのport forwardを使う
セキュリティタイプリスト
×
接続
セキュリティタイプリスト
×
パスワード入力
接続
セキュリティタイプリスト
セキュリティタイプ選択
通信開始
© DeNA Co., Ltd.
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/5JGR4L217L.jpg)

permission
●
ローカルPC間ではtrans+sshでVNCできたが、
ランナーでは「画面共有が許可されていません」
●
設定の「一般 → 共有 → 画面共有」を
オンにする必要がある
●
CLIでできないか調べたが無理そう
○
ぐぐるとkickstartなどヒットするが、
OSのバージョン更新で使えなくなっている
○
●
なんとかなったとしても後の更新で変わるかも
ランナーVM作成時にpackerでGUI操作して設定
© DeNA Co., Ltd.
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/47QVGYPNEP.jpg)

success
runner
VNC
server
tmux
job
upterm+ssh
5900
upterm
sshd
trans
ssh port fw
trans
pty
sshd
VNC
client (your pc)
VNC
client
ssh
5901
© DeNA Co., Ltd.
trans
ssh
20022
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/KE4M5WY371.jpg)

use
●
ジョブ内でtransをcloneしてビルド
●
- name: SSH Debug
uses: gha-runner/debug-action@pr/175
with:
command: |
chmod 600 ~/.ssh/config
stty raw -icanon -echo
$HOME/trans -q -m to -p 22
●
●
●
●
make tunnel HOST=&lt;コピーしたssh先&gt;
作ったトンネルを使ってVNCをポートforward
○
make ssh-runner
○
8秒くらいかかってパスワードを聞かれる
make vnc
○
●
3つのターミナル画面が必要
トンネルを起動
○
ssh先の部分をコピー
© DeNA Co., Ltd.
ローカルPCからtransでVNC接続
○
ジョブのログを開きSSH Command が
表示されるまで待つ
●
●
ユーザー名、パスワードを入力して接続
参考: Makefile
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/L718WY6ZJG.jpg)

technology
●
stty raw -icanon -echo
●
escape/unescape、uuencode/uudecode
●
socket listen/connect/accept/shutdown/close
●
pipe/dup2、fork/exec、stdin/stdout
●
select/poll/fcntl/EAGAIN/EWOULDBLOCK
●
Wireshark/protocols
© DeNA Co., Ltd.
○
TCP/SYN/ACK/FIN
○
SSH
○
VNC
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/G7WZ6GW672.jpg)

summary
●
●
●
macOSランナーにVNCを通したい
○
uptermでsshはできる
○
なぜかssh port forwardingできない
○
なぜかsocatでうまくいかない
トンネルツール「trans」を作った
○
うまくいくまでいろいろ調べて対策した
○
調査では16進ダンプやWiresharkを活用できた
低レイヤは面白いですね!
© DeNA Co., Ltd.
upterm+ssh
trans
ssh port fw
VNC
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/4JZ1YL5RE3.jpg)

© DeNA Co., Ltd.
27


