SSD Nodes Learn RAM 8GB — $66/tahun
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-08-01

Cara Memasang GitHub Actions Runner di VPS Ubuntu

Panduan Ubuntu 24.04 dan runner 2.336.0: buat pengguna khusus, verifikasi checksum, jalankan config.sh, pasang systemd, dan pahami risiko pull request fork.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

Fungsi runner GitHub Actions yang di-hosting sendiri

Runner GitHub Actions yang di-hosting sendiri adalah program yang Anda instal di VPS milik Anda. Program ini meminta job kepada GitHub dan menjalankannya di perangkat keras Anda. Anda mendaftarkannya ke satu repositori, menginstalnya sebagai layanan systemd, dan runner akan aktif kembali setelah setiap reboot. GitHub menjadwalkan job tersebut. Server Anda yang menjalankannya.

CI (continuous integration) pada server milik sendiri bermanfaat karena dua alasan. Menit build tidak lagi dihitung berdasarkan penggunaan, dan job dapat mengakses hal-hal yang hanya tersedia di mesin Anda, seperti cache build yang sudah terisi atau jaringan privat. Konsekuensinya adalah keamanan. Runner menjalankan apa pun yang ditentukan file workflow, sebagai pengguna yang Anda tetapkan. Jadi, file workflow pada dasarnya adalah eksekusi kode jarak jauh. Pada repositori privat, hal ini aman karena hanya orang yang Anda percaya yang dapat menambahkannya. Pada repositori publik, hal ini merupakan risiko nyata. Bagian tentang pull request dari fork menjelaskan mekanismenya.

Semua langkah di bawah ini menggunakan Ubuntu 24.04 dan runner versi 2.336.0, yaitu rilis terbaru per Juli 2026.

Yang Anda perlukan sebelum memulai

Mulai dengan VPS yang memiliki akun admin biasa dan sudo, dalam kondisi yang dicapai pada sepuluh menit pertama di VPS baru. Anda tidak perlu membuka port masuk. Runner membuka koneksi HTTPS (hypertext transfer protocol secure) keluar ke GitHub dan mempertahankan koneksi tersebut tetap terbuka sambil menunggu tugas. Dengan demikian, GitHub tidak pernah terhubung ke server Anda. Firewall dapat tetap menutup akses dari dunia luar, dan tugas tetap masuk.

Anda juga memerlukan hak admin pada repositori, karena token pendaftaran ditampilkan di pengaturan repositori.

Buat pengguna khusus untuk runner

Jangan pernah menjalankan runner sebagai root atau sebagai pengguna admin Anda sendiri. Setiap job mewarisi hak pengguna runner, sehingga workflow yang memanggil sudo akan berhasil jika pengguna runner dapat menggunakan sudo. Buat satu pengguna tanpa hak istimewa yang tidak memiliki apa pun selain direktori home-nya sendiri. Akun pengguna dengan hak minimum pada VPS membahas pola umum ini. Berikut konfigurasi khususnya.

sudo useradd -m -s /bin/bash gharunner
sudo passwd -l gharunner
sudo chmod 750 /home/gharunner
sudo install -d -m 700 -o gharunner -g gharunner /home/gharunner/actions-runner

passwd -l mengunci kata sandi, sehingga tidak ada yang dapat masuk sebagai gharunner menggunakan kata sandi tersebut. Mode 700 pada direktori runner penting karena runner menyimpan kredensialnya dalam teks biasa di sana, dan checkout dapat berisi kode sumber privat.

Periksa kedua properti tersebut sebelum melanjutkan:

sudo passwd -S gharunner
sudo -l -U gharunner

passwd -S mencetak baris yang diawali gharunner L, dengan L yang berarti kata sandi terkunci. sudo -l -U gharunner seharusnya menampilkan is not allowed to run sudo. Jika yang ditampilkan adalah daftar perintah yang diizinkan, akun tersebut berada dalam grup sudo dan isolasi yang baru saja Anda buat sudah tidak berlaku.

Unduh runner dan periksa tarball

Mulai dari sini, gunakan pengguna runner.

sudo -iu gharunner
cd ~/actions-runner
RUNNER_VERSION=2.336.0
curl -fL -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz \
  "https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz"

Jalankan uname -m terlebih dahulu jika Anda tidak yakin dengan arsitekturnya. x86_64 menggunakan file linux-x64 di atas. aarch64 menggunakan actions-runner-linux-arm64-${RUNNER_VERSION}.tar.gz.

