Get instant SSH access to your GitHub Actions runner VM using Border0's ephemeral connector. Perfect for debugging failed workflows or inspecting build environments.
For more details: https://www.border0.com/blogs/ssh-shell-access-to-your-github-actions-vm
- Ephemeral connectors - Auto-cleanup when workflow ends, no manual cleanup needed
- Built-in SSH service - Ready to use immediately
- Custom tags - Add metadata tags to your connector's socket
- GitHub context tags - Automatically tag with repository, workflow, run ID, etc.
- Slack notifications - Get notified when the connector starts
- Register a Border0 account
- Create a service account at Border0 Admin Portal -> Team -> Service Accounts
- Generate a token with
Adminpermissions - Add the token as
BORDER0_TOKENin your GitHub repository secrets
name: My Workflow
on: [push]
jobs:
example:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Your build steps
run: echo "Building..."
- name: Setup Border0 (on failure)
if: ${{ failure() }}
uses: borderzero/gh-action@v3
with:
token: ${{ secrets.BORDER0_TOKEN }}
wait-for: 15Note: No cleanup step is needed - ephemeral connectors automatically clean up when the workflow ends.
| Input | Required | Default | Description |
|---|---|---|---|
token |
Yes | - | Border0 API token |
wait-for |
No | 15 |
Minutes to wait before exiting |
background-mode |
No | false |
Run connector in background |
connector-name |
No | auto | Override auto-generated connector name |
builtin-socket-tags |
No | - | Tags for the socket (format: key1=value1,key2=value2) |
include-github-tags |
No | false |
Add GitHub context tags automatically |
slack-webhook-url |
No | - | Slack webhook for notifications |
By default, the connector name follows this pattern:
{github-org}-{github-repo}-{run-id}-{run-attempt}
Example: myorg-myrepo-12345678-1
Override with connector-name input if needed.
Debug failed builds by adding if: ${{ failure() }}:
- name: Setup Border0
if: ${{ failure() }}
uses: borderzero/gh-action@v3
with:
token: ${{ secrets.BORDER0_TOKEN }}
wait-for: 15Add metadata tags to identify and filter connectors:
- name: Setup Border0
if: ${{ failure() }}
uses: borderzero/gh-action@v3
with:
token: ${{ secrets.BORDER0_TOKEN }}
builtin-socket-tags: "environment=ci,team=platform,app=myservice"
include-github-tags: true
wait-for: 15When include-github-tags: true, these tags are added automatically:
github_repositorygithub_workflowgithub_run_idgithub_actorgithub_refgithub_sha
Run the connector in background while other steps continue:
- name: Setup Border0
uses: borderzero/gh-action@v3
with:
token: ${{ secrets.BORDER0_TOKEN }}
background-mode: true
- name: Continue with other steps
run: echo "Connector running in background"Get notified when the connector starts:
- name: Setup Border0
if: ${{ failure() }}
uses: borderzero/gh-action@v3
with:
token: ${{ secrets.BORDER0_TOKEN }}
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
wait-for: 15Add a manual trigger option for on-demand debugging:
name: My Workflow
on:
push:
workflow_dispatch:
inputs:
debug:
type: boolean
description: Enable Border0 debugging
required: false
default: false
jobs:
example:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: npm run build
- name: Setup Border0 (manual debug)
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug }}
uses: borderzero/gh-action@v3
with:
token: ${{ secrets.BORDER0_TOKEN }}
wait-for: 15Once the action runs, connect using the Border0 client:
# Via connector
border0 client ssh --connector {connector-name}
# Via built-in SSH socket
border0 client ssh runner@ssh-{connector-name}The connector and its socket will appear in the Border0 Admin Portal.
If migrating from v2 (socket-based approach):
- Remove cleanup steps - No longer needed
- Update secret name -
BORDER0_ADMIN_TOKEN→BORDER0_TOKEN - Remove
clean-up-mode- Input no longer exists - Update action version -
borderzero/gh-action@v2→borderzero/gh-action@v3
Before (v2):
- name: Setup Border0
uses: borderzero/gh-action@v2
with:
token: ${{ secrets.BORDER0_ADMIN_TOKEN }}
background-mode: true
- name: Cleanup Border0
if: always()
uses: borderzero/gh-action@v2
with:
token: ${{ secrets.BORDER0_ADMIN_TOKEN }}
clean-up-mode: trueAfter (v3):
- name: Setup Border0
uses: borderzero/gh-action@v3
with:
token: ${{ secrets.BORDER0_TOKEN }}
background-mode: true
# No cleanup step needed!