# Live Debugging: SSH into a Running GitLab CI or GitHub Action Job I've always like the idea of being able to ssh into a running job to debug CI-specific things like firewall rules. ## Live Debugging in GitHub Actions In GitHub Actions, the solution is super simple. Just use the action [`owenthereal/action-upterm`](https://github.com/owenthereal/action-upterm): ```yaml name: CI jobs: build: runs-on: ubuntu-latest steps: - name: Setup upterm session uses: owenthereal/action-upterm@v1 with: limit-access-to-actor: true ``` **Security implications:** `limit-access-to-actor: true` makes sure only the pub keys of the person who triggered the workflow can SSH into the Action. Note that the entire TCP traffic is going through [owenthereal/upterm](https://github.com/owenthereal/upterm)'s servers, but since it is being encrypted (SSH), so all good. We could improve the situation by running our own upterm server. ## Live Debugging in GitLab CI With GitLab CI, Actions don't exist and you have to craft your own. To make things worse, you can't find examples of people using `upterm` in their `.gitlab-ci.yml` files since GitLab code search isn't available on the public gitlab.com instance... (one of the many reasons one should prefer GitHub over GitLab). > Tested on 7 March 2025. Here is the commands I use. You can also copy-paste these commands into your job's `script` block as long as it is an Alpine image. For Debian-based images, adjustments will need to be made. ```bash # Alpine version. test: image: alpine:3.19 script: # Heavily inspired from the GitHub Action owenthereal/action-upterm, you can # look into its index.ts to understand the below tricks. - apk add --no-cache curl tmux openssh-client - curl -sSfL https://github.com/owenthereal/upterm/releases/download/v0.14.3/upterm_linux_amd64.tar.gz | tar xz -C /usr/local/bin - mkdir -p ~/.ssh - ssh-keyscan uptermd.upterm.dev 2>/dev/null | awk '{ print "@cert-authority * " $2 " " $3 }' | tee /dev/stderr >> ~/.ssh/known_hosts - ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 - tmux new -d -s upterm-wrapper -x 132 -y 43 "upterm host --accept --force-command 'tmux attach -t upterm' -- tmux new -s upterm -x 132 -y 43" - tmux set -t upterm-wrapper window-size largest; tmux set -t upterm window-size largest - until upterm session current --admin-socket ~/.upterm/*.sock; do sleep 5; done - until ! ls ~/.upterm | grep -q '\.sock$'; do sleep 5; done ``` ```bash # Debian and Ubuntu version. test: image: alpine:3.19 script: # Heavily inspired from the GitHub Action owenthereal/action-upterm, you can # look into its index.ts to understand the below tricks. - apt update && apt install -y tmux openssh-client - curl -sSfL https://github.com/owenthereal/upterm/releases/download/v0.14.3/upterm_linux_amd64.tar.gz | tar xz -C /usr/local/bin - mkdir -p ~/.ssh - ssh-keyscan uptermd.upterm.dev 2>/dev/null | awk '{ print "@cert-authority * " $2 " " $3 }' | tee /dev/stderr >> ~/.ssh/known_hosts - ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 - tmux new -d -s upterm-wrapper -x 132 -y 43 "upterm host --accept --force-command 'tmux attach -t upterm' -- tmux new -s upterm -x 132 -y 43" - tmux set -t upterm-wrapper window-size largest; tmux set -t upterm window-size largest - until upterm session current --admin-socket ~/.upterm/*.sock; do sleep 5; done - until ! ls ~/.upterm | grep -q '\.sock$'; do sleep 5; done ``` ### Notes for Live Debugging in GitLab CI Note that you can't just do: ```yaml test: image: alpine:3.19 script: - upterm host --force-command 'tmux attach -t upterm' --accept -- tmux new-session -d upterm ``` Not sure why... but when trying to connect, you would get "Connection closed": ```console $ ssh psxScav2LZnOJugeSE8A:ZTc4NGUxMWRiMjI5MDgudm0udXB0ZXJtLmludGVybmFsOjIyMjI=@uptermd.upterm.dev Connection closed by 37.16.25.99 port 22 ```