How to SSH into GitHub Actions Runners: Bypass Restrictions with tmate and ngrok
This article explains how to bypass GitHub Actions' lack of interactive SSH access by using tmate and ngrok, providing step‑by‑step workflow examples, required server specifications, code snippets, and tips for maintaining persistent connections, while emphasizing responsible, non‑malicious usage.
GitHub Actions is GitHub's continuous integration service launched in October 2018. Each action performs a specific task such as fetching code, running tests, or deploying to third‑party services. Actions are combined to form a CI workflow and are shared via GitHub repositories.
GitHub Actions provides a server environment with the following specifications:
2‑core CPU
7 GB RAM
84 GB SSD storage
The detailed system environment is shown below:
Besides Ubuntu, the runner also supports Windows Server 2019 and macOS Catalina 10.15. However, GitHub Actions does not allow direct interactive SSH connections, so obtaining a VPS‑like shell requires workarounds.
Solution 1
mxschmitt/action-tmate provides the first method to establish an interactive tmate session on the Actions runner. The connection ends when you exit, so it cannot continue to subsequent steps, but it is useful for quick SSH access.
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup tmate session
uses: mxschmitt/action-tmate@v2Solution 2
csexton/debugger-action builds on the tmate approach, allowing the workflow to continue after the SSH session. It adds a 15‑minute auto‑disconnect which can be disabled by touching /tmp/keepalive.
name: debugger-action
on:
watch:
types: started
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Debug Session
uses: csexton/debugger-action@masterAction log output:
Solution 3
This method does not use an Action; instead it creates an SSH tunnel via ngrok to expose port 22 of the runner.
#!/bin/bash
if [[ -z "$NGROK_TOKEN" ]]; then
echo "Please set 'NGROK_TOKEN'"
exit 2
fi
if [[ -z "$USER_PASS" ]]; then
echo "Please set 'USER_PASS' for user: $USER"
exit 3
fi
echo "### Install ngrok ###"
wget -q https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-386.zip
unzip ngrok-stable-linux-386.zip
chmod +x ./ngrok
echo "### Update $USER password ###"
echo -e "$USER_PASS
$USER_PASS" | sudo passwd "$USER"
echo "### Start ngrok proxy for 22 port ###"
rm -f .ngrok.log
./ngrok authtoken "$NGROK_TOKEN"
./ngrok tcp 22 --log ".ngrok.log" &
sleep 10
HAS_ERRORS=$(grep "command failed" < .ngrok.log)
if [[ -z "$HAS_ERRORS" ]]; then
echo "=========================================="
echo "To connect: $(grep -o -E "tcp://(.+)" < .ngrok.log | sed "s/tcp:\/\//ssh $USER@/" | sed "s/:/ -p /")"
echo "=========================================="
else
echo "$HAS_ERRORS"
exit 4
fiFirst, register on the ngrok website and obtain a tunnel authtoken. Then add the following workflow to create the tunnel when a job fails:
name: Debugging with SSH
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Try Build
run: ./not-exist-file.sh it bloke build
- name: Start SSH via Ngrok
if: ${{ failure() }}
run: curl -sL https://gist.githubusercontent.com/retyui/.../debug-github-actions.sh | bash
env:
NGROK_TOKEN: ${{ secrets.NGROK_TOKEN }}
USER_PASS: ${{ secrets.USER_PASS }}
- name: Don't kill instance
if: ${{ failure() }}
run: sleep 1hThe server’s default lifetime is one hour, which can be adjusted. Secrets should be stored in GitHub’s encrypted secrets as described in the official documentation.
Action log output:
Disclaimer: Use these techniques only for learning and research purposes; do not employ them for malicious activities.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
