Shipfox
Shipfox Runners

SSH access

Connect directly to a running job via SSH to debug failures, inspect the environment, and run commands in real time.

CI failures are frustrating when all you have is log output. SSH access lets you connect directly to the runner while your job is running: inspect the filesystem, run commands, reproduce failures, and understand exactly what's happening in your environment.

How it works

Every Shipfox runner gets a unique SSH endpoint. When a job starts, Shipfox provisions a dedicated port on the SSH gateway and makes the connection command available in the job detail view.

Authentication relies on your personal SSH public keys. Each team member registers their own keys in the dashboard. When you open a connection, Shipfox checks your key against the authorized keys for your organization. No passwords, no shared credentials.

All members of your organization can connect to any running job, not just the person who triggered it. This makes collaborative debugging straightforward: a teammate can connect to your failing build and help investigate without needing special access.

Add your SSH key

Click Add SSH key, paste your public key, and give it a name (e.g. "My MacBook Pro").

Supported key types: ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, and FIDO2 hardware security keys (sk-ssh-ed25519, sk-ecdsa-sha2-nistp256).

Each person on your team adds their own key. Any member with a registered key can connect to any runner in the organization.

Connect to a runner

Once your key is added, open the job in GitHub Actions and expand the Set up runner step. The connection command is printed there:

ssh -p <port> runner@<runner-id>.runner.shipfox.io

Run it in your terminal. The connection opens immediately using your local SSH key, no additional configuration needed.

Keep the job alive

By default, a job ends when all steps complete. Add a sleep step to keep the runner available long enough to connect and investigate:

steps:
  - name: Run tests
    run: npm test

  - name: Wait for SSH session
    if: failure()
    run: sleep 1800  # 30 minutes

The if: failure() condition ensures the sleep step only runs when the job has failed, so it doesn't add overhead to successful runs.

What you can do

Once connected, you have a full shell on the runner:

  • Reproduce the failure: re-run the failing command directly
  • Inspect the filesystem: check build artifacts, dependency trees, generated files
  • Debug environment variables: verify secrets, paths, and runtime values
  • Profile resource usage: see CPU, memory, and disk state during the job
  • Test fixes live: apply changes and re-run steps without waiting for a new CI run

Security

  • Organization-scoped: only members of your organization can connect, and only to runners belonging to that organization.
  • Key-based authentication: connections require a registered SSH public key. Removing a key from the dashboard immediately revokes access.
  • Ephemeral endpoints: each runner's SSH endpoint is unique and expires when the job ends.