Connect, build and manage

Getting started with your Mac

Start by getting your connection details from the portal, then verify SSH or screen sharing. This guide follows the workflow from transferring files and running builds to securing your data before expiry.

Already renting? Use the portal to check your instance hostname, port, username and expiry date. The examples in this guide are not real credentials.

Check your connection details first

Three ways to connect—choose the one you need

Use SSH for command-line tasks, screen sharing to work in the macOS GUI, and an SSH connection to transfer project files and build artifacts. Don’t guess the port and keep trying.

SSH

Open the relevant instance in the portal and check its hostname, SSH port and username. Run the command below in your local terminal, replacing the uppercase values with the details for your instance.

ssh -p SSH_PORT USER@HOST

The usual SSH port is 22, but an instance may use a different external port. Check the host fingerprint before connecting for the first time. If it changes, verify why before proceeding.

If the connection times out, check the hostname, network and port. If authentication is denied, check the username and authentication method. Never share passwords or private keys in public logs.

Builds, scripts and log checks

macOS screen sharing (VNC)

Get the screen-sharing address, port and authentication details from the portal. Enter them in your local screen-sharing app or a compatible VNC client. Don’t reuse the SSH port.

The usual VNC port is 5900, but use the external port shown for your instance. Don’t include screen-sharing credentials in screenshots or shared team documents.

Use a protected connection where possible. To create an SSH tunnel, forward local port 5901 to the instance’s VNC service, then connect to your local address.

ssh -N -L 5901:127.0.0.1:VNC_PORT -p SSH_PORT USER@HOST

This forwarding setup works only if the VNC service is listening on the instance and SSH forwarding is allowed. A black screen and an authentication failure are different issues; mention which one you’re seeing in your support ticket.

GUI access and environment checks

File transfers (scp / rsync)

First, verify that you can connect over SSH. File transfers use the same SSH port, so there’s no need to open a separate file-transfer service. Use scp for small files and rsync to sync project directories repeatedly.

scp -P SSH_PORT ./build.zip USER@HOST:~/
rsync -av -e "ssh -p SSH_PORT" ./project/ USER@HOST:~/project/

Note that scp uses an uppercase -P for the port option, while SSH uses lowercase -p. The trailing slash on an rsync source path means to sync the directory’s contents.

Don’t use an automatic delete option for the first sync. Check the destination path and file count before transferring large asset collections. After downloading, verify the archive rather than relying on the progress bar.

Code, assets and build artifacts
Know what each result means

Verify the connection, build and upload separately

This sample log illustrates three distinct stages. The example hostname is not a working service, and the output does not reflect a live task.

Japan (Tokyo) node · example session
$ ssh admin@jp-0417.node.vpskeep.com
Welcome to your dedicated Mac mini.

$ xcodebuild -scheme App archive
** ARCHIVE SUCCEEDED **

$ fastlane beta
Successfully uploaded package to App Store Connect.
  1. 01

    SSH welcome message

    This confirms that you’ve opened a remote session, not that the project environment is ready. Next, run sw_vers and xcodebuild -version and note the system and tool versions.

  2. 02

    Archive complete

    ARCHIVE SUCCEEDED means the archive step passed. In this example, App is the scheme name. For a real project, you’ll also need to specify a workspace or project, target platform and output path. A successful archive doesn’t mean it has been exported or distributed.

  3. 03

    Fastlane upload complete

    beta is a lane defined by the project. You’ll need to configure signing and distribution credentials first. After a successful upload, check the platform’s processing status; a successful local command doesn’t mean the build is ready for testing.

When troubleshooting, keep the failed command, exit code and surrounding log output. A final line saying only “failed” usually isn’t enough to diagnose environment, signing or network issues.

Set up your environment

Pin your Xcode version before setting up simulators and signing