Sekarang verifikasi file yang Anda unduh. SHA256 (secure hash algorithm, 256 bit) di bawah ini adalah untuk tarball x64 versi 2.336.0. GitHub menampilkan nilai untuk rilis saat ini di halaman rilis dan pada layar New self-hosted runner. Nilai ini berubah pada setiap versi, jadi salin nilai tersebut dari sana saat menginstal versi lain.

echo "04cf0be1aff4c3ec3554466c39124ca250e3effd8873bb7e8d68535aa9505d5d  actions-runner-linux-x64-2.336.0.tar.gz" | sha256sum -c

Unduhan yang benar menampilkan satu baris:

actions-runner-linux-x64-2.336.0.tar.gz: OK

File yang terpotong atau diubah menampilkan kegagalan dan peringatan:

actions-runner-linux-x64-2.336.0.tar.gz: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match

Jangan lewati pemeriksaan ini dan membiarkan tar menemukan masalahnya. Arsip yang ditulis sebagian akan gagal dengan gzip: stdin: unexpected end of file dan tar: Unexpected EOF in archive. Pesan tersebut menunjukkan bahwa file rusak, tetapi tidak menunjukkan apakah file terpotong atau telah diganti.

tar xzf ./actions-runner-linux-x64-2.336.0.tar.gz
ls

Isi tarball dan yang tidak disertakannya

Setelah diekstrak, direktori tersebut berisi config.sh, run.sh, env.sh, safe_sleep.sh, bin/, dan externals/. bin/ berisi biner runner dan bin/installdependencies.sh. externals/ berisi runtime Node yang disertakan, yang digunakan untuk menjalankan action JavaScript.

svc.sh belum tersedia. Dokumentasi GitHub menjelaskannya sebagai skrip "yang dibuat setelah runner berhasil ditambahkan", karena skrip tersebut ditulis dari template dengan nama repositori dan runner Anda yang disertakan dalam nama service. Jadi, sudo ./svc.sh install sebelum ./config.sh gagal dengan sudo: ./svc.sh: command not found. Lakukan registrasi terlebih dahulu, lalu instal service.

Instal dependensi runner

Runner adalah aplikasi .NET, sehingga memerlukan beberapa pustaka bersama. Biarkan shell pengguna runner tetap aktif dan instal pustaka tersebut dengan sudo, karena skrip menulis ke basis data paket sistem.

exit
cd /home/gharunner/actions-runner
sudo ./bin/installdependencies.sh

Di Ubuntu 24.04, perintah tersebut menginstal libkrb5-3, zlib1g, liblttng-ust1t64, libssl3t64, dan libicu74. Skrip mencoba beberapa nama versi untuk setiap pustaka dan mempertahankan nama yang tersedia dalam rilis Anda. Karena itu, skrip yang sama dapat digunakan pada Ubuntu versi lama dan Debian.

Lewati langkah ini, dan ./config.sh berhenti sebelum melakukan apa pun:

Dependencies is missing for Dotnet Core 6.0
Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 6.0 dependencies.

libicu yang tidak tersedia menghasilkan saran yang sama dengan baris pertama yang berbeda, yaitu Libicu's dependencies is missing for Dotnet Core 6.0. Keduanya berasal dari sumber yang sama: config.sh menjalankan ldd terhadap pustaka yang disertakan sebelum memulai. Karena itu, tautan yang tidak terselesaikan akan menghentikan skrip, bukan menimbulkan crash yang membingungkan kemudian.

Daftarkan runner ke repositori Anda

Dapatkan token dari repositori. Buka Settings, lalu Actions, kemudian Runners, dan New self-hosted runner. Halaman tersebut menampilkan token pendaftaran yang diawali dengan A. Token tersebut kedaluwarsa satu jam setelah dibuat, jadi buat token saat Anda siap menempelkannya.

Lakukan pendaftaran sebagai pengguna runner. config.sh menolak dijalankan dengan sudo.

sudo -iu gharunner
cd ~/actions-runner
./config.sh --url https://github.com/YOUR-USER/YOUR-REPO \
  --token PASTE_REGISTRATION_TOKEN_HERE \
  --name vps-runner-1 \
  --labels vps \
  --work _work \
  --unattended \
  --replace

