For APAC and North American teams

From access to app delivery

Your Mac is ready—start with the step that’s holding you up. Check access, toolchains, signing and CI separately, then turn a successful build into a repeatable release.

Use the instance details in the console for the host, port, username and delivery status. Replace the environment variables in these commands with your own settings; no real access credentials are included.

01 · Connect to your Mac

Check the access details, then test the connection

Use SSH for command-line work and automation, and VNC for the desktop. Both connect to the same dedicated physical Mac, but their connection settings are separate.

SSH: Check each connection detail

Open the instance in the console and note its host address, SSH port and username. Verify your private key path locally before connecting. Don’t use the VNC port in your SSH command.

chmod 600 "$SSH_KEY"
ssh -i "$SSH_KEY" -p "$SSH_PORT" "$NODE_USER@$NODE_HOST"

Verify the host fingerprint on your first connection. If you can’t confirm it, open a support ticket rather than disabling host verification. For a timeout, check your local network and port reachability. For a permission error, verify the username, key and public key configured on the instance.

The fingerprint may change after a reinstall or Mac replacement. Update your local record only after confirming the instance has changed.

VNC: Use the desktop for interactive tasks

Connect using the remote desktop details in the console and verify the address, port and password. Set your own access password after the first login instead of sharing one credential long-term.

Use the desktop to configure Xcode, check Keychain and monitor simulators. Run ongoing builds over SSH or through a runner. If SSH works but the desktop doesn’t, record the client error and instance status, then troubleshoot the remote desktop connection before restarting the Mac.

To connect through an SSH tunnel, forward the configured VNC port and connect your client to the local port:

ssh -N -L 5901:127.0.0.1:"$VNC_PORT" \
  -p "$SSH_PORT" "$NODE_USER@$NODE_HOST"

Keep the tunnel connected while in use. Check the instance settings and your team’s access policy before enabling it or choosing a port.

Choose a node based on where you work, not where the project is based

The five nodes are Singapore, Tokyo, Seoul, Hong Kong and US East. Place interactive desktops near their primary users. For automated builds, also consider routes for code and dependency downloads. Teams across regions can use nearby build machines and route jobs with clear runner labels, rather than having everyone work remotely on the same desktop.

Compare nodes using the same client, network and time window. Record connection round-trip time, repository checkout time and a complete build. Network latency isn’t compile time, so don’t compare results from different network conditions.

02 · Pin your toolchain

Give each branch a defined Xcode environment

Record versions before moving signing assets. A successful desktop build doesn’t mean the runner’s user session is ready too.

Run multiple versions without switching underneath other jobs

Give each Xcode version a distinct name and place it in the Applications folder. Stable and Next below are custom app names; replace them with the names used on your Mac. Complete the first launch, accept the license and install the required platform components before adding Xcode to your pipeline.

xcode-select -p
xcodebuild -version
xcrun --sdk iphoneos --show-sdk-version

sudo xcode-select --switch \
  /Applications/Xcode-Stable.app/Contents/Developer

A global switch affects jobs that don’t explicitly select a toolchain. For parallel builds across branches, set the environment variable in each job to avoid another pipeline changing the default version in use.

export DEVELOPER_DIR=/Applications/Xcode-Next.app/Contents/Developer
xcodebuild -version

Check certificates, private keys and provisioning profiles together

Import the signing certificate and matching private key under the macOS user that will run the build. Then install the provisioning profile for the signing settings in your Xcode version. A certificate without its private key can’t sign code.

security find-identity -v -p codesigning
xcodebuild -list -workspace App.xcworkspace

Verify the project’s team ID, bundle identifier, signing method and provisioning profile coverage. First, create an archive manually as the same user; then run the same command in CI. This helps distinguish project settings from runner session permissions.

For automation, use a dedicated Keychain and a controlled process for injecting keys. Check that non-interactive sessions can access the signing identity. Never commit Keychain passwords, certificate export passwords or private keys to the repository, or print them in build logs.

Create a build record you can reproduce

This example uses a workspace and shared scheme. Replace the project name, scheme and export settings; configure export settings for your project’s signing and distribution requirements. Record the exit code, toolchain version and artifact path—not just the success message.

xcodebuild archive \
  -workspace App.xcworkspace \
  -scheme App \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  -archivePath "$HOME/builds/App.xcarchive"

xcodebuild -exportArchive \
  -archivePath "$HOME/builds/App.xcarchive" \
  -exportPath "$HOME/builds/export" \
  -exportOptionsPlist ExportOptions.plist
03 · Set up continuous builds

Run jobs as a dedicated macOS user

Renting a Mac to a single customer doesn’t automatically prevent jobs from interfering with one another. Agree on build users, directories and queue rules across your team.

GitHub Actions: Register the runner, then run it as a service

Get the Apple Silicon-compatible package and registration commands from your repository or organization’s runner settings, then extract the package into a dedicated directory. Register with the temporary token provided there, selecting the correct repository or organization. Don’t store the token in a script.

./config.sh \
  --url "$RUNNER_URL" \
  --token "$RUNNER_TOKEN" \
  --labels pushmac,macos,arm64

./svc.sh install
./svc.sh start
./svc.sh status

The workflow’s runs-on must match the registered labels. Start with a test job that doesn’t use signing assets. Verify the toolchain, working directory and permissions before adding release jobs. Allow only trusted code to use a runner with signing assets.

Run service commands from the runner’s installation directory, using the same account for the operator and service.

GitLab Runner: Set the executor and working directory

Install a compatible runner according to your team’s GitLab instance documentation, then register it using the instance’s authentication details. For native macOS builds, you can choose the shell executor. Jobs then run with the local user’s permissions, so restrict which projects and branches can trigger them.

mkdir -p "$HOME/ci"
gitlab-runner register
gitlab-runner install --working-directory "$HOME/ci"
gitlab-runner start
gitlab-runner status

Follow the prompts to enter your team’s instance URL, token, tags and executor. The configuration file may contain authentication details, so restrict access to it. Keep job IDs and error traces in logs, but don’t expose secret environment variables.

Installation options depend on your runner version. Check the local help output before running commands.

Test the first job after a restart

macOS user-level services usually depend on a logged-in session. Installing a service doesn’t guarantee that signing jobs can run when no user is logged in. Check the runner’s launchd service type, login requirements and Keychain availability. Don’t bypass your team’s access controls just to enable startup at boot.

At a time you can monitor, verify the service after a restart and run one complete build. Use the project’s locked dependencies with Fastlane, for example bundle exec fastlane ios build. Use the lane name defined by your project. For handoffs across time zones, document concurrency limits and queue rules so two archives don’t write to the same output directory.

04 · Keep work reusable

Measure build time before expanding storage

Track dependency resolution, compilation, signing and export separately. Compare clean and incremental builds using the same commit and toolchain to see whether caching is working.

Partition caches by project and toolchain

On a dedicated Mac, you can keep DerivedData, SPM downloads and CocoaPods caches for the duration of your rental. Don’t have every branch write to the same directory indiscriminately. Separate paths by project, toolchain and job type, and keep dependency lockfiles.

xcodebuild archive \
  -workspace App.xcworkspace \
  -scheme App \
  -destination 'generic/platform=iOS' \
  -derivedDataPath "$HOME/ci-cache/App/stable/DerivedData" \
  -clonedSourcePackagesDirPath "$HOME/ci-cache/App/stable/SPM" \
  -archivePath "$HOME/builds/App.xcarchive"

Flutter and React Native projects also need consistent tool versions and locked iOS dependencies. If something goes wrong, keep the failure logs and clear only the relevant cache. Deleting everything on every build usually wipes out the benefits of incremental builds.

Treat storage and memory as separate needs

Push M4 S has an M4 chip, 16GB of memory and 256GB of storage—well suited to everyday CI for a single app. Push M4 L has an M4 chip, 24GB of memory and 512GB of storage for higher memory needs and multi-target builds. Test your project to determine whether it can build in parallel.

+1TB SSD suits workloads where dependency caches, multiple toolchains and build artifacts are gradually filling the system disk. +2TB SSD suits workflows that need to retain more project caches and archives. Extra storage doesn’t add unified memory or guarantee faster builds.

df -h
du -sh "$HOME/ci-cache" "$HOME/builds"

Confirm the mount path before moving caches and updating pipeline variables. An add-on isn’t a backup; keep separate copies of archives, symbol files and important configuration according to your team’s policy.

05 · Account and rental term

Renew ahead of your release schedule

Check billing periods, node details and payment status in the console. Include your order number in support tickets; never send passwords, private keys or full card details.

Daily rentals and renewal periods

Rent by the day, week, month or quarter. Push M4 S costs $19.2/day, $51.8/week, $95.9/month or $260.8/quarter. Push M4 L costs $39.7/day, $107.2/week, $198.5/month or $539.9/quarter. Check the instance expiry date, renewal options and available periods in the console. Daily rates aren’t the listed prices for other billing periods.

Before a release, make sure your rental covers the build and acceptance testing. To change your billing period, check the available options in the console and the amount shown on your bill. Don’t assume an existing payment will automatically switch to another period.

Prepare before changing nodes

Changing nodes means a new network entry point and Mac environment—it’s more than changing a region label. Confirm the process through a console support ticket, then back up your code, signing assets, runner configuration and any required artifacts. Don’t assume local files, caches or login details will move automatically.

After migration, recheck the host fingerprint, runner labels and signing permissions. Run a successful test build before stopping job dispatch to the old environment.

Payment methods and USD billing

Pay by USDT-TRC20 or Visa, Mastercard or Amex, processed by Stripe. All payments are settled in US dollars (USD). Available payment gateways depend on the response from the backend. For on-chain payments, use the network, recipient details and amount shown for that order; don’t reuse payment details from an old order.

Check the order status after paying. If you need help verifying it, provide the order number, payment time and transaction hash or payment reference in a support ticket. Don’t pay again to try to refresh the status.

365-day uptime and project backups

Physical nodes run 365 days a year. The data centre provides power, network connectivity and cooling. Uptime doesn’t replace project backups or guarantee an uninterrupted connection from your client. If a remote session drops, first check the instance status and try the other connection method before deciding whether the Mac is at fault.

At the end of the rental, the Mac is wiped before it’s assigned to another customer. Before your rental ends, export any code, artifacts and configuration you need, remove the runner registration and revoke related access tokens. Don’t use the instance as your only copy of important files.

Keep improving your build workflow

Use this guide for tasks; explore our articles for deeper guidance

This guide covers immediate setup tasks. For migration, cache design and handoffs across time zones, read the full context in our article library.

Explore PushMac technical articles

Choose a topic from our published articles for detailed steps and guidance on when they apply. Before migrating a toolchain or changing cache paths, record your current settings, plan a way to roll back and validate each change.

Commands in this guide demonstrate how to perform a task. Apply recommendations from the articles to your repository structure, signing policy and team permissions.

Include build details support can verify

When teammates across APAC and North America hand off an issue, specific times and node details make it easier to investigate than “can’t connect.”

  1. 01

    Identify the instance

    Include the order or instance number, node, time and time zone. If teammates are connecting from different networks, note each connection location.

  2. 02

    Include the error

    Attach the client error, build command, exit code, Xcode version and relevant log excerpt. Remove any secrets before sharing screenshots or text.

  3. 03

    List the checks you’ve done

    Say whether SSH and VNC each work, whether the issue is reproducible and what settings changed recently. This helps the next person avoid repeating checks.

Send your findings to support

Sign in to the console to open a support ticket about an instance or order. If you can’t sign in, email support@pushmac.com with your account email address and a brief description of the issue.