iSHにSSH接続してiPhoneでClaude Codeを動かす

iPhoneのファイルアプリに溜まった画像やPDFや音源を整理したかったのですが、iPhoneの画面で1個ずつ長押しして移動するのが面倒すぎて放置していました。結局、iSHでSSHサーバーを立ててPCから接続し、PC側のClaude Codeにコマンドを投げてもらう形で片付けたので、その手順を書いておきます。

前提として、iSHの入れ方とファイルアプリのフォルダをマウントする話は前の記事に書いたので、そちらを先に読んでもらうと早いです。この記事はその続きで、マウントしたフォルダに外から入る方法です。

自分の環境は以下です。

  • iPhone
  • iSH(App Store版、中身はAlpine Linux 3.14、OpenSSH 8.6p1)
  • PC側はMac(Claude Codeが動くならWindowsでもLinuxでも同じはずです)
  • iPhoneとPCは同じWi-Fiに接続

iSH側でsshdを起動する

opensshを入れる

apk add opensshでクライアントとサーバー(sshd)の両方が入ります。前の記事でSSH鍵を作るために入れていれば、そのままで大丈夫です。

apk update
apk add openssh

ホスト鍵を作る

sshdはサーバー用のホスト鍵がないと起動しません。普通はssh-keygen -Aで全種類まとめて作るのですが、iSHでやると最初のRSA鍵の生成で止まったまま一向に終わりませんでした。

~ # ssh-keygen -A
ssh-keygen: generating new host keys: RSA

エミュレータ上でRSAの鍵生成が重すぎるんだと思います。なのでed25519の鍵だけ手で作って、それを使うようにsshd_configに書くことにしました。こちらは一瞬で終わります。

ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""

rootのパスワードを設定する

iSHの中では最初からrootなのですが、パスワードが設定されていないのでSSHでログインできません。passwdで設定します。

passwd

sshd_configを編集する

/etc/ssh/sshd_configをviで開いて、さっき作ったホスト鍵の指定、ポート、rootログインの許可の3行を書きます。

vi /etc/ssh/sshd_config
HostKey /etc/ssh/ssh_host_ed25519_key
Port 2222
PermitRootLogin yes

iで入力モード、書き終わったらEscを押して:wqで保存です。既存の行がコメントアウトされているならそれを直してもいいですし、ファイルの末尾に足しても動きます。自分は面倒だったのでecho "Port 2222" >> /etc/ssh/sshd_configのように末尾に追記しました。

PasswordAuthenticationはデフォルトでyesなので触らなくて大丈夫です。

ポートはデフォルトの22ではなく、2222のようなウェルノウンポート以外にしておきます。22のままだとiOS側で既に使われていて起動に失敗することがありますし、同じWi-Fiに知らない端末がいるときに真っ先に叩かれるポートでもあるので、変えておいて損はないです。

sshdを起動する

Alpineなので普段ならrc-service sshd startですが、iSHではOpenRCがまともに動かないので直接実行します。

/usr/sbin/sshd

何も表示されなければ起動しています。psでsshdが見えればOKです。

iSHを終了するとsshdも止まるので、起動のたびに実行する必要があります。毎回打つのが面倒なので、自分は~/.profileに書いて自動で上がるようにしました。

vi ~/.profile
/usr/sbin/sshd

iSHは起動時にログインシェルとして~/.profileを読むので、これでiSHのアプリを開いた時点でsshdが立ち上がります。実際にアプリを終了して開き直したら、何も打たなくてもPCから繋がりました。すでに起動済みのときに二重に実行してもポートが使用中で失敗するだけなので気にしなくて大丈夫ですが、気になるならpidof sshd >/dev/null || /usr/sbin/sshdとしておけば二重起動しません。

iPhoneのIPアドレスを調べる

iSHの中でip addrやifconfigを打ってもiOS側のネットワーク情報は取れません。

~ # ip addr
ip: socket(AF_NETLINK,3,0): Invalid argument
~ # ifconfig
ifconfig: /proc/net/dev: No such file or directory

iPhoneの「設定」→「Wi-Fi」→接続中のネットワークの「i」ボタンを開くとIPアドレスが出るので、それを使います。

DHCPで毎回変わるとつなぎ直すのが面倒なので、ルーター側でiPhoneのIPを固定しておくと楽です。

PCからSSH接続する

PCのターミナルから、さっき調べたIPに向かってrootで接続します。

ssh -p 2222 root@192.168.1.23

ポートを変えているので-p 2222を忘れずに付けます。初回はAre you sure you want to continue connectingと聞かれるのでyes、その後にpasswdで設定したパスワードを入れればiSHのシェルに入れます。

毎回パスワードを打つのも面倒なので、PC側の公開鍵を送っておきます。

ssh-copy-id -p 2222 root@192.168.1.23

これで次からはパスワードなしで入れます。鍵を入れたあとはsshd_configのPasswordAuthenticationをnoに戻しておいたほうが安心です。

毎回-p 2222を打つのも面倒なので、PC側の~/.ssh/configに書いておくとssh iphoneだけで入れます。

Host iphone
  HostName 192.168.1.23
  Port 2222
  User root

ファイルアプリのフォルダをマウントしておく

SSHで入ってもiSH側のファイルシステムしか見えないので、整理したいフォルダは前の記事と同じ方法でマウントしておきます。自分はホームの下にmntを作って、「このiPhone内」と「iCloud Drive」をそれぞれマウントしています。

mkdir -p ~/mnt/ios ~/mnt/icloud
cd ~/mnt
mount -t ios . ios/      # フォルダ選択で「このiPhone内」を選ぶ
mount -t ios . icloud/   # フォルダ選択で「iCloud Drive」を選ぶ

mount -t iosはフォルダ選択のダイアログがiPhoneの画面に出るので、これだけはSSH越しではなくiPhone本体のiSHで実行する必要があります。一度マウントすればiSHを終了しても外れないので、最初の1回だけiPhoneを触ればあとはPCから触れます。

マウント済みかどうかはmountコマンドで確認できます。iOS側の実体のパスがそのまま出てくるのでちょっと面白いです。

~ # mount
/private/var/mobile/Containers/Shared/AppGroup/xxxx/File\040Provider\040Storage on /root/mnt/ios type ios (rw)
/private/var/mobile/Library/Mobile\040Documents/com~apple~CloudDocs on /root/mnt/icloud type ios (rw)

Claude Codeで整理する

ここからが本題です。自分はClaude CodeをiPhone側ではなくPC側で動かして、SSH越しにコマンドを実行してもらう形にしました。一応ダメ元でapk add claude-codeと打ってみましたがそんなパッケージはなく、iSHは32bitのx86エミュレータなので中でNode.jsを動かすのもかなり厳しいと思います。

PCで適当な作業用ディレクトリを作ってClaude Codeを起動し、だいたいこんな感じで頼みます。

ssh iphone でiPhoneに入れる(ポート2222、~/.ssh/config に設定済み)。
~/mnt/ios/Downloads の中にあるファイルを整理したい。
まず ls -la と find で中身を全部見せて。

Claude CodeはBashツールでssh iphone "find ~/mnt/ios/Downloads -type f"のようにコマンドを打って中身を把握してくれるので、あとは普通に指示するだけです。例えばこんな整理を頼めます。

  • ダウンロードフォルダに溜まった画像・PDF・zipを拡張子ごとのフォルダに分ける
  • IMG_1234.jpgみたいな名前の画像を、撮影日ベースの名前にリネームする
  • 同じ内容で名前だけ違うファイル((1)やコピーが付いたもの)をmd5sumで見つけて消す
  • 音源フォルダのファイル名の表記揺れ(全角スペースとか)を揃える

削除や一括リネームはいきなりやらせずに、まず「何をどう動かすか一覧にして」と頼んで、見てから実行させるようにしました。SSH越しなので間違えて消しても戻せません。

ハマったところ

遅い

iSHの中は何をやっても遅いです。特にmount -t iosで繋いだフォルダはfindやmd5sumがかなり時間がかかるので、Claude Codeに「1ファイルずつsshし直す」ような動きをされると待ち時間が辛いです。「まとめて1回のsshで実行して」と伝えておくとマシになりました。

iSHをバックグラウンドにすると接続が切れる

iOSはバックグラウンドのアプリを容赦なく止めるので、iPhoneでiSHを開いたまま他のアプリに切り替えるとしばらくしてSSHが切れます。PC側から見るとConnection refusedになって、iSHを開き直してsshdを起動するまで繋がりません。整理している間ずっとiSHを前面に出して画面も消さない、というのは正直つらいです。

これの対策として、iSHには/dev/locationという特殊なファイルがあって、これを読み続けていると位置情報サービスを使っている扱いになりバックグラウンドでも止められない、という裏技があります。

cat /dev/location > /dev/null &

初回は位置情報の許可ダイアログがiPhoneに出るので許可します。許可するまではcatが何も出力せずに待ち続けるので、ダイアログを見落とすと「動いてない?」と悩むことになります(自分は悩みました)。中身を見てみると、1秒くらいおきに緯度経度が1行ずつ流れてきます。

+35.681236,+139.767125
+35.681236,+139.767124
+35.681236,+139.767124

本当に効くのか気になったので、これを動かしたままiSHをホーム画面に戻して3分ほど放置し、PCから10秒おきにsshで繋いでみました。結果は3分間ずっと繋がったままで、/dev/locationの出力も途切れず増え続けていたので、ちゃんとバックグラウンドで生きていました。ついでに電源ボタンを押してiPhoneを完全にスリープさせた状態でも3分放置してみましたが、こちらも切れませんでした。スリープ中は位置情報の更新頻度が目に見えて落ちるのですが、プロセスが止まることはなかったです。さすがにアプリスイッチャーからiSHを終了させると即座にConnection refusedになるので、整理が終わるまでは終了させないようにしてください。

位置情報を取り続けるのでバッテリーは多少食うはずですが、整理している間だけ動かしておく分には問題ないと思います。ステータスバーに位置情報の矢印が出っぱなしになるので、終わったらpkill catで止めておけばいいです。

iCloud Driveのフォルダは中身が無いことがある

iCloud Driveのフォルダをマウントすると、iPhoneにダウンロードされていないファイルはサイズ0に見えたり読めなかったりします。iCloud上のものを整理したいときは、先にファイルアプリで該当フォルダを開いてダウンロードを済ませてからのほうが安全です。

ファイルアプリに反映されるまで少し待つ

SSHからmvやリネームをしても、ファイルアプリの表示がすぐに更新されないことがありました。一度ファイルアプリを閉じて開き直すと反映されます。

まとめ

  • apk add openssh、ホスト鍵はed25519だけ手で作る(ssh-keygen -AはRSAで止まる)、passwd、sshd_configにHostKeyとポート2222とroot許可、/usr/sbin/sshdで起動
  • ~/.profileに/usr/sbin/sshdと書いておけばiSHを開くだけで上がる
  • iPhoneのIPは「設定」→「Wi-Fi」で確認してssh -p 2222 root@<IP>
  • 整理したいフォルダはiPhone側でmount -t iosしておく(一度やれば外れない)
  • Claude CodeはPC側で動かして、ssh経由でコマンドを打ってもらう
  • cat /dev/location > /dev/null &を動かしておけばiSHを裏に回してもスリープしても切れない(それぞれ実測3分OK)
  • 削除やリネームは一覧を出させてから実行

iPhoneの画面でファイルをちまちま動かすのに比べると圧倒的に楽でした。iSHが遅いのが難点ですが、/dev/locationの裏技でバックグラウンドに回しても切れなくなったので、たまにやる整理なら十分です。