Fungsi setiap flag tersebut. --name menentukan nama runner yang ditampilkan di repositori, jadi pilih nama yang masih dapat Anda kenali enam bulan lagi. --labels menambahkan label Anda sendiri; runner sudah memiliki self-hosted, Linux, dan X64 secara otomatis. --work menentukan nama direktori tempat checkout disimpan, di dalam direktori runner. --unattended menjawab prompt interaktif dengan nilai defaultnya. Ini sesuai jika perintah tersebut ditempatkan dalam skrip. --replace mengambil alih pendaftaran yang sudah ada dengan nama yang sama, bukan gagal. Ini sesuai saat Anda membangun ulang server.

Proses yang berhasil berakhir dengan baris berikut:

√ Runner successfully added
√ Runner connection is good
√ Settings Saved.

Pendaftaran tersebut kini tersimpan di direktori runner sebagai .runner, .credentials, dan .credentials_rsaparams. Dua yang terakhir mengidentifikasi runner ini ke GitHub, sehingga siapa pun yang dapat membacanya dapat menyamar sebagai runner tersebut. Karena itu, direktori menggunakan mode 700 dan pengguna tersebut tidak memiliki akses sudo.

Instal runner sebagai layanan systemd

./run.sh di terminal cukup untuk satu pengujian, tetapi proses tersebut berhenti saat sesi SSH berakhir. Instal layanan ini agar runner dimulai saat boot. layanan dan timer systemd pada VPS menjelaskan file unit itu sendiri. Di sini, svc.sh membuatkannya untuk Anda.

exit
cd /home/gharunner/actions-runner
sudo ./svc.sh install gharunner
sudo ./svc.sh start
sudo ./svc.sh status

svc.sh memerlukan root karena menulis unit ke /etc/systemd/system dan mengaktifkannya. Argumen setelah install adalah pengguna yang menjalankan layanan. Berikan gharunner secara eksplisit. Tanpa argumen, skrip menggunakan $SUDO_USER, yaitu akun administrator Anda, sehingga setiap tugas berjalan sebagai pengguna yang dapat menggunakan sudo.

Unit tersebut diberi nama berdasarkan repositori dan runner, dalam format actions.runner.YOUR-USER-YOUR-REPO.vps-runner-1.service. Anda tidak perlu mengetikkannya:

systemctl list-units 'actions.runner.*'
sudo journalctl -u 'actions.runner.*' -n 20 --no-pager

Runner yang berjalan normal mencatat √ Connected to GitHub, lalu baris yang diakhiri dengan Listening for Jobs. Halaman Runners pada repositori akan menampilkannya sebagai Idle. Runner yang ditampilkan sebagai Offline berarti layanan tersebut tidak berjalan atau tidak dapat terhubung ke GitHub melalui port 443.

Kirim tugas ke runner

runs-on memilih runner berdasarkan label. Minta self-hosted dan label Anda sendiri agar tugas tidak dijalankan pada runner yang tidak dimaksud.

name: build
on:
  push:
    branches: [main]
jobs:
  build:
    runs-on: [self-hosted, linux, vps]
    steps:
      - uses: actions/checkout@v5
      - run: uname -a

Jika tugas menunggu di Waiting for a runner to pick up this job, labelnya tidak cocok. Setiap label di runs-on harus ada pada runner. Satu kata tambahan dapat membuat tugas tetap berada dalam antrean tanpa kesalahan di mana pun. Bandingkan daftar tersebut dengan label yang ditampilkan di samping runner pada pengaturan repositori.

Mengapa runner yang di-host sendiri dan repositori publik tidak dapat digunakan bersama

Ini adalah bagian yang sering dilewati. Panduan GitHub menyatakan dengan tegas bahwa runner yang di-host sendiri “hampir tidak boleh digunakan untuk repositori publik” dan “tidak memiliki jaminan bahwa tugas akan berjalan di mesin virtual bersih yang bersifat sementara. Runner tersebut juga dapat terus-menerus disusupi oleh kode yang tidak tepercaya dalam workflow”.

Mekanismenya sederhana. Pull request dari fork membawa salinan file workflow-nya sendiri. Jika repositori publik Anda menjalankan workflow pull request pada runner Anda, siapa pun yang dapat melakukan fork repositori tersebut dapat mengusulkan workflow yang menjalankan perintah mereka di VPS Anda. Mereka tidak memerlukan akses tulis karena hal yang mereka usulkan adalah hal yang dijalankan.

