본문으로 건너뛰기

원격 Mac 빌드 서버를 사용한 iOS 개발

iOS remote Mac build setup with Cursor

iOS 앱을 빌드하려면 루프 어딘가에 macOS가 필요하지만, 에디터가 Mac에서 실행되어야 한다는 의미는 아닙니다. Cursor의 Remote-SSH 지원을 사용하면 Windows나 Linux에서 빠른 로컬 편집 경험을 유지하면서 Mac 머신이 컴파일, 서명, 시뮬레이터 실행을 처리하도록 할 수 있습니다. 이 가이드는 아키텍처 옵션, 설정, 빌드 명령, 그리고 가장 많은 시간을 낭비하는 함정을 안내합니다.

Mac이 필요한 이유​

Apple의 툴체인은 macOS에서만 실행되며, iOS 워크플로의 여러 부분이 직접적으로 이에 의존합니다.

  • 코드 서명: 서명 신원은 macOS 키체인에 있으며 서명된 아티팩트를 생성하는 데 사용됩니다.
  • 프로비저닝 프로파일: 앱 ID를 장치와 인증서에 바인딩하는 프로파일은 Apple 도구를 통해 관리됩니다.
  • iOS 시뮬레이터: 시뮬레이터는 macOS 애플리케이션이며, 실제 장치 충실도를 위한 지원되는 Linux나 Windows 대응물이 없습니다.
  • xcodebuild 툴체인: 컴파일러, 링커, SDK는 macOS의 Xcode 내부에 있습니다.
  • App Store 제출: App Store Connect에 업로드하려면 Apple의 도구가 필요하며, 일반적으로 macOS에서 Transporter나 altool/notarytool을 통해 이루어집니다.

이 모두가 macOS에 묶여 있으므로, 실제 질문은 Mac이 필요한지가 아니라 그 Mac이 어디에 있는지입니다.

아키텍처 옵션​

단일 최선의 답은 없습니다; 올바른 선택은 팀 규모, 예산, 빌드 빈도에 달려 있습니다.

옵션작동 방식장점단점
Mac으로 Remote-SSHCursor가 SSH로 연결; 파일과 터미널이 Mac에 있음단일 소스 오브 트루스, 전체 툴체인 액세스, 실제 시뮬레이터지속적이고 접근 가능한 Mac 필요
rsync / git push로 Mac에로컬에서 편집, Mac으로 푸시, 거기서 빌드편집은 오프라인 작동, 단순한 멘탈 모델동기화 드리프트, 느린 대용량 전송, 라이브 LSP 없음
클라우드 CI macOS 러너Git으로 푸시, CI가 호스팅된 macOS 러너에서 빌드소유할 하드웨어 없음, 재현 가능, 릴리스에 적합대화형 아님, 분당 비용, 콜드 스타트
클라우드 Mac 제공자SSH로 Mac 임대(MacStadium, AWS EC2 Mac)주문형 실제 하드웨어, 확장 가능시간당 비용, 프로비저닝 및 해제 오버헤드

일상 개발에는 Mac으로 Remote-SSH가 보통 최고의 균형입니다. 클라우드 CI는 릴리스 파이프라인에 맞습니다. 클라우드 Mac 제공자는 데스크를 소유하지 않고 플릿을 원하는 팀에 맞습니다.

작업에 도구를 맞추세요

대화형 개발에는 Remote-SSH를, 릴리스에는 클라우드 CI를, 규모나 짧은 버스트에는 클라우드 Mac 인스턴스를 사용하세요. 대부분의 성숙한 팀은 하나의 옵션이 모든 것을 하도록 강요하기보다 적어도 두 가지를 운영합니다.

원격 Mac 설정​

이 단계들은 빌드 서버로 작동할 Mac에서 한 번 실행됩니다. 관리자 권한과 안정적인 네트워크 연결이 필요합니다.

1. Xcode와 명령줄 도구 설치​

Mac App Store에서 Xcode를 설치한 다음 명령줄 도구를 설치하여 xcodebuild 및 관련 바이너리를 사용할 수 있게 하세요:

xcode-select --install

# Point the toolchain at the full Xcode app, not the standalone CLT
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

2. 라이선스 동의​

새로 설치하면 xcodebuild는 라이선스가 동의될 때까지 실행을 거부합니다:

sudo xcodebuild -license accept

3. 빌드 사용자 생성​

개인 계정으로 빌드하지 마세요. 자격 증명과 키체인이 격리되도록 전용 사용자를 만드세요:

# Create a build user (adjust the short name and full name)
sudo dscl . -create /Users/builduser
sudo dscl . -create /Users/builduser UserShell /bin/zsh
sudo dscl . -create /Users/builduser RealName "Build User"
sudo dscl . -create /Users/builduser UniqueID 510
sudo dscl . -create /Users/builduser PrimaryGroupID 20
sudo dscl . -create /Users/builduser NFSHomeDirectory /Users/builduser
sudo passwd builduser

4. 원격 로그인 활성화​

Mac이 연결을 수락하도록 SSH를 켜세요:

sudo systemsetup -setremotelogin on

5. SSH 공개 키 설치​

비밀번호 없이 연결할 수 있도록 로컬 공개 키를 빌드 사용자의 authorized_keys에 추가하세요:

mkdir -p /Users/builduser/.ssh
# Paste your public key (id_ed25519.pub) into authorized_keys
chmod 700 /Users/builduser/.ssh
chmod 600 /Users/builduser/.ssh/authorized_keys
chown -R builduser:staff /Users/builduser/.ssh
SSH 계정을 잠그세요

인터넷에 노출된 빌드 Mac은 빌드 사용자에 대해 비밀번호 로그인을 허용해서는 안 됩니다. 비밀번호 인증을 비활성화하고, 가능한 경우 허용된 소스 주소를 제한하고, 개인 키는 로컬 머신에만 유지하세요.

Remote-SSH로 Cursor 연결​

Mac에 도달할 수 있게 되면 Cursor를 연결하세요. 원격이 확장, 터미널, 빌드가 실행되는 환경이 됩니다.

1. Remote-SSH 확장 설치​

Cursor를 열고 확장 보기(Ctrl+Shift+X)로 이동하여 Remote - SSH를 설치하세요(Microsoft가 패키징한 확장은 Cursor의 마켓플레이스에서 사용 가능합니다).

2. SSH 구성 항목 추가​

일반적으로 ~/.ssh/config에 있는 로컬 SSH 구성을 편집하고 호스트 별칭을 추가하세요:

# ~/.ssh/config
Host mac-build
HostName 203.0.113.10
User builduser
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 30
ServerAliveCountMax 4
TCPKeepAlive yes

keep-alive 설정은 불안정한 네트워크에서 연결 끊김을 줄입니다. 네이티브 macOS OpenSSH는 mosh를 지원하지 않으므로 keep-alive가 첫 번째 방어선입니다.

3. 연결​

명령 팔레트(Ctrl/Cmd+Shift+P)를 열고 Remote-SSH: Connect to Host를 실행한 다음 mac-build를 선택하세요. 또는 한 단계로 실행하세요:

cursor --remote ssh-remote+mac-build /Users/builduser/projects/MyiOSApp

4. 창이 다시 로드됨​

Cursor가 원격 창으로 다시 로드됩니다. 상태 표시줄이 원격 호스트 이름을 보여줍니다. 모든 터미널, 작업, 언어 서버가 이제 Mac에서 실행되며, UI와 렌더링은 로컬에 유지됩니다.

5. 확장이 원격에 설치됨​

Swift 파일을 열면 Cursor가 원격에 언어 확장을 설치하라는 프롬프트를 표시합니다. 수락하세요. Swift 도구, 디버그 어댑터, Swift 확장은 로컬 머신이 아니라 Mac에 속합니다.

로컬 vs 원격 확장

테마 같은 UI 전용 확장은 로컬에서 실행됩니다. Swift 언어 서버와 모든 디버그 어댑터를 포함하여 프로세스를 실행하는 확장은 원격 Mac에서 실행됩니다. Cursor에게 맡기면 Cursor가 분할을 관리합니다.

로컬에서 편집하고 원격에서 빌드​

생산적인 패턴은: Cursor에서 편집하고, Mac의 터미널인 통합 터미널에서 빌드를 실행하는 것입니다. 파일은 항상 Mac에 있으므로 드리프트할 동기화 단계가 없습니다.

기본 빌드​

특정 장치가 필요하지 않도록 일반 iOS 대상에 대해 스킴을 빌드하세요:

xcodebuild \
-project MyApp.xcodeproj \
-scheme MyApp \
-configuration Debug \
-destination 'generic/platform=iOS' \
build

프로젝트 대신 워크스페이스를 사용하면 -project를 -workspace로 바꾸세요:

xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -destination 'generic/platform=iOS' build

릴리스용 아카이빙​

아카이빙은 .xcarchive를 생성하며, 내보내기 단계가 이를 배포용 .ipa로 변환합니다:

xcodebuild \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath build/MyApp.xcarchive \
archive

아카이브 내보내기​

아카이빙 후 배포 방법을 설명하는 내보내기 옵션 plist를 사용하여 내보내세요:

xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportPath build/export \
-exportOptionsPlist ExportOptions.plist

App Store 스타일 배포를 위한 ExportOptions.plist는 대략 다음과 같습니다:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store-connect</string>
<key>teamID</key>
<string>ABCDE12345</string>
<key>signingStyle</key>
<string>automatic</string>
<key>uploadSymbols</key>
<true/>
</dict>
</plist>
CI에서는 일반 대상을 선호하세요

generic/platform=iOS용으로 빌드하면 빌드를 특정 장치나 시뮬레이터 UDID에 묶지 않으므로, 구성 변경 없이 모든 빌드 머신에서 같은 명령이 작동합니다.

테스트 실행 및 로그 읽기​

테스트는 빌드와 같은 방식으로 실행되며, test 액션과 구체적인 대상만 다릅니다.

테스트 실행​

xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16,OS=latest'

로그를 읽기 가능하게 만들기​

원시 xcodebuild 출력은 방대하고 스캔하기 어렵습니다. 포매터를 통해 파이프하여 읽기 가능한 줄로 축약하세요:

# xcbeautify: modern, fast formatter
xcodebuild test -workspace MyApp.xcworkspace -scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16' | xcbeautify

# xcpretty: older but widely available alternative
xcodebuild test -workspace MyApp.xcworkspace -scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16' | xcpretty

지속적인 로그 파일과 읽기 가능한 스트림을 위해 출력을 tee하세요:

xcodebuild build -scheme MyApp -destination 'generic/platform=iOS' \
2>&1 | tee build.log | xcbeautify

터미널이 원격이므로 로그 파일은 Mac에 저장됩니다. Cursor의 파일 탐색기로 같은 원격 창에서 읽거나, 원한다면 두 번째 SSH 세션으로 로컬에서 스트리밍하세요.

시뮬레이터 스크린샷 찍기​

시뮬레이터가 Mac에서 실행되므로, 로컬 스크린샷을 찍는 대신 SSH를 통해 xcrun simctl로 캡처합니다.

시뮬레이터 나열 및 부팅​

# List available devices
xcrun simctl list devices available

# Boot a specific simulator by UDID or name
xcrun simctl boot "iPhone 16"

# Open the Simulator UI if a desktop session is available
open -a Simulator

앱 설치 및 실행​

# Install a built .app onto the booted simulator
xcrun simctl install booted ./build/Build/Products/Debug-iphonesimulator/MyApp.app

# Launch it by bundle identifier
xcrun simctl launch booted com.example.MyApp

스크린샷 캡처​

# Save a screenshot to a file on the Mac
xcrun simctl io booted screenshot /Users/builduser/shots/home.png

이 파일이 원격에 있으므로 Cursor 원격 창에서 직접 여세요. 이미지 미리보기는 Remote-SSH를 통해 작동하므로 로컬로 복사할 필요가 없습니다.

헤드리스 시뮬레이터에는 세션이 필요합니다

simctl은 GUI 없이 시뮬레이터를 부팅할 수 있지만, 일부 UI 기반 테스트와 더 풍부한 스크린샷 시나리오는 로그인된 데스크톱 세션을 기대합니다. 헤드리스 Mac에서는 지속적인 로그인 세션을 유지하거나, 시뮬레이터 UI 기능의 제한을 예상하세요.

코드 서명​

서명은 새 머신에서 실패할 가능성이 가장 큰 부분이므로 의도적으로 설정하세요.

키체인의 인증서​

서명 신원은 빌드 사용자의 키체인에 있습니다. Apple 개발자 계정에서 내보낸 .p12를 가져오세요:

security import /path/to/distribution.p12 \
-k /Users/builduser/Library/Keychains/login.keychain-db \
-P "p12-password" \
-T /usr/bin/codesign \
-T /usr/bin/security

-T 플래그는 가져온 신원에 codesign과 security 액세스를 부여하여 빌드가 액세스 프롬프트에서 멈추지 않도록 합니다.

프로비저닝 프로파일​

프로파일을 빌드 사용자를 위해 Xcode가 기대하는 위치에 두세요:

mkdir -p /Users/builduser/Library/MobileDevice/Provisioning\ Profiles
cp ~/profiles/MyApp_AppStore.mobileprovision \
/Users/builduser/Library/MobileDevice/Provisioning\ Profiles/

자동 vs 수동 서명​

  • 자동 서명: 더 단순하며, 빌드 사용자가 Apple 개발자 계정에 로그인되어 있고 Apple 서비스에 대한 네트워크 액세스가 있어야 합니다. 하나의 신뢰할 수 있는 Mac에 적합합니다.
  • 수동 서명: CI에 더 재현 가능합니다. CODE_SIGN_STYLE=Manual을 지정하고 특정 신원과 프로파일을 가리켜 계정 의존적 동작을 피합니다.
xcodebuild archive \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'generic/platform=iOS' \
CODE_SIGN_STYLE=Manual \
CODE_SIGN_IDENTITY="Apple Distribution: Example Corp (ABCDE12345)" \
PROVISIONING_PROFILE_SPECIFIER="MyApp AppStore Profile" \
-archivePath build/MyApp.xcarchive
CI에서 키체인 잠금 해제

무인 Mac에서는 빌드 전에 로그인 키체인을 잠금 해제하여 codesign이 GUI 프롬프트 없이 신원에 도달할 수 있도록 하세요. 잠금 해제 비밀번호는 시크릿 저장소에 보관하고 커밋된 스크립트에는 절대 넣지 마세요.

비용 비교​

가격은 변하므로 다음은 현재 견적이 아니라 계획을 위한 대략적인 범위로 취급하세요.

옵션대략적인 월 비용참고
빌드 서버로 Mac mini 소유하드웨어 구매, 이후 반복 비용 거의 0꾸준한 사용 시 가장 저렴; 유지보수를 직접 담당
클라우드 Mac 제공자(MacStadium, EC2 Mac)시간당, 24/7 사용 시 종종 월 수백확장 또는 축소; 프로비저닝 오버헤드
클라우드 CI macOS 러너분당, 빌드 중에만 청구간헐적 빌드에 가장 저렴; 콜드 스타트가 부담
rsync / git로 공유 Mac에Mac 비용만개인에게 적합, 팀에는 어색함

전용 Mac mini는 하루 종일 빌드하는 소규모 팀에 보통 유리합니다. 클라우드 CI는 빌드가 드물거나 엄격히 릴리스 시점일 때 유리합니다. 클라우드 Mac 인스턴스는 주문형 용량이 필요하고 하드웨어를 소유하고 싶지 않을 때 유리합니다.

흔한 함정​

대부분의 원격 빌드 문제는 소수의 반복되는 실수에서 비롯됩니다. 이국적인 것을 디버깅하기 전에 다음을 확인하세요.

라이선스 미동의​

xcodebuild가 라이선스 오류와 함께 즉시 실패합니다. 다음으로 한 번 수정하세요:

sudo xcodebuild -license accept

잘못된 Xcode 버전 선택​

여러 Xcode 설치가 툴체인을 혼란스럽게 합니다. 의도한 것을 명시적으로 선택하세요:

sudo xcode-select -s /Applications/Xcode-16.app/Contents/Developer
xcodebuild -version

서명 신원 누락​

아카이브되지만 내보내기에 실패하는 빌드는 보통 일치하는 신원이나 프로파일이 없습니다. 키체인이 실제로 무엇을 보유하는지 확인하세요:

security find-identity -v -p codesigning

필요한 신원에 대해 목록이 비어 있으면 .p12를 다시 가져오고 프로파일이 앱의 번들 식별자와 일치하는지 확인하세요.

느린 동기화​

SSH를 통해 편집하는 대신 코드를 동기화하는 경우 rsync보다 git을 선호하세요. Git은 델타를 전송하고 기록과 충돌 처리를 제공합니다; rsync는 전체 트리를 이동하고 조용히 드리프트합니다. Remote-SSH를 통해 직접 편집하면 동기화가 전혀 없으며, 이것이 가장 빠른 옵션입니다.

네트워크 끊김이 SSH를 깨뜨림​

불안정한 링크를 통한 긴 빌드는 연결을 끊고 빌드를 죽일 수 있습니다. 구성의 SSH keep-alive로 완화하고, Mac에서 tmux나 screen 안에서 긴 빌드를 실행하여 연결 끊김에서 살아남도록 하세요:

tmux new-session -s build 'xcodebuild archive -workspace MyApp.xcworkspace -scheme MyApp -destination "generic/platform=iOS" -archivePath build/MyApp.xcarchive'

나중에 다시 연결하고 tmux attach -t build로 재부착하세요.

헤드리스에서 실행되지 않는 시뮬레이터​

일부 테스트 흐름은 보이는 시뮬레이터를 가정합니다. 헤드리스 Mac에서는 simctl로 시뮬레이터를 부팅하고, 로그인된 데스크톱 세션을 유지하거나 축소된 시뮬레이터 UI 커버리지를 수용하세요.

첫날부터 빌드를 tmux로 감싸세요

완전히 통제하지 못하는 네트워크를 통해 빌드한다면 모든 긴 xcodebuild를 tmux 안에서 실행하세요. SSH 세션이 살아남는지와 관계없이 빌드는 Mac에서 계속 실행되며, 다시 부착하여 완료를 지켜볼 수 있습니다.

원격 빌드는 하드 플랫폼 제약을 워크플로 선택으로 바꿉니다. 팀에 맞는 아키텍처를 선택하고, Mac을 한 번 설정하고, Mac이 macOS가 요구하는 작업을 하는 동안 Cursor의 Remote-SSH가 편집 경험을 빠르게 유지하도록 하세요.