Building a Remote Dev Workflow on a Cloud Mac: Tuning VS Code Remote-SSH and JetBrains Gateway

Remote Mac ·~6 min read

Building a Remote Dev Workflow on a Cloud Mac: Tuning VS Code Remote-SSH and JetBrains Gateway

It's 2am, you connect from your laptop at home to that rented cloud Mac mini, ready to pick up the build you left running earlier in the day. VS Code pops up an "Installing remote extensions" progress bar that spins for a full forty seconds — the extension list is identical to yesterday's, yet it's being reinstalled from scratch. That "meeting for the first time, every time" experience is usually the first trap people hit when they move their editor to a cloud Mac. Waiting further down the road: dropped sessions on flaky networks, and graphical debugging that simply doesn't work. This post walks through all three.

Why move your editor to a cloud Mac instead of developing locally

If you only log in occasionally to run xcodebuild once, plain SSH plus typing commands is fine. But if you're writing code, debugging, and running tests on a cloud Mac mini day in and day out, a bare terminal with vim is noticeably worse than a local IDE — no semantic jump-to-definition, no breakpoint debugging, and clipboard sync needs extra setup. The better approach is to let the Mac mini handle only compute and compilation, while keeping the editor UI local, bridged over a remote protocol. That's really the point of a "cloud Mac" service: the machine is a dedicated physical resource you treat as your own computer sitting in a data center — not a disposable container you spin up and throw away.

Bridging to a cloud Mac with VS Code Remote-SSH

VS Code Remote-SSH works on a simple principle: the local side runs only a thin client, while the actual language services, terminal, and filesystem all live on the remote Mac. On first connection it installs a vscode-server binary and an extension host into ~/.vscode-server on the remote machine; subsequent connections reuse that same environment.

SSH config and connection multiplexing

By default, every connection redoes a full TCP + SSH handshake, and when you're reaching across the Pacific to an APAC or US-West node, that latency shows up directly as "opening a file takes a beat." Using ControlMaster for connection multiplexing eliminates most of that handshake overhead:

# ~/.ssh/config
Host omac-jp
    HostName <your node IP>
    User devuser
    Port 22
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 10m
    ServerAliveInterval 30
    ServerAliveCountMax 3

ControlPersist 10m means that after the master connection's window closes, the shared channel stays alive for 10 more minutes — any new terminal tab or VS Code reconnect during that window rides the existing channel, skipping the crypto renegotiation entirely. ServerAliveInterval guards against ISPs whose NAT quietly kills idle connections.

Extension caching and index warm-up

That "reinstalling extensions every time" issue mentioned earlier usually isn't a VS Code bug — it's that the remote host itself changed between connections, e.g. you reimaged the instance from the console, or switched to a different one. As long as you stick to the same machine, everything in ~/.vscode-server — extensions, language server caches, TypeScript/Swift indexes — persists across sessions, and connections after the first should feel instant.

For larger projects (say, an Xcode project with multiple targets), you can pre-warm the cache by running a full index pass on the remote before disconnecting:

cd ~/Projects/MyApp
xcodebuild -project MyApp.xcodeproj -scheme MyApp -showBuildSettings > /dev/null

This doesn't produce an executable, but it does get Xcode's index database built ahead of time, so jump-to-definition in the editor won't need to rebuild it on the spot.

Where JetBrains Gateway fits — and where it doesn't

If your team also runs backend services (say, a Kotlin/Go API) on the same cloud Mac, JetBrains Gateway is another option: a lightweight local client connects to a full IDE backend running remotely (IntelliJ IDEA, GoLand, etc.), with rendering streamed back over a proprietary protocol — closer to a native feel than a plain web IDE.

Gateway's boundary is clear: it serves language ecosystems that have a corresponding JetBrains IDE. Apple-exclusive tooling — Xcode projects, Interface Builder, Swift Playgrounds — is outside its coverage.

In other words, for pure iOS/macOS development on a cloud Mac, your main toolchain is still VS Code Remote-SSH (for writing code, running scripts, tailing logs) paired with xcodebuild in a terminal. Gateway is a better fit for teams that happen to also run backend services on that same Mac.

Keeping sessions alive with tmux against flaky networks

Whichever remote editing setup you use, as long as the underlying connection is SSH, disconnection risk is baked in — switching Wi-Fi networks on the road, a home router rebooting, anything can sever the connection instantly. If that happens mid-way through a 40-minute build, the build process gets killed and all that progress is lost.

The fix is to launch every long-running task inside a tmux session rather than directly under the SSH session:

ssh omac-jp
tmux new -s build
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp \
  -destination 'generic/platform=iOS' build 2>&1 | tee build.log

After reconnecting, running tmux attach -t build picks right back up where the terminal output left off — the build process is completely unaffected. This habit isn't just for builds; long model fine-tuning runs, log tailing, and fastlane packaging scripts should all live inside tmux too.

Scenario Recommended tool Why
Day-to-day coding, log watching VS Code Remote-SSH Semantic navigation + integrated terminal, fast once connections are multiplexed
Team backend services (non-Xcode) JetBrains Gateway Full IDE experience, but no Xcode project support
Long-running tasks (builds/training) tmux / screen Disconnects don't kill the process; reattach anytime
GUI needed (Instruments, Interface Builder) Screen sharing / VNC The only way to see the actual GUI

Handling graphical debugging: the VNC/screen-sharing trade-off

The command line covers most scenarios, but some work can't avoid a GUI: reading a memory timeline in Instruments, tweaking constraints in Interface Builder, or just confirming what a UI actually looks like when rendered. For those, you switch to screen sharing (VNC), and the experience is a different animal — far more latency-sensitive. Dropping the resolution to what you actually need (say 1440×900 instead of 4K) and setting color depth to the "thousands of colors" tier noticeably improves smoothness over cross-region links. For daily work, stick to SSH plus your editor and only spin up the GUI on demand — don't leave VNC running and eating bandwidth in the background.

Checklist and lessons learned

Before you put this workflow into practice, run through the following:

Frequently asked questions

Why do VS Code Remote-SSH extensions get reinstalled on every reconnect?

Extensions live under ~/.vscode-server on the remote host, so they persist as long as you keep connecting to the same instance and don't wipe that directory; reinstalls usually happen after switching to a different server or reimaging the OS, so pin one instance for the rental period.

Does JetBrains Gateway work for Xcode-based development?

Gateway targets languages with a matching JetBrains IDE (JVM, Node, Go, Python); it doesn't support Xcode projects, so Swift/Objective-C work still goes through VS Code Remote-SSH with xcodebuild in a terminal, or screen sharing when you need the Xcode GUI.

Will a flaky network kill a build running over SSH?

Not if the build was started inside a tmux or screen session — the process keeps running after the SSH link drops, and reattaching with tmux attach picks the output back up without a rerun.

HireVPS

Try a dedicated cloud Mac mini today

Rent by the day, get SSH/VNC credentials in 2 minutes, and upgrade your configuration anytime.

Rent a Mac mini now