Guide - Remote Development

Remote Xcode Development: Complete Setup Guide

A complete guide to developing iOS and macOS apps on a remote Mac server. Learn how to connect via SSH, VNC, VS Code Remote SSH, and JetBrains Gateway for a seamless remote Xcode workflow.

35 min read Updated January 2025

Why Develop Remotely?

Remote Xcode development is not just for people who do not own a Mac. Many professional teams use remote Mac servers even when they have local machines, because of the significant advantages:

Always-On Build Server

Your remote Mac runs 24/7 in a datacenter. CI/CD pipelines, nightly builds, and automated tests run without keeping your laptop open.

10Gbps Network

Datacenter-grade networking means faster git clones, dependency downloads, and artifact uploads. CocoaPods installs and SPM resolves happen in seconds.

Consistent Environment

Every team member connects to the same server configuration. No more "works on my machine" issues caused by different macOS versions or Xcode setups.

Work From Any Device

Access your full Xcode development environment from a Windows laptop, Linux desktop, Chromebook, or even an iPad with an SSH client.

Method 1: SSH + xcodebuild CLI

The most lightweight approach. You edit code in your preferred editor locally (or on the server), then build using xcodebuild over SSH. This method works from any device with a terminal.

Set Up SSH Keys

# Generate SSH key on your local machine (if you don't have one)
ssh-keygen -t ed25519 -C "dev@company.com"

# Copy your public key to the remote Mac
ssh-copy-id user@your-mac.myremotemac.com

# Configure SSH for convenience (~/.ssh/config)
Host mac-dev
    HostName your-mac.myremotemac.com
    User your-username
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes
    ServerAliveInterval 60
    ServerAliveCountMax 3
    Compression yes

# Now connect with just:
ssh mac-dev

Common xcodebuild Commands

# List available schemes
xcodebuild -list -project MyApp.xcodeproj

# Build for iOS Simulator
xcodebuild -project MyApp.xcodeproj \
  -scheme MyApp \
  -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.2' \
  clean build

# Build with workspace (CocoaPods/SPM)
xcodebuild -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  build

# Run unit tests
xcodebuild test \
  -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  -resultBundlePath ./TestResults.xcresult

# Archive for distribution
xcodebuild archive \
  -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -configuration Release \
  -archivePath ./build/MyApp.xcarchive \
  CODE_SIGN_IDENTITY="Apple Distribution" \
  PROVISIONING_PROFILE_SPECIFIER="MyApp Distribution"

# Export IPA from archive
xcodebuild -exportArchive \
  -archivePath ./build/MyApp.xcarchive \
  -exportPath ./build/ipa \
  -exportOptionsPlist ExportOptions.plist

# Upload to App Store Connect
xcrun altool --upload-app \
  -f ./build/ipa/MyApp.ipa \
  -t ios \
  -u "apple-id@example.com" \
  -p "@keychain:AC_PASSWORD"

Using tmux for Persistent Sessions

Use tmux to keep your builds running even if your SSH connection drops.

# Install tmux via Homebrew
brew install tmux

# Start a new tmux session
tmux new -s build

# Run your build inside tmux
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp build

# Detach from tmux: press Ctrl+B, then D
# Your build keeps running on the server

# Reconnect later
ssh mac-dev
tmux attach -t build

Method 2: VNC for Full GUI

VNC gives you full access to the macOS desktop, including Xcode's visual interface, Interface Builder, the iOS Simulator, and Instruments. This is the best method when you need the complete Xcode GUI experience.

Enable Screen Sharing on macOS

# Enable Screen Sharing via command line
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart \
  -activate -configure -access -on \
  -restart -agent -privs -all

# Alternatively, set a VNC password
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart \
  -activate -configure -access -on \
  -clientopts -setvnclegacy -vnclegacy yes \
  -clientopts -setvncpw -vncpw "your-vnc-password" \
  -restart -agent -privs -all

# Verify Screen Sharing is running
sudo launchctl list | grep -i screen

Recommended VNC Clients by OS

Your OS Recommended Client Notes
Windows RealVNC Viewer (free) Best performance, supports Apple's high-DPI
Linux Remmina or TigerVNC Remmina has built-in SSH tunneling
macOS Built-in Screen Sharing Open Finder > Go > Connect to Server > vnc://
Chromebook VNC Viewer (Chrome Web Store) Works well for basic GUI access
iPad/iPhone Screens 5 or RealVNC Touch gestures for macOS interaction

Secure VNC via SSH Tunnel

Always use an SSH tunnel for VNC connections to encrypt all traffic.

# Create SSH tunnel for VNC (run on your LOCAL machine)
ssh -L 5900:localhost:5900 -N -f mac-dev

# Now connect your VNC client to: localhost:5900
# All traffic is encrypted through the SSH tunnel

# On Windows with PuTTY:
# Connection > SSH > Tunnels
# Source port: 5900
# Destination: localhost:5900
# Click "Add", then connect

VNC Optimization Tips

  • Lower screen resolution: Set the remote Mac to 1920x1080 instead of Retina for faster rendering.
  • Reduce color depth: In your VNC client, set color quality to Medium or 16-bit for better performance.
  • Disable transparency: On the remote Mac, go to System Settings > Accessibility > Display > Reduce transparency.
  • Close unnecessary apps: Each open window increases the screen data that needs to be transferred.
  • Use SSH compression: Add Compression yes to your SSH config for the tunnel.

Method 3: VS Code Remote SSH

VS Code Remote SSH gives you the best of both worlds: local editor responsiveness with remote Mac computing power. Your keystrokes are local, your builds run on the server.

Install and Configure

# Step 1: Install VS Code extensions
# Open VS Code and install these extensions:
# - Remote - SSH (ms-vscode-remote.remote-ssh)
# - Swift (sswg.swift-lang)
# - CodeLLDB (vadimcn.vscode-lldb) - for debugging

# Step 2: Configure SSH in ~/.ssh/config
Host mac-dev
    HostName your-mac.myremotemac.com
    User your-username
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes
    ServerAliveInterval 60

# Step 3: Connect
# Press Ctrl+Shift+P (or Cmd+Shift+P on macOS)
# Type: "Remote-SSH: Connect to Host"
# Select: mac-dev
# VS Code installs its server component on the remote Mac
# Open your project folder

Configure Build Tasks

Create a .vscode/tasks.json in your project to run xcodebuild from VS Code:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build iOS (Simulator)",
            "type": "shell",
            "command": "xcodebuild",
            "args": [
                "-workspace", "MyApp.xcworkspace",
                "-scheme", "MyApp",
                "-destination", "platform=iOS Simulator,name=iPhone 16",
                "build"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": ["$xcodebuild"]
        },
        {
            "label": "Run Tests",
            "type": "shell",
            "command": "xcodebuild",
            "args": [
                "test",
                "-workspace", "MyApp.xcworkspace",
                "-scheme", "MyApp",
                "-destination", "platform=iOS Simulator,name=iPhone 16"
            ],
            "group": "test",
            "problemMatcher": ["$xcodebuild"]
        },
        {
            "label": "Clean Build",
            "type": "shell",
            "command": "xcodebuild",
            "args": [
                "-workspace", "MyApp.xcworkspace",
                "-scheme", "MyApp",
                "clean"
            ],
            "problemMatcher": []
        }
    ]
}

Now you can press Ctrl+Shift+B (or Cmd+Shift+B) to trigger a build, and the output appears in VS Code's integrated terminal.

Swift Language Support in VS Code

# On the remote Mac, install SourceKit-LSP (comes with Xcode)
# Verify it's available:
xcrun sourcekit-lsp --help

# VS Code Swift extension will automatically detect SourceKit-LSP
# You get:
# - Code completion for Swift and SwiftUI
# - Jump to definition
# - Find references
# - Inline error diagnostics
# - Symbol search

Method 4: JetBrains Gateway + AppCode

JetBrains Gateway provides a remote development experience similar to VS Code Remote, but with the JetBrains IDE ecosystem. While AppCode has been discontinued, you can use JetBrains Fleet or the Gateway with other JetBrains IDEs.

Set Up JetBrains Gateway

# Step 1: Download JetBrains Gateway from jetbrains.com/remote-development/gateway/

# Step 2: Configure SSH connection
# In Gateway: New Connection > SSH
# Host: your-mac.myremotemac.com
# User: your-username
# Authentication: Key pair (select your private key)

# Step 3: Select IDE Backend
# Choose "IntelliJ IDEA" or "Fleet" to run on the remote Mac
# Gateway downloads and installs the IDE backend on the server

# Step 4: Open your project
# Navigate to your project folder on the remote Mac
# The IDE opens with full language support and indexing

Tip: JetBrains Gateway works best with a stable internet connection (at least 10 Mbps). The thin client renders the UI locally, so the experience feels responsive even over long distances.

Managing Code Signing Remotely

Code signing is one of the trickiest parts of remote iOS development. Here is how to manage certificates and provisioning profiles on your remote Mac server.

Export Certificates from Apple Developer Portal

# Option 1: Export from existing Mac as .p12
# On your local Mac (if you have one):
# Open Keychain Access > My Certificates
# Right-click your distribution certificate > Export
# Save as .p12 with a strong password

# Transfer to remote Mac
scp ~/Desktop/Certificates.p12 mac-dev:~/

# On the remote Mac, import:
security import ~/Certificates.p12 \
  -k ~/Library/Keychains/login.keychain-db \
  -P "your-p12-password" \
  -T /usr/bin/codesign -T /usr/bin/security

# Allow codesign access without password prompts
security set-key-partition-list \
  -S apple-tool:,apple:,codesign: \
  -s -k "your-login-password" \
  ~/Library/Keychains/login.keychain-db

# Option 2: Create new certificate on remote Mac
# Use VNC to open Xcode > Settings > Accounts
# Add your Apple ID
# Xcode manages certificates automatically

Keychain Management for CI/CD

# Create a dedicated keychain for CI/CD
security create-keychain -p "keychain-password" build.keychain-db

# Set it as the default keychain
security default-keychain -s build.keychain-db

# Unlock the keychain (needed for automated builds)
security unlock-keychain -p "keychain-password" build.keychain-db

# Set keychain timeout to prevent auto-lock during builds
security set-keychain-settings -t 3600 -u build.keychain-db

# Import certificate
security import Certificates.p12 \
  -k build.keychain-db \
  -P "p12-password" \
  -T /usr/bin/codesign

# Add to search list
security list-keychains -s build.keychain-db login.keychain-db

# Verify
security find-identity -v -p codesigning build.keychain-db

Provisioning Profiles

# Download profiles from Apple Developer Portal
# Or use the xcodebuild automatic provisioning:

# Install provisioning profiles manually
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles/
cp MyApp_Distribution.mobileprovision \
  ~/Library/MobileDevice/Provisioning\ Profiles/

# List installed profiles
ls ~/Library/MobileDevice/Provisioning\ Profiles/

# Decode profile info
security cms -D -i ~/Library/MobileDevice/Provisioning\ Profiles/MyApp_Distribution.mobileprovision

File Syncing Strategies

Choose the right file syncing strategy based on your workflow.

Git (Recommended)

The simplest and most reliable approach. Edit locally, push to a repository, pull on the remote Mac.

# Local machine: push changes
git add . && git commit -m "Update views" && git push

# Remote Mac: pull and build
ssh mac-dev "cd ~/MyApp && git pull && xcodebuild build"

rsync (Fast Sync)

Syncs only changed files over SSH. Faster than copying entire directories.

# Sync local project to remote Mac
rsync -avz --exclude '.git' --exclude 'DerivedData' \
  --exclude 'build' --exclude '.DS_Store' \
  ./MyApp/ mac-dev:~/MyApp/

# Watch for changes and auto-sync (using fswatch on macOS/Linux)
fswatch -o ./MyApp/Sources/ | while read; do
  rsync -avz ./MyApp/Sources/ mac-dev:~/MyApp/Sources/
done

SSHFS (Mount Remote Filesystem)

Mount the remote Mac's filesystem as a local drive. Edit files as if they were local.

# Install SSHFS
# Linux: sudo apt install sshfs
# macOS: brew install macfuse sshfs
# Windows: Install WinFsp + SSHFS-Win

# Mount remote directory
mkdir ~/remote-mac
sshfs mac-dev:/Users/your-username/MyApp ~/remote-mac

# Edit files locally -- they are actually on the remote Mac
code ~/remote-mac

# Unmount when done
fusermount -u ~/remote-mac   # Linux
umount ~/remote-mac           # macOS

Performance Tips

Optimize your remote development experience with these settings.

SSH Compression

Enable compression in your SSH config to reduce data transfer.

# ~/.ssh/config
Host mac-dev
    Compression yes
    CompressionLevel 6

SSH Multiplexing

Reuse SSH connections to eliminate reconnection delays.

# ~/.ssh/config
Host mac-dev
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

DerivedData on RAM Disk

Move Xcode's DerivedData to a RAM disk for faster builds.

# Create 8GB RAM disk
diskutil erasevolume HFS+ \
  "RAMDisk" $(hdiutil attach \
  -nomount ram://16777216)

# Point Xcode DerivedData to RAM disk
defaults write com.apple.dt.Xcode \
  IDECustomDerivedDataLocation \
  /Volumes/RAMDisk/DerivedData

Local Caching with Mosh

Use Mosh instead of SSH for better responsiveness on unstable connections.

# Install Mosh on both machines
brew install mosh

# Connect (handles roaming and sleep)
mosh user@your-mac.myremotemac.com

VNC Resolution Settings

# Set a lower resolution for better VNC performance
# On the remote Mac:
sudo displayplacer "id:1 res:1920x1080 hz:60 color_depth:8 scaling:off"

# Install displayplacer if needed
brew tap jakehilborn/jakehilborn
brew install displayplacer

# List current display settings
displayplacer list

Frequently Asked Questions

Which method should I choose: SSH, VNC, or VS Code?

Most developers use a combination. VS Code Remote SSH for daily coding (best editing experience), SSH for quick builds and scripts, and VNC when you need Interface Builder or the Simulator GUI. Start with VS Code Remote SSH and add VNC when needed.

Can I use Xcode's SwiftUI preview remotely?

Yes, but only through VNC since SwiftUI previews require the Xcode GUI. Connect via VNC, open your project in Xcode, and use the canvas preview as you normally would. The preview updates in real-time on the remote Mac.

How much bandwidth does VNC use?

VNC typically uses 1-5 Mbps for normal development work at 1920x1080. Active scrolling or animations can spike to 10-15 Mbps. A 25 Mbps connection is comfortable for full-day VNC usage. SSH and VS Code Remote use far less bandwidth (under 1 Mbps).

Can I run multiple Simulator instances remotely?

Yes. The Mac Mini M4 has plenty of RAM and CPU cores to run multiple Simulator instances simultaneously. This is useful for testing different iPhone models or running parallel UI tests. Use xcrun simctl to manage Simulator instances from the command line.

What happens if my SSH connection drops during a build?

If you are using tmux or screen, the build continues running on the server and you can reattach to the session. Without tmux, the build process will be terminated. We strongly recommend always running builds inside a tmux session.

Ready to Start Remote Xcode Development?

Get a dedicated Mac Mini M4 with full root access, 10Gbps network, and 24/7 uptime. Your Xcode builds will never be faster.

Related Guides