Joifup Blog

Tailscale × NeoServerでiPhoneリモート開発環境を構築―ハマった4つの落とし穴と解決策

2026-02-05

TailscaleSSHtmuxClaude Code

はじめに

この記事では、iPhoneから自宅のMacにリモート接続してClaude Codeで開発する環境の作り方と、構築中にハマった4つの問題の解決策を紹介します。

外出先やスマホから軽く個人開発を進めたいエンジニア向けの内容です。

電車での移動中とか、休日にPCの前に座る気力はないけど「スマホで軽く進めるか〜」みたいなとき、ありませんか。自分はずっとスマホからの開発に興味があったんですが、現実的にスマホのターミナルでコードを書くのは無理がありました。ただ、Claude Codeの登場で状況が変わりました。自然言語で指示を出せるなら、スマホからでもいけるんじゃないかと。

構築にあたっては、以下のZenn記事を参考にさせていただきました。基本的な手順はこちらが詳しいです。

外出先のiPhoneから自宅MacのClaude Codeを操作する方法|Tailscale × NeoServer × tmux

この記事では、上記を参考に実際に構築してみてハマったポイントに焦点を当てて書いていきます。

構成の全体像

今回構築した環境の全体像はこんな感じです。

iPhone (NeoServer)
SSH over Tailscale VPN
自宅 Mac
    └── tmux セッション
         └── Claude Code

使うツールは3つだけです。

  • Tailscale: VPNでiPhoneとMacを同じネットワークに繋ぐ
  • NeoServer: iPhone用のSSHクライアント
  • tmux: ターミナルのセッション管理(接続が切れても作業が消えない)

Tailscaleを使うことで、外出先からでもVPN経由で自宅のMacに直接SSH接続できます。tmuxでセッションを維持しておけば、接続が不安定になっても途中から再開できます。

環境構築の手順

1. Tailscaleのインストールと接続

Tailscaleは、面倒なVPN設定なしでデバイス同士を繋いでくれるサービスです。

Mac側はHomebrewでインストールします。

brew install --cask tailscale

iPhone側はApp Storeから「Tailscale」をインストール。

両方で同じGoogleアカウント(またはその他の認証方法)でログインするだけで、VPN接続が完了します。設定ファイルをいじったりする必要はありません。

2. Mac側のSSH有効化

MacはデフォルトだとSSH接続を受け付けていません。システム設定 > 一般 > 共有 > リモートログイン をONにする必要があります。

これが有効になっていないとSSH接続できないので、事前に確認しておくと良いです。自分はOFFになっていました。

3. NeoServerからSSH接続

iPhone側にNeoServerをインストールし、Tailscale経由でMacにSSH接続します。

SSHクライアントはNeoServer以外にもTermiusやnagiといった選択肢がありますが、今回は参考記事に倣ってNeoServerを使いました。

接続の流れとしては、まずユーザー名/パスワード(Macのログイン情報)で接続し、動作確認ができたらSSH鍵を設定してパスワードなしで接続できるようにします。詳細な手順は参考記事に譲ります。

4. tmuxのセットアップ

tmuxはターミナルのセッション管理ツールです。SSH接続が切れてもセッションが維持されるので、再接続すれば途中から作業を再開できます。スマホからの接続は不安定になりがちなので、tmuxは必須です。

自分は以前Neovimを使い始めた頃に少しだけ触ったことがありましたが、結局ターミナルアプリのペインとタブ機能を使っていたので、ほぼ忘れていました。今回改めてキャッチアップし直しました。

最低限覚えておくと良いコマンドだけ載せておきます。

# 新しいセッションを作成
tmux new -s dev

# セッションから抜ける(セッションは維持される)
# デフォルトの場合: Ctrl+b → d(プレフィックスキーを変更している場合は読み替えてください)

# セッションに再接続
tmux attach -t dev

ハマった4つの落とし穴と解決策

ここからが本題です。参考記事の通りに進めれば基本的にはスムーズですが、自分は4箇所でつまずきました。

落とし穴1: SSHが繋がらない

NeoServerからMacに接続しようとしても、反応がない。

以下のコマンドでMac側のSSH待ち受け状態を確認したところ、何も返ってきませんでした。

sudo lsof -nP -iTCP:22 -sTCP:LISTEN

原因はシンプルで、Macのリモートログインが無効だっただけです。前述の通り、システム設定 > 一般 > 共有 > リモートログインをONにしたら接続できるようになりました。

落とし穴2: パスワードが通らない

SSHの接続画面でユーザー名とパスワードを入力するんですが、何を入れても弾かれる。

「SSH用のユーザーとパスワードを新しく作るのか?」と思っていたんですが、違いました。普段Macにログインするときのユーザー名とパスワードをそのまま使うだけでした。勘違いしていて少し恥ずかしかったです。

落とし穴3: Claude Codeで「Missing API key」エラー