Pengaturan persetujuan hanya mengurangi risiko ini, bukan menyelesaikannya. Kebijakan default untuk repositori publik meminta maintainer menyetujui workflow fork dari kontributor untuk pertama kalinya. Setelah Anda menyetujui orang tersebut satu kali, pull request berikutnya dari orang itu berjalan tanpa permintaan baru. Jadi, pengamannya adalah manusia yang membaca diff setiap kali. Payload yang disembunyikan tiga tingkat di dalam skrip build mudah terlewat.

Pull request dari fork tidak menerima secrets Anda, dan GITHUB_TOKEN-nya bersifat hanya-baca. Hal ini membatasi kerusakan di dalam GitHub. Namun, hal ini tidak melindungi server Anda. Penyerang memiliki shell sebagai gharunner. Mereka dapat membaca semua file yang dapat dibaca oleh pengguna tersebut, mengakses apa pun yang dapat dijangkau VPS melalui jaringan privatnya, dan meninggalkan sesuatu di ~/.bashrc atau di unit systemd pengguna yang berjalan selama job berikutnya.

Mendaftarkan runner dengan --ephemeral membuat runner menerima satu job lalu membatalkan pendaftarannya. Dengan demikian, satu job tidak dapat membaca workspace job berikutnya. Cara ini hanya membantu jika ada proses yang membangun ulang mesin atau container untuk setiap job, karena backdoor yang ditulis ke direktori home pengguna runner tetap ada setelah pendaftaran baru.

Aturan berikut singkat. Gunakan runner yang di-host sendiri untuk repositori privat. Jika Anda harus menghubungkannya ke repositori publik, jangan jalankan pull request dari fork di runner tersebut, jangan simpan hal lain di server itu, dan perlakukan mesin tersebut sebagai sumber daya sekali pakai.

Pekerjaan Docker dan grup yang pada dasarnya setara dengan root

Pekerjaan dalam container, container layanan, dan langkah alur kerja apa pun yang memanggil docker build memerlukan daemon Docker pada host runner. Instal Docker dengan cara yang umum, seperti yang dijelaskan dalam Docker dan Docker Compose pada VPS, lalu tambahkan pengguna runner ke grup docker.

Pahami risikonya sebelum melakukannya. Keanggotaan dalam grup docker setara dengan root karena container dapat melakukan bind mount pada / dan berjalan sebagai root di dalamnya. Jadi, alur kerja yang dapat berkomunikasi dengan socket Docker dapat membaca dan menulis setiap file di VPS, termasuk /etc/shadow. Pada repositori privat dengan kontributor tepercaya, risiko ini mungkin dapat diterima. Di lingkungan lain, hal ini menghilangkan manfaat pengguna tanpa hak istimewa. Docker rootless membatasi build container pada hak akses pengguna runner, tetapi menggunakan driver penyimpanan yang lebih lambat dan tidak mendukung container dengan hak istimewa.

Pembaruan dan penghapusan runner dengan benar

Self-hosted runner memperbarui dirinya secara default. Runner mendeteksi rilis baru, mengganti berkasnya sendiri, lalu memulai ulang layanan. Biasanya, Anda tidak perlu melakukan apa pun. ./config.sh --disableupdate menonaktifkan pembaruan otomatis jika Anda memerlukan versi tetap. Setelah itu, Anda harus memperbaruinya sendiri. Dokumentasi GitHub menyatakan dengan jelas bahwa runner yang dikonfigurasi dengan --disableupdate harus diperbarui secara manual.

Pembaruan manual mempertahankan registrasi karena .runner dan .credentials tidak terdapat dalam tarball. Hentikan layanan, unduh dan periksa checksum tarball baru sebagai gharunner, ekstrak tarball tersebut ke direktori yang sama menggunakan tar xzf, lalu mulai kembali layanan:

cd /home/gharunner/actions-runner
sudo ./svc.sh stop
sudo ./svc.sh start

Untuk menghapus runner, hapus instalasi layanan terlebih dahulu, lalu batalkan registrasinya. Token penghapusan tersedia di halaman Runners yang sama, pada tombol Remove milik runner tersebut.

cd /home/gharunner/actions-runner
sudo ./svc.sh stop
sudo ./svc.sh uninstall
sudo -iu gharunner
cd ~/actions-runner
./config.sh remove --token PASTE_REMOVAL_TOKEN_HERE

Menghapus direktori tanpa membatalkan registrasi membuat runner tetap tercantum sebagai Offline di repositori. GitHub hanya mengetahui bahwa runner tersebut sudah dihapus ketika runner menginformasikannya atau administrator menghapus entri itu secara manual.

Mode kegagalan dan string yang akan ditampilkan

Must not run with sudo. config.sh menampilkan pesan ini lalu keluar jika dijalankan sebagai root. Pemeriksaan ini disengaja karena file milik root di _work akan menyebabkan setiap job berikutnya yang dijalankan sebagai pengguna layanan gagal. Jalankan ./config.sh sebagai gharunner. Variabel RUNNER_ALLOW_RUNASROOT menimpa pemeriksaan ini. Penggunaannya hanya menunda kegagalan.

sudo: ./svc.sh: command not found. Anda berada di direktori yang benar. svc.sh belum ada karena config.sh belum menyelesaikan pendaftaran. Daftarkan runner, lalu instal layanan.

Http response code: NotFound from 'POST https://api.github.com/actions/runner-registration'. Token tersebut bukan token pendaftaran yang valid. Token itu mungkin sudah kedaluwarsa karena masa berlakunya hanya satu jam, atau personal access token ditempelkan sebagai pengganti token pendaftaran dari halaman Runners. Buat token baru, lalu tempelkan kembali.

Dependencies is missing for Dotnet Core 6.0. Jalankan sudo ./bin/installdependencies.sh dari direktori runner sebagai root, lalu lakukan pendaftaran kembali.

Runner Offline setelah reboot. Jalankan systemctl is-enabled 'actions.runner.*'. Jika tidak ada yang tercantum, ./svc.sh install belum pernah dijalankan. Artinya, runner hanya pernah berjalan di dalam sesi terminal Anda. Jika unit telah diaktifkan tetapi runner masih Offline, baca journalctl -u 'actions.runner.*' dan periksa HTTPS keluar.

Disk penuh. Checkout, cache build, dan image Docker menumpuk di bawah _work dan di direktori home pengguna runner. Tidak ada proses yang menghapusnya secara otomatis. Pantau du -sh /home/gharunner/actions-runner/_work dan tambahkan pembersihan terjadwal sebelum disk penuh.

FAQ

Mengapa sudo ./svc.sh install menampilkan pesan command not found?

Karena svc.sh tidak ada di dalam tarball runner. File tersebut dibuat di direktori runner setelah ./config.sh selesai melakukan pendaftaran, menggunakan nama repositori dan runner Anda untuk membuat nama layanan. Jalankan ./config.sh terlebih dahulu sebagai pengguna runner. Setelah itu, sudo ./svc.sh install gharunner menemukan skrip tersebut dan menulis unit bernama actions.runner.OWNER-REPO.RUNNER-NAME.service ke dalam /etc/systemd/system.

Apakah saya perlu membuka port firewall untuk runner yang di-hosting sendiri?

Tidak. Runner membuka koneksi HTTPS keluar ke GitHub dan mempertahankannya tetap terbuka saat menunggu job, sehingga GitHub tidak pernah memulai koneksi ke VPS Anda. Izinkan koneksi keluar pada port 443 dan biarkan aturan koneksi masuk tetap tertutup. Jika runner menampilkan status Offline saat layanannya berjalan, periksa pemfilteran koneksi keluar dan DNS, bukan aturan koneksi masuk.

Dapatkah saya menggunakan runner yang di-hosting sendiri pada repositori publik?

Dapat, tetapi GitHub tidak menyarankannya. Pull request dari fork membawa file workflow-nya sendiri, sehingga siapa pun yang dapat melakukan fork terhadap repositori Anda dapat mengusulkan perintah yang dijalankan di mesin Anda. Prompt persetujuan hanya berlaku untuk proses pertama dari seorang kontributor. Jika Anda memasang runner pada repositori publik, nonaktifkan workflow pull request dari fork di dalamnya, jangan simpan hal lain di server tersebut, dan bangun ulang mesin sesuai jadwal.

Mengapa pendaftaran gagal dengan Http response code: NotFound?

Panggilan pendaftaran memberikan respons NotFound jika kredensial salah, bukan hanya jika URL salah. Hal ini membuat pesan tersebut menyesatkan. Token pendaftaran kedaluwarsa satu jam setelah ditampilkan, dan personal access token tidak diterima untuk panggilan ini. Buka Settings, Actions, Runners, New self-hosted runner lagi, salin token terbaru, lalu pastikan nilai --url mengarah ke repositori tempat Anda memiliki hak administrator.

#github-actions#ci#self-hosted#runner#ubuntu-24-04