2026년 08월 21일

GitHub Actions 무료 시간 절약을 위한 Self-hosted Runner 세팅 경험기

GitHub Actions를 쓰다 보면 어느 순간 월 사용량 경고 메일을 받게 된다. 개인 계정의 퍼블릭 저장소는 무제한이지만, 프라이빗 저장소는 Free 플랜 기준으로 매달 2,000분이 무료로 주어진다. 테스트 자동화나 배포 파이프라인을 조금만 촘촘하게 구성해도 이 한도는 생각보다 빠르게 닳는다.

그래서 찾은 대안이 Self-hosted Runner다. 내가 직접 준비한 머신을 GitHub Actions의 실행 환경으로 등록하면, GitHub에서 제공하는 클라우드 러너 시간을 소비하지 않는다. 이 글은 로컬 개발 머신과 별도로 임대한 VPS 서버, 두 가지 환경에 각각 Self-hosted Runner를 세팅하면서 경험한 내용을 정리한 것이다.

Self-hosted Runner가 필요했던 구체적인 이유

운영 중인 프라이빗 저장소가 세 개였고, 각 저장소마다 Push 이벤트에 반응하는 워크플로우가 있었다. 테스트 → 빌드 → 배포까지 한 파이프라인에 묶어 두었는데, 한 번 실행에 평균 8~12분 정도 걸렸다. 하루에 10번만 커밋해도 약 100분이 사라지는 구조였다.

팀원이 추가되고 커밋 빈도가 늘자 2,000분으로는 턱없이 부족해졌다. 유료 플랜으로 올리거나, 추가 분을 구매하거나, 아니면 다른 방법을 찾아야 했다. Self-hosted Runner는 이 세 가지 선택지 중 가장 비용 효율적인 방법이었다.

로컬 머신에 Self-hosted Runner 등록하기

처음에는 항상 켜두는 로컬 데스크탑에 러너를 등록했다. GitHub 저장소 설정 페이지에서 Settings → Actions → Runners → New self-hosted runner로 이동하면 운영체제별 설치 스크립트를 바로 확인할 수 있다.

설치 과정

macOS 환경 기준으로 진행했다. 제공된 스크립트를 그대로 터미널에 붙여넣으면 된다.

# 러너 디렉토리 생성 및 이동
mkdir actions-runner && cd actions-runner

# 러너 패키지 다운로드 (버전은 GitHub에서 제공하는 최신 버전 사용)
curl -o actions-runner-osx-x64.tar.gz -L https://github.com/actions/runner/releases/download/v2.x.x/actions-runner-osx-x64-2.x.x.tar.gz

# 압축 해제
tar xzf ./actions-runner-osx-x64.tar.gz

# 구성 (토큰은 GitHub에서 자동 생성된 값 사용)
./config.sh --url https://github.com/{owner}/{repo} --token {TOKEN}

# 실행
./run.sh

./config.sh 단계에서 러너 이름, 작업 그룹, 레이블을 입력하라는 프롬프트가 나온다. 기본값 그대로 Enter를 눌러도 무방하다. 레이블은 나중에 워크플로우 파일에서 runs-on 값으로 지정하게 되므로 알아보기 쉽게 설정해 두는 것이 좋다.

백그라운드 서비스로 등록

./run.sh로 실행하면 터미널을 닫는 순간 러너도 종료된다. 이를 방지하기 위해 macOS의 launchd 서비스로 등록했다.

sudo ./svc.sh install
sudo ./svc.sh start

Windows라면 ./svc.sh 대신 PowerShell로 동일한 명령을 실행하면 Windows Service로 등록된다. Linux는 systemd 서비스로 등록하는 방식이다.

로컬 러너의 한계

데스크탑을 러너로 쓰는 방식에는 명확한 단점이 있다. 컴퓨터를 끄면 러너도 멈춘다. 야간에 배포 파이프라인이 돌아야 하는 상황이라면 로컬 머신은 적합하지 않다. 또 러너가 워크플로우를 처리하는 동안 로컬 머신 자원을 함께 사용하기 때문에, 무거운 빌드 작업이 돌면 다른 작업에 영향이 간다.

VPS 서버에 Self-hosted Runner 세팅하기

로컬 러너의 한계를 느끼고 저렴한 VPS를 하나 임대했다. 월 몇 달러 수준의 인스턴스로도 충분했다. Ubuntu 22.04 기준으로 세팅했다.

사전 환경 준비

Ubuntu 서버에 처음 SSH 접속하면 기본 패키지부터 정리하는 게 편하다.

sudo apt update && sudo apt upgrade -y

# 워크플로우에서 Docker를 사용한다면 Docker 설치 필요
sudo apt install -y docker.io
sudo systemctl enable docker
sudo systemctl start docker

# 러너 실행 계정에 docker 그룹 권한 부여
sudo usermod -aG docker $USER

러너는 root 계정으로 실행하지 않는 것이 권장된다. 별도의 사용자 계정을 만들고 해당 계정으로 러너를 설치하는 것이 보안상 바람직하다.

sudo useradd -m githubrunner
sudo su - githubrunner

이후 GitHub에서 제공하는 Linux용 설치 스크립트를 동일하게 실행하면 된다.

systemd 서비스로 등록

VPS는 상시 운영이 목적이므로 서비스로 등록하는 것이 필수다.

sudo ./svc.sh install
sudo ./svc.sh start

# 서비스 상태 확인
sudo ./svc.sh status

서버 재부팅 후에도 자동으로 러너가 시작되도록 enable 옵션을 함께 확인해야 한다. svc.sh install 과정에서 자동으로 처리되지만, systemctl is-enabled actions.runner.* 명령으로 확인해 두면 마음이 편하다.

워크플로우 파일 수정

Self-hosted Runner를 등록했다고 해서 기존 워크플로우가 자동으로 그쪽으로 몰리는 것은 아니다. .github/workflows/ 디렉토리 안의 YAML 파일에서 runs-on 값을 바꿔야 한다.

jobs:
  build:
    runs-on: self-hosted  # 기존: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: npm test

여러 러너를 등록해 두고 특정 러너만 사용하고 싶다면 등록 시 설정한 레이블을 배열로 지정한다.

runs-on: [self-hosted, linux, my-vps]

레이블을 잘 구분해 두면 환경별로 워크플로우를 분리하거나, 특정 작업은 성능 좋은 서버에서만 실행되도록 라우팅하는 것도 가능하다.

운영 중 겪은 문제들

의존성 환경이 러너마다 달라지는 문제

GitHub에서 제공하는 클라우드 러너는 실행할 때마다 깨끗한 환경에서 시작된다. Self-hosted Runner는 그렇지 않다. 이전 워크플로우 실행의 흔적이 남아 있어서, 특정 패키지가 설치된 상태라고 가정하고 작성한 워크플로우가 엉뚱하게 실패하는 경우가 있었다.

이 문제는 워크플로우 안에서 필요한 의존성을 명시적으로 설치하는 방식으로 해결했다. 혹은 러너 환경 자체를 Docker 컨테이너로 격리하는 방식도 있는데, 이 경우 runs-on 설정과 함께 container 블록을 사용한다.

러너 오프라인 감지

VPS가 예상치 못하게 재시작되거나 서비스가 죽으면 러너가 오프라인 상태가 된다. GitHub Actions는 이때 워크플로우를 큐에 쌓아두다가 결국 실패로 처리한다. UptimeRobot 같은 외부 모니터링 도구로 서버 상태를 감시하고, 이상 발생 시 알림을 받도록 설정해 두는 게 도움이 됐다.

포크된 저장소와 보안 위험

Public 저장소에 Self-hosted Runner를 연결하는 것은 위험하다. 외부 기여자가 Pull Request를 보내면서 악의적인 워크플로우를 실행할 수 있기 때문이다. Self-hosted Runner는 Private 저장소 또는 신뢰할 수 있는 멤버만 있는 조직 저장소에 연결하는 것이 원칙이다. GitHub 공식 문서에서도 이 점을 명확하게 경고하고 있다.

비용과 효과 정리

한 달 운영 결과, GitHub Actions 클라우드 러너 사용량이 사실상 0에 가까워졌다. VPS 임대 비용이 추가됐지만, 기존에 사용하던 유료 플랜의 추가 분 구매 비용보다 낮았다. 무엇보다 분 단위로 소비량을 걱정하지 않아도 된다는 심리적인 여유가 생겼다.

로컬 머신은 개발 중인 저장소의 빠른 피드백 용도로 여전히 사용 중이고, VPS 러너는 안정적인 배포 파이프라인 처리에 주로 활용하고 있다. 두 환경을 레이블로 구분해 두니 워크플로우 파일에서 용도에 맞게 선택할 수 있어서 편하다.

세팅 전에 확인해야 할 것들

실제로 Self-hosted Runner 도입을 고려한다면 몇 가지를 미리 따져보는 게 좋다.

  • 저장소 공개 여부: Public 저장소라면 Self-hosted Runner 사용을 재고해야 한다.
  • 상시 운전 가능 여부: 로컬 머신만 있다면 VPS 임대를 함께 고려하는 게 현실적이다.
  • 워크플로우 환경 일관성: 클린 환경이 필요한 작업이라면 Docker 컨테이너 격리를 함께 구성해야 한다.
  • 러너 개수: 저장소 하나에 러너를 여러 개 등록해 두면 동시 실행되는 작업이 많을 때 대기 시간이 줄어든다.
  • 유지보수 부담: 클라우드 러너는 GitHub이 관리하지만, Self-hosted Runner는 OS 업데이트, 러너 소프트웨어 업데이트, 보안 패치를 직접 챙겨야 한다.

Self-hosted Runner는 확실히 비용을 줄여주는 수단이지만, 관리 부담도 함께 늘어난다는 점을 감안해야 한다. 상황에 따라 GitHub의 유료 플랜이나 다른 CI/CD 서비스가 더 적합할 수도 있다. 어떤 선택이 맞는지는 팀 규모, 저장소 수, 워크플로우 복잡도에 따라 달라진다.