SSH接続してClaude Codeを起動すると、Missing API key · Run /login というエラーが出ました。Macのターミナルから直接起動すると問題ないのに、SSH経由だとダメ。

これはSSH経由だとmacOSのKeychainにアクセスできないことが原因でした。Claude Codeの認証情報はKeychainに保存されているので、まずKeychainのロックを解除する必要があります。

security unlock-keychain ~/Library/Keychains/login.keychain-db

このコマンドを実行してMacのログインパスワードを入力すると、Keychainがアンロックされて、Claude Codeが正常に起動するようになりました。

ChatGPTに聞いたらすぐ回答が返ってきて、実行したら解決しました。ここはそこまでハマってはいません。

落とし穴4: tmuxで日本語が全部「__」になる

これが少しだけ厄介でした。

tmuxを起動して日本語を入力すると、すべてアンダースコア2つ(__)に置き換わるという現象が起きました。

最初は文字化けかと思いましたが、文字化けにしては表示がおかしい。__って何だという感じでした。

ここからChatGPTと一緒に原因を切り分けていきました。

切り分け1: locale(文字コード設定)の確認

まず疑ったのはlocale。UTF-8になっていないのでは?

locale

結果は LANG=ja_JP.UTF-8LC_CTYPE=ja_JP.UTF-8。問題なし。

printf "日本語テスト\n" も正常に表示されました。localeは無罪です。

切り分け2: 入力が壊れているのか、表示が壊れているのか

次に、そもそもiPhoneから送った文字が正しくMacに届いているのかを確認しました。

cat > /tmp/jp.txt
# 日本語を入力してCtrl+D

xxd /tmp/jp.txt

バイト列を見ると e3 81 ... のUTF-8バイト列が確認できました。入力はちゃんとUTF-8で届いている

つまり壊れているのは入力ではなく、端末(TTY)の解釈側です。

切り分け3: sttyの確認(ここが犯人)

TTYの設定を確認してみました。

stty -a

出力の中に -iutf8 という表示がありました。先頭のハイフンは「OFF」を意味します。

iutf8 は、このTTY(端末接続)がUTF-8を扱うかどうかをカーネルに伝えるフラグです。これがOFFだと、tmuxは「この端末はUTF-8に対応していない」と判断して、日本語のようなワイド文字を __ のような代替表示に置き換えます。

解決: stty iutf8

修正は1コマンドです。

stty iutf8

これを実行した瞬間、tmux内の日本語が正常に表示されるようになりました。

なぜNeoServerからだと iutf8 がOFFになるのか

Macのターミナルの場合はこの問題は起きません。iutf8は通常ONになっているからです。

NeoServer(iPhone)からSSH接続した場合、端末のTTY属性として iutf8 が設定されないことがあるようです。これはSSHクライアント側が端末情報をどう伝えるかに依存しており、NeoServer固有の挙動と言えます。

ポイントは、localeとTTYのiutf8は別のレイヤーだということです。

  • locale(LANG, LC_CTYPE): アプリが文字をどう解釈するか → 今回はUTF-8で正常だった
  • stty iutf8: カーネル/TTYが入力をUTF-8として扱うか → OFFだった(これが原因)

localeが正しくても、TTY側がUTF-8と認識していなければ、tmuxのような端末マルチプレクサは正常に動作しません。

永続化

stty iutf8 はセッション単位の設定なので、SSH接続するたびにリセットされる可能性があります。~/.zshrc に以下を追記して永続化しておきます。

# Ensure UTF-8 tty mode (fixes NeoServer/iOS SSH + tmux Japanese)
if [[ -t 0 ]]; then
  stty iutf8 2>/dev/null
fi

[[ -t 0 ]] は標準入力がTTYの場合のみ実行する条件です。スクリプト実行時など、TTYが接続されていない場合にエラーが出るのを防ぎます。

使ってみた感想

環境が整ったので、実際にiPhoneからClaude Codeで開発してみました。

まだ慣れてはいないですが、割と使っていけそうな感触です。コードを直接書くわけではなく、Claude Codeに自然言語で指示を出すスタイルなので、スマホのソフトウェアキーボードでも意外とストレスが少ないです。

ただ、tmuxのキーバインド入力は少しコツがいりそうです。

SSHクライアントについては、今回はNeoServerだけ試しましたが、今後時間があるときにnagiも試してみようかなと思っています。

まとめ

  • Tailscale × NeoServer × tmuxでiPhoneからMacにSSH接続してClaude Codeを動かす環境を構築しました
  • 環境構築自体はシンプルですが、SSHのリモートログイン設定、Keychainのアンロック、tmuxの日本語表示問題など、いくつか落とし穴があります
  • 特にtmuxで日本語が __ になる問題は、localeではなくTTYの iutf8 フラグが原因でした。stty iutf8 で解決します

参考記事: