I wanted to pull out my phone on a train in Japan, reconnect to a dev session running on my Mac at home, and keep working. That is not such a strange thing to want anymore. But getting it to actually work, reliably, from a phone, without blowing up my existing setup, turned out to be the interesting part.
And then, right around the time I got it working, Claude Code shipped Remote Control and Dispatch. More on that later.
Why Not Just Use Tailscale?
If someone told me they wanted private remote access to their personal machine, I would probably tell them to use Tailscale and move on with their life. It is a great tool. For plenty of people it is the whole answer.
But my situation was a little stranger than that. My Mac runs a work VPN, and I did not want to mix personal and company Tailscale accounts on the same machine. I did not want to expose my home network to inbound connections from the public internet. And because I planned to use this from my phone, often on mobile data between Wi-Fi networks, I needed the connection to survive the kind of interruptions that kill a normal SSH session.
Any one of those constraints alone would be easy to work around. Stacked together, they started ruling out the cleaner-looking options. What remained was not the most elegant diagram. It was the version that actually fit.
The Shape of the Thing
The final setup is a chain, and each link exists for a specific reason:
flowchart LR
phone[Phone]
mosh[mosh]
vps[VPS]
reverse[reverse SSH]
mac[Mac]
tmux[tmux]
tools[Claude Code]
phone --> mosh --> vps --> reverse --> mac --> tmux --> tools
My phone connects to a small VPS using mosh, which handles the part that plain SSH is terrible at on mobile networks: changing IPs, switching between Wi-Fi and cellular, and recovering from drops without leaving you staring at a frozen cursor. The VPS is the only thing with a public address. My Mac reaches it through an outbound reverse SSH tunnel, which means the Mac never needs to accept inbound traffic from the internet at all. And tmux on the Mac turns the whole thing from a fragile connection into a persistent session I can detach from and come back to later.
That last part surprised me. Once the session itself became durable, the phone stopped feeling like a limited access path. I was not reconnecting to a machine. I was stepping back into work that was already in progress.
Where It Actually Broke
Most of what I learned came from the failures, not the original plan.
The reverse tunnel could go half-dead after sitting idle. Port 22 was still listening on the VPS. The connection looked fine. But the session behind it had quietly gone stale, so jumping to the Mac would just hang. What fixed it was not a single setting. It was treating liveness as a real concern on both sides. SSH keepalives from the Mac, autossh to rebuild the tunnel when it dropped, and a VPS-side script that checked whether localhost:22 was actually responsive before attempting the jump.
That jump script was its own lesson. The first version tried to SSH into the Mac every time I connected to the VPS. Fine when the tunnel was up. Completely useless when it was not, just a hanging shell with no feedback. The better version checked the port first, used a short connect timeout, and dropped me into a normal VPS shell as a fallback. Small change, but it turned an unreliable experience into one I could trust.
Then there was tmux. A session created under one terminal environment did not always attach cleanly from another. In my case, xterm-ghostty on the Mac caused problems when the same session got reattached from a mobile client. Setting a more portable default terminal type fixed it, but it was a good reminder: persistent sessions are only as portable as the assumptions baked into them.
None of these were dramatic. They were just the kind of half-solved problems that turn a clever setup into one you stop using after a week.
And Then the Tooling Caught Up
Right around the time I had this working reliably, Anthropic shipped two features that cover a lot of the same ground.
Remote Control lets you continue a local Claude Code session from your phone or any browser. It runs on your machine (your filesystem, your tools, your project config) with the phone just acting as a window into that session. No port forwarding, no VPS, no reverse tunnel.
Dispatch goes further. You message a task from your phone, and it spawns a session on your Mac to handle it. You do not even need to have a session running already.
So did I waste my time? Honestly, I do not think so. Remote Control is limited to one connection per session and times out after about ten minutes of network loss, which is not ideal if you are on spotty mobile data on a rural train line. My setup survives longer outages because mosh and autossh were designed for exactly that. And the VPS gives me a general-purpose foothold that is useful beyond just Claude Code. It is a place to land when I need a shell, period.
But if I were starting fresh today with a stable connection and only needed Claude Code access from my phone? I would try Remote Control first and probably never build any of this. That is worth being honest about.
The Lesson Worth Keeping
I keep running into this pattern, with infrastructure, with AI tooling, with the house we built last year. The first version of an idea usually looks clean because it has not met reality yet. What survives contact with real constraints looks a little stranger, but it is the version that holds up.
What is also true is that sometimes the tools catch up and the constraints shift underneath you. The setup I built is still useful to me. But the reason to write about it is less "here is what you should build" and more "here is what I learned by building it." The constraints shaped the system. Understanding why each piece existed made it easy to know which pieces I could drop once better options showed up.
That is the part worth keeping, even after the tools change.