Using different versions locally and remotely can lead to differences in dependency resolution and build results. Record the versions first, then make changes one at a time. Don’t update the toolchain and project dependencies simultaneously.

  1. 01

    Check and switch versions

    Run these two commands to check your setup. If the machine has multiple Xcode versions, you can change the system-wide default. To affect only the current task, set DEVELOPER_DIR in the process environment instead.

    xcode-select -p
    xcodebuild -version
    sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
    DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -version

    Make sure the path points to the installed app. Check the instance details to see whether your required version is preinstalled. If you need another version, use a properly licensed installer and check available disk space first.

  2. 02

    Install simulator runtimes

    In Xcode settings, use the platform or component manager to install a runtime that matches your project. The menu name varies by version. Once installed, list the available devices and select a test target.

    xcrun simctl list runtimes
    xcrun simctl list devices available
    df -h

    Simulators, DerivedData and archives all use disk space. Run a test on one device before increasing concurrency. Simulator testing is not a substitute for testing on a physical iOS device.

  3. 03

    Import signing materials

    Transfer your authorised signing certificate, its private key and provisioning profile to the instance over a protected connection. Import the certificate into the keychain used for the task, and install the profile as required by your Xcode version. Then check the Team, Bundle ID, certificate expiry and distribution type.

    security find-identity -v -p codesigning

    Use a separate build keychain for CI, and store its password in a restricted secret variable. For non-interactive tasks, also check that the keychain is unlocked and the signing tools have access. Seeing a certificate in the GUI alone doesn’t confirm that signing is configured correctly.

    Before leaving the instance, remove any signing private keys, tokens and provisioning profiles you no longer need. In a support ticket, share only the certificate name and error text—never send private keys, passwords or full credentials.

Make tasks repeatable

Get one pipeline working before keeping a runner online

The Keep M4 L configuration is M4 / 24GB / 512GB and can be a starting point for builds across multiple branches. Determine concurrency through project testing; CPU core count alone won’t tell you how many UI tests can run at once.

GitHub Actions self-hosted runner

Start the registration flow from the Actions runner page in your repository or organisation settings. Select macOS and the matching architecture, then download and register the runner using the commands shown on the page. Use the registration token only when needed; don’t add it to your repository.

Give the instance clear labels, such as macos, arm64 and a label for your team’s use case. Target runners by label in your workflow so signing jobs don’t run in an environment without the required certificates.

runs-on: [self-hosted, macOS, ARM64]

Start the runner manually and run a test job before installing it as a persistent service using the runner’s service script. The runtime account needs access to the project directory, Xcode and the build keychain.

Job logs + runner diagnostics

GitLab Runner with a shell executor

Install a GitLab Runner that matches the instance architecture, get the registration details from your project or team settings, then run gitlab-runner register. If you need the native Xcode toolchain, choose a shell executor in line with your team’s security requirements.

A shell executor runs jobs directly on the machine. Accept trusted projects only, and restrict which branches and jobs can access signing keys. Don’t run untrusted contributor code on an instance with production credentials.

gitlab-runner --version
gitlab-runner verify

Confirm that registration and job assignment work before configuring the service for your installation method. Document the build directory, cache directory and log location for your team.

Verify registration, then jobs

Document startup and logs for handover

On macOS, persistent processes are usually managed by launchd. A user-level LaunchAgent and a system-level LaunchDaemon have different startup conditions. If a service depends on a graphical session or user keychain, don’t copy a system-level startup configuration without adapting it.

GitHub Actions runner diagnostic files are usually in the _diag directory under the installation directory; check job-step logs on the pipeline page. GitLab Runner service output depends on how it was installed and started. If you create a launchd configuration, set StandardOutPath and StandardErrorPath explicitly rather than assuming there’s a standard system log file.

Record the runner name, runtime account, Xcode version, working directory and log paths. Use separate DerivedData and artifact directories for concurrent jobs. If jobs overwrite files with the same name, intermittent failures can look like machine issues.

Estimate memory before loading a model

Leave room beyond model weights on the Keep M4 Pro’s 64GB

The Keep M4 Pro configuration is M4 Pro / 64GB / 2TB. Unified memory is shared by the system, models and other processes, so don’t allocate all of it to model weights. These figures estimate weights only; they’re not a performance test or a guarantee that a model will run.

Estimated raw weight size by parameter count and bit width
Model sizeEstimated 4-bit weightsEstimated 8-bit weightsBefore loading
Approx. 7B parametersApprox. 3.3 GiBApprox. 6.5 GiBStart by checking the installation, model format and short-context generation.
Approx. 14B parametersApprox. 6.5 GiBApprox. 13.0 GiBMeasure peak memory for a single request before trying batch jobs.
Approx. 32B parametersApprox. 14.9 GiBApprox. 29.8 GiBLong contexts and concurrent requests can significantly increase KV cache usage.

