Guide

VS Code Remote-SSH to a GCP VM through IAP, on a Mac

VS Code's Remote-SSH extension uses your Mac's ssh and ~/.ssh/config, so a Compute Engine VM with no external IP opens like any other host once SSH knows to go through Identity-Aware Proxy. This guide sets that up with a ProxyCommand, then covers the three things that trip it up on a Mac: gcloud not on VS Code's PATH, the connect timeout, and a VM that cannot download the VS Code server.

Updated

An SSH host that goes through IAP

The VM needs what any IAP SSH connection needs: a firewall rule from 35.235.240.0/20 on tcp:22, roles/iap.tunnelResourceAccessor, and your key accepted through OS Login or metadata (see SSH without an external IP). Run gcloud compute ssh once so it creates ~/.ssh/google_compute_engine, then add a host to ~/.ssh/config:

Host example-vm
    User dana_acme_example
    IdentityFile ~/.ssh/google_compute_engine
    ProxyCommand /opt/homebrew/bin/gcloud compute start-iap-tunnel example-vm 22 --listen-on-stdin --zone=europe-west1-b --project=acme-prod

Check it in Terminal with ssh example-vm. Then in VS Code, run Remote-SSH: Connect to Host… from the Command Palette and pick example-vm.

gcloud not found when VS Code starts from the Dock

An app opened from the Dock or Spotlight does not read your shell's PATH, so a ProxyCommand that says only gcloud fails there while working in Terminal. VS Code then reports a timeout, often "Connection timed out during banner exchange", because the proxy exited before SSH could start. Use the full path, as above. Find it with:

which gcloud

On Apple Silicon with Homebrew it is usually /opt/homebrew/bin/gcloud; with Google's installer, the bin folder of wherever you unpacked the SDK.

The connect timeout

Remote-SSH gives up if the connection is not up within its connect timeout. Opening an IAP tunnel, signing in and, on the first visit, starting a stopped VM can take longer than you expect. Raise it in VS Code's settings:

"remote.SSH.connectTimeout": 60

A VM that cannot reach the internet

On the first connection, VS Code installs its server on the VM. By default it tries to download it on the VM first and falls back to downloading it on your Mac and copying it over. On a VM with no external IP and no Cloud NAT, that first attempt can hang for a long time at "Downloading VS Code Server" before the fallback. Skip it:

"remote.SSH.localServerDownload": "always"

Extensions you install on the remote side have the same problem. Install them from a VSIX file, or give the subnet Cloud NAT.

With Ostgate instead of gcloud

Ostgate is a native macOS app that opens IAP tunnels itself. In Settings › SSH Integration, click Install: Ostgate adds one managed block to ~/.ssh/config for every instance of your signed-in accounts, and its ProxyCommand calls Ostgate by its full path, so the Dock PATH problem does not arise and no gcloud is needed. In VS Code, connect to a host named after the instance:

web-1.europe-west1-b.acme-prod.gcp

ssh still signs in with your own keys from ~/.ssh, so your public key must be accepted by the VM: in your OS Login profile, or in the instance's or project's SSH keys. The optional OS Login username field in the same settings adds a User line, so you do not have to type it. It works with Ostgate's window closed.

When it does not connect

SymptomCheck
Connection timed out during banner exchange The ProxyCommand failed: gcloud not found from the Dock, or the tunnel was refused. Run ssh -v example-vm in Terminal to see why.
Could not establish connection, timeout Raise remote.SSH.connectTimeout; a stopped VM also has to start.
Permission denied (publickey) The user name, or a key the VM does not accept.
Slow or stuck at Downloading VS Code Server The VM has no internet access; set remote.SSH.localServerDownload to always.
Tunnel closed with 4003 or 4033 Firewall on tcp:22, or the IAP tunnel role; see IAP tunnel errors.

Questions

Why does VS Code say "Connection timed out during banner exchange"?

The ProxyCommand failed before SSH could start, and VS Code only sees silence. On a Mac the usual reason is that VS Code, opened from the Dock, cannot find gcloud on its PATH. Put the full path to gcloud in the ProxyCommand.

Why does "Downloading VS Code Server" hang?

The VM has no external IP and no Cloud NAT, so it cannot download the server itself, and VS Code's fallback to a download on your Mac can take a long time to start. Set remote.SSH.localServerDownload to always, and VS Code downloads it on your Mac and copies it over the SSH connection straight away.

Does this work for Cursor or other VS Code based editors?

Editors that connect with the system ssh and read ~/.ssh/config work the same way. Check that the editor's remote extension uses your SSH config rather than its own SSH client.

Do I need gcloud on the Mac?

With the gcloud ProxyCommand, yes. With Ostgate's SSH integration, no: the ProxyCommand calls Ostgate, which opens the IAP tunnel with your signed-in account.

Open private VMs in your editor without gcloud. Ostgate runs on Apple Silicon Macs with macOS 26.3 or later, with a 7-day trial and no sign-up. See Use ssh from Terminal in the docs.