出先のスマホから、PCのClaude Codeを設定まで含めて操作する(tmux + mosh)

あるXのポストに、こんな趣旨の不満が書かれていた。公式のスマホアプリからClaude Codeに指示は出せる。ただ、一部の設定やコネクターの再認証のときは、PCのターミナルに戻らされる。外出先でも、そこまでアプリの中で済ませたい、という内容だった。 私は、この不満が出る形とは別のやり方で使っている。アプリを経由せず、Claude Codeが動いている端末の画面そのものを、スマホで開く。 この記事では、その仕組みと弱点を書く。 何をしているか PCの端末(ターミナル)の中でClaude Codeを動かしている。その端末の画面を、スマホから、そのまま開いている。 スマホ側では、a と打つだけで、PCのClaude Codeの画面に入る。PCの前に戻ったら、cc と打てば、同じ画面が出る。どちらから入っても、同じ画面に入る。会話の途中のまま、続けられる。 端末の画面そのものなので、設定の変更も、再認証も、PCで打つのと同じコマンドを、スマホで打てる。戻る場所が、そもそも無い。 使っているもの 名前 役割 tmux 端末の中身を保つ。画面を閉じても、接続が切れても、中の作業が残る。あとで同じ画面に入り直せる mosh SSHの仲間。Wi-Fiが変わる、スマホがスリープする、といった回線の切れ目があっても、つなぎ直さずに続く SSH(鍵認証) PCに入るための入口。パスワードでのログインは切って、鍵だけにしている Tailscale 外から自宅のPCに届く経路(VPN) Termux スマホ(Android)側の端末アプリ。ここでmoshを動かす 流れは、こうなる。 スマホのTermuxで a と打つ。これは、mosh でPCに入り、tmuxの dev というセッションに入る、という命令の短縮(エイリアス)。 SSHでPCにつないだあと、mosh-serverがその場で起動して、UDPで、つなぎ直す。 tmuxの dev に入る。そこで、Claude Codeが動いている。 PCの前では、cc で、同じ dev に入る。cc は、tmux new -A -s dev(あれば入る、無ければ作る)の短縮にしてある。 つまずいた点 mosh-serverは、常駐しない。 つなぐたびに起動する。誰もつないでいないときに動いていないのは、正常。 moshの -p は、SSHのポートではなく、mosh自身のUDPポート。 SSHのポートを変えているなら、--ssh="ssh -p ポート番号" の形で渡す。 ロケールが無いと、moshが接続に失敗する。 UTF-8のロケールが必要で、PC側で生成しておかないと、「needs a UTF-8 locale」で止まる。 スマホのTermuxは、Androidに、バックグラウンドで止められることがある。 接続が切れたら、Termuxを開き直す。 弱点 PCが起きていることが前提。 落ちているときは、家のNASから、Wake-on-LANで起こしている(wake-arch という命令にしてある)。 PCを再起動すると、tmuxごと消える。 dev セッションも、中で動いていたClaude Codeも、再起動のたびに作り直しになる。電源が切れていたPCをWake-on-LANで起こした場合も、同じ。会話は、Claude Code側の --continue で、続きから再開できる。 画面が小さい。 長い出力を読むのは、スマホでは辛い。長い出力は、ファイルに書かせて、あとで読む。 日本語の入力は、端末アプリ越しだと、PCの前より手間がかかる。 公式アプリとは、役割が違う。 通知や、アプリの画面での確認は、アプリの方が楽。私は、Remote Control(公式アプリからの指示)も有効にしてあり、必要に応じて使い分けている。 まとめ 公式アプリで足りない場面(設定、再認証)は、端末の画面を、そのままスマホで開けば、戻らずに済む。 必要なのは、tmux、mosh、PCに届く経路、鍵認証のSSH。 弱点は、PCが起きている必要があること、画面が小さいこと。 セキュリティ面では、SSHをパスワードなし(鍵認証のみ)にして、外からは、VPN経由でしか入れない形にしておくのが前提になる。この記事では、ポート番号やアドレスなど、環境の具体的な値は書いていない。

sudoersのNOPASSWDを絞り込んだら、PCが2回勝手に落ちた話

sudo systemctl restart bluetoothと打ったら、パスワードを聞かれずに通った。何かがおかしい。ここから、GTFOBinsの調査、SSH鍵の作り直し、rrsyncとの格闘、そしてOpenSSHのソースコードを読むところまで進んだ調査の記録。最後には、原因が分からないままPCが2回勝手に落ちるという、後味の悪いオチが付く。 きっかけ: パスワードを聞かれない Bluetoothの調子が悪くてsudo systemctl restart bluetoothを打った。いつもならパスワードを聞かれるはずが、そのまま通った。直近でsudoを使った覚えもない。おかしいと思ってsudo -n -l(パスワード無しで、自分に許可されているsudoコマンドを一覧表示する)を叩いてみた。 ユーザー takashi は takashi-pc 上で コマンドを実行できます (ALL : ALL) ALL (root) NOPASSWD: /usr/bin/rsync, /usr/bin/systemctl, /usr/bin/poweroff Copy /etc/sudoers.d/配下に、rsync・systemctl・poweroffの3つが、パスワード無しで、引数を問わず実行できる設定が入っていた。 GTFOBinsで確認した危険性 GTFOBinsは、Unix系のバイナリを悪用した権限昇格の手口をまとめたデータベースだ。systemctlとrsyncのページを見ると、この設定がどれだけまずいかがすぐ分かる。 systemctl: 自分でsystemdのサービスファイルを作り、systemctl link→systemctl enable --nowで登録・起動すれば、そのサービスはroot権限で動く。あるいはSYSTEMD_EDITOR環境変数に自分のスクリプトを指定した状態でsystemctl editを叩くと、そのスクリプトがrootで呼ばれる。 rsync: --rsh(または-e)オプションで、任意のコマンドを「リモートシェル」として起動できる。sudo rsync -e /bin/sh ...のような形で、rootのシェルを直接取れる。 つまりこの設定は、一般ユーザーのまま実質rootになれる、という状態だった。poweroffだけは被害が限定的(シャットダウンのみ)だが、残り2つは深刻。 誰がこれを使っていたのか このPCで動いている自動化を一通り確認したが、systemd timerにもcronにも、この3つのNOPASSWDに依存しているものは見当たらなかった。 答えは、別のマシン(自宅のミニPC、以下NAS)側にあった。backup-archという、このPCの/home /boot /etcを毎晩NASへrsyncでバックアップするスクリプトが、SSH経由でこのPCに対してsudo rsyncを実行していた。バックアップ完了後、sudo systemctl stop/startでコンテナを一時停止する処理と、sudo poweroffで自動シャットダウンする処理も持っていた。 backup-archの最初のコミットは2025年10月。当時はコーディングエージェントに書かせたもので、SSH経由のsudo実行を前提にした設計だった。systemctlを使っていた「バックアップ前後にコンテナを止める」処理は、後になって「そもそも止める対象がバックアップ範囲に含まれておらず、意味が無かった」という理由で既に削除されていたが、sudoers側の許可だけが広いまま残っていた。 絞り込みの設計: rrsyncとSSH強制コマンド rsyncとsystemctlのNOPASSWDを外し、その代わりに、必要な操作だけをできる形に絞り込むことにした。 rsyncにはrrsync(restricted rsync)という、rsync本体に同梱されている補助スクリプトがある。SSHのauthorized_keysで、特定の鍵に対してcommand="rrsync -ro /path/to/dir"のように強制コマンドを指定すると、その鍵で接続してきたクライアントが何を要求しても無視され、指定した1つのディレクトリへの読み取り専用アクセスだけが許可される。 ただしrrsyncは、1回の起動につき1つのディレクトリしか制限できない。今回は/home /boot /etcの3か所が必要だったので、ディレクトリごとに専用の鍵を1本ずつ、計3本作った。加えて、シャットダウン専用の鍵をもう1本。合計4本の鍵、それぞれに対応する強制コマンドをauthorized_keysに設定した。 command="sudo /usr/bin/rrsync -ro /home",restrict ssh-ed25519 AAAA... nas-backup-home command="sudo /usr/bin/rrsync -ro /boot",restrict ssh-ed25519 AAAA... nas-backup-boot command="sudo /usr/bin/rrsync -ro /etc",restrict ssh-ed25519 AAAA... nas-backup-etc command="sudo /usr/bin/poweroff",restrict ssh-ed25519 AAAA... nas-backup-poweroff Copy sudoers側も、引数まで完全一致させた形にする。 ...

Termux の sshd はどんなユーザー名でも同じユーザーで入れる ── ソースで確かめる

母艦から Pixel 6(Termux の sshd)へ画像を scp するために ~/.ssh/config に エントリを足したとき、User を書いた。あとで気づいたが、相手が Termux だと ssh banana@<phone> でも ssh root@<phone> でも、同じユーザーでログインできる。 ~/.ssh/config の User 行は効いていない。設定の問題ではなく、Termux の OpenSSH ビルドの話だった。 まず観察 $ ssh -p 8022 banana@100.65.202.69 'whoami' u0_a440 $ ssh -p 8022 root@100.65.202.69 'whoami' u0_a440 Copy banana も root も通って、着地するのは u0_a440(Termux アプリのユーザー)。 鍵は /data/data/com.termux/files/home/.ssh/authorized_keys だけを見ている。 通常の OpenSSH がユーザーをどう解決するか sshd は、接続してきたユーザー名を struct passwd に解決する。これをやるのが auth.c の getpwnamallow()。素の OpenSSH ではこう: pw = getpwnam(user); Copy user はクライアントが送ってきた名前。それを /etc/passwd(実際には NSS 経由で LDAP / SSSD なども)で引く。 ...

AWSでSSH接続できない問題を解決した話

はじめに 先日、AWSで立てたEC2インスタンスにSSH接続できなくなる問題が発生しました。このトラブルの原因と解決方法を記録しておきます。同じ状況に陥った方の助けになれば幸いです。 問題の症状 EC2インスタンスにSSH接続を試みると、Connection timed out のエラーが表示される。 AWSコンソール上では、インスタンスは正常に動作中。 ブラウザからの接続は可能(インスタンス内のApacheは稼働中)。 トラブルシューティングの進め方 問題解決のため、まずはSSH接続ができない間もAWS System Managerの「セッションマネージャー」を利用しました。System Managerを活用することで、インスタンスの内部に直接ログインでき、次のような確認や操作が可能になりました: ファイアウォール(UFW)の状態確認 sudo ufw status Copy SSHサービスの状態確認 sudo systemctl status ssh Copy System Managerは、セキュリティグループやファイアウォールの設定ミスが原因でSSH接続ができなくてもインスタンス内部にアクセスできるため、非常に有用です。 原因と解決方法 調査の結果、以下の4つの原因が考えられました。 原因1: セキュリティグループのルール設定ミス 問題点 セキュリティグループでポート22(SSH)が許可されていなかった。 解決方法 AWSコンソールのセキュリティグループ設定に以下のルールを追加: タイプ: SSH プロトコル: TCP ポート範囲: 22 ソース: 自分のグローバルIPアドレス(例: 203.0.113.0/32) 原因2: UFW(Uncomplicated Firewall)がポート22を閉じていた 問題点 EC2インスタンス内のUFW(ローカルファイアウォール)でポート22が閉じられていた。 解決方法 以下のコマンドを実行してポート22を許可し、設定を反映しました。 sudo ufw allow 22 sudo ufw reload Copy 原因3: グローバルIPの変動 問題点 自分のグローバルIPアドレスが変更されたことで、セキュリティグループのルールが機能しなくなった。 解決方法 新しいグローバルIPを確認し、セキュリティグループのSSHルールを更新しました。 curl ifconfig.me Copy 原因4: インターネットゲートウェイの設定ミス 問題点 インターネットゲートウェイがVPCに正しくアタッチされていなかった。 解決方法 AWSコンソールのVPCダッシュボードで以下を確認しました: ...