Calculation: parameter count × bit width ÷ 8 ÷ 2³⁰, rounded to one decimal place in GiB. Quantisation groups, scaling factors, unquantised layers, KV cache and runtime buffers add to actual usage. Model file size is not the same as peak memory usage.

Run your first test in an isolated Python environment

Check that your Python version meets the requirements of the MLX packages you plan to use, then create a virtual environment. Make sure you can access the package source and model files, and that you’re authorised to use the model. Check available disk space before downloading.

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install mlx mlx-lm
python -m mlx_lm.generate --model ./models/model --prompt "Explain unified memory." --max-tokens 128

./models/model should point to a prepared, compatible model directory. Start with a short input and a small number of output tokens, then gradually increase the context length. Record the model version, quantisation method, input length and peak memory so you can reproduce the results.

If memory pressure stays high or swap usage rises quickly, reduce the context length, batch size and number of concurrent requests first. Adding an SSD expands storage, not unified memory, and can’t replace proper memory planning.

Keep track of your rental term

Check the price before renewing and verify your backup before leaving

Choose from four billing cycles: daily, weekly, monthly or quarterly. Treat the expiry date as a deadline for your work, and start moving your data before the final build. Nodes run year-round, 365 days a year; your rental term and delivery status are shown in your order details.

  1. 01

    Renew or change your billing cycle

    Sign in to the portal, check the expiry date for your instance or subscription, then start the renewal process. Confirm the model, node, billing cycle, add-ons and total due before paying. The order details and quote will show when a cycle change takes effect and whether a balance is due. After payment, check that the expiry date has been updated.

  2. 02

    Add storage or Thunderbolt 5

    For extra space for assets, check the +1TB SSD or +2TB SSD options. Before adding Thunderbolt 5 interconnect, confirm that your workflow and devices support it. Add-ons don’t change the original model’s unified memory. Check the available options, billing cycle and delivery requirements in the portal before submitting a configuration change. Back up your data and stop any related writes before making changes to disks or tasks.

  3. 03

    Move your data before expiry

    Export your code, assets, build artifacts and required configuration files. Download them to storage you manage, then test a restore. Stop runners and automated tasks, revoke temporary access tokens, and remove signing private keys and credentials you no longer need. An archive in a remote directory isn’t a verified backup.

  4. 04

    What happens after expiry

    This guide doesn’t treat post-expiry retention as a backup plan. Check your order’s data-handling details for retention periods, deletion status and recovery options. If anything is unclear, confirm it through a support ticket in advance. Don’t assume deleted data can be restored; move anything important before expiry.

Help the on-call engineer reproduce the issue

Include these four sets of details in one ticket

Sign in to the portal to open a support ticket linked to your order. Keep one ticket per issue and add subsequent test results to the same thread to keep the context together.

  1. 01

    Instance and node

    Include your rental ID or order number, model, and the node you’re actually using: Singapore, Japan (Tokyo), South Korea (Seoul) or Hong Kong. Don’t include your login password or private key.

  2. 02

    When the issue occurred

    Give the start time and time zone, say whether it’s still happening, and note when you last used the instance successfully. Specify whether it’s an SSH timeout, authentication failure, black screen in VNC or an error from a build command.

  3. 03

    Reproduction steps and logs

    List the shortest steps to reproduce the issue, your system and tool versions, the full error text and the checks you’ve already tried. Redact credentials in screenshots, and remove tokens, certificate passwords and other sensitive fields from logs.

  4. 04

    If your issue involves a payment

    Include the order number, amount and payment method. We accept USDT-TRC20 and Visa / Mastercard / Amex via Stripe, with all charges in USD. Actual availability depends on the payment gateway returned by the backend. For USDT, provide the transaction hash; for cards, provide the receipt number. Never send your full card number.

If you can’t sign in to the portal, email support@vpskeep.com with your account email and order number. Don’t include connection credentials.

Prepare your environment, then hand off the work

Verify the connection, run a single build and download its artifacts before enabling automation. Still choosing a machine? Start with the three configurations and four billing cycles.