Self-hosted GitHub Actions runner sa Ubuntu 24.04
Irehistro ang self-hosted GitHub Actions runner sa Ubuntu 24.04 gamit ang dedicated user, checksum, config.sh at systemd, kasama ang panganib ng fork pull requests.
Ang ginagawa ng self-hosted GitHub Actions runner
Ang self-hosted GitHub Actions runner ay isang program na ini-install mo sa sarili mong VPS. Humihingi ito ng mga job sa GitHub at pinapatakbo ang mga ito sa hardware mo. Nirerehistro mo ito sa isang repository, ini-install bilang systemd service, at awtomatiko itong bumabalik pagkatapos ng bawat reboot. Si GitHub ang nagso-schedule ng job. Ang server mo ang gumagawa ng trabaho.
Sulit ang CI (continuous integration) sa sarili mong machine sa dalawang dahilan. Hindi na sinisingil ayon sa paggamit ang build minutes, at maaaring ma-access ng isang job ang mga resource na nasa machine mo lamang, gaya ng warm build cache o private network. Ang kapalit nito ay seguridad. Ine-execute ng runner ang anumang ipinapagawa ng workflow file, gamit ang user na itinalaga mo rito. Dahil dito, ang workflow file ay sadyang remote code execution. Sa private repository, ayos ito dahil mga taong pinagkakatiwalaan mo lamang ang maaaring magdagdag nito. Sa public repository, totoong panganib ito. Ipinapaliwanag ng seksyon tungkol sa fork pull requests kung paano ito gumagana.
Lahat ng sumusunod ay para sa Ubuntu 24.04 gamit ang runner version 2.338.0, ang kasalukuyang release noong 12 October 2026.
Mga kailangan bago magsimula
Magsimula sa isang VPS na may karaniwang admin account at sudo, sa kalagayang naabot mo sa unang sampung minuto sa bagong VPS. Hindi mo kailangang magbukas ng inbound port. Nagbubukas ang runner ng outbound HTTPS (hypertext transfer protocol secure) connection papunta sa GitHub at pinananatili itong bukas habang naghihintay ng work. Kaya hindi kailanman kumokonekta ang GitHub sa iyong server. Maaaring manatiling sarado sa external traffic ang firewall mo at makararating pa rin ang mga job.
Kailangan mo rin ng admin rights sa repository dahil ipinapakita ang registration token sa repository settings.
Gumawa ng dedicated user para sa runner
Huwag kailanman patakbuhin ang runner bilang root o bilang sarili mong admin user. Namamana ng bawat job ang mga karapatan ng runner user, kaya magtatagumpay ang workflow na tumatawag sa sudo kung maaaring gumamit ng sudo ang runner user. Gumawa ng isang unprivileged user na sariling home directory lamang ang pagmamay-ari. Tinalakay sa Mga user account na may least privilege sa isang VPS ang pangkalahatang pattern. Narito ang partikular na setup.
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-runnerNilala-lock ng passwd -l ang password, kaya walang makakapag-log in bilang gharunner gamit ito. Mahalaga ang mode 700 sa runner directory dahil doon iniimbak ng runner ang mga credential nito bilang cleartext, at maaaring maglaman ang checkout ng private source.
Suriin ang dalawang property bago magpatuloy:
sudo passwd -S gharunner
sudo -l -U gharunnerNagpi-print ang passwd -S ng linyang nagsisimula sa gharunner L, kung saan ang L ay nangangahulugang naka-lock ang password. Dapat magbalik ang sudo -l -U gharunner ng is not allowed to run sudo. Kung listahan ng mga pinapahintulutang command ang ipi-print nito, kabilang ang account sa isang sudo group at nawala na ang isolation na kakagawa mo lang.
I-download ang runner at suriin ang tarball
Mula rito, gamitin ang runner user.
sudo -iu gharunner
cd ~/actions-runner
RUNNER_VERSION=2.338.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"Patakbuhin muna ang uname -m kung hindi ka sigurado sa architecture. Kinukuha ng x86_64 ang linux-x64 file sa itaas. Kinukuha ng aarch64 ang actions-runner-linux-arm64-${RUNNER_VERSION}.tar.gz.
Ngayon, i-verify ang na-download mo. Ang SHA256 (secure hash algorithm, 256 bit) sa ibaba ay para sa 2.338.0 x64 tarball. Ipinapakita ng GitHub ang value para sa kasalukuyang release sa release page at sa New self-hosted runner screen. Nagbabago ito sa bawat version, kaya kopyahin ito mula roon kapag ibang version ang ini-install mo.
echo "af4b794c1bc41d73d40535e3fe092a39f9679cd8d965954c2aca25a05ca41d32 actions-runner-linux-x64-2.338.0.tar.gz" | sha256sum -cAng matagumpay na download ay nagpi-print ng isang linya:
actions-runner-linux-x64-2.338.0.tar.gz: OKAng naputol o nabagong file ay nagpi-print ng failure at warning:
actions-runner-linux-x64-2.338.0.tar.gz: FAILED
sha256sum: WARNING: 1 computed checksum did NOT matchHuwag laktawan ang check at hayaang tar ang makatuklas ng problema. Nabibigo ang hindi kumpletong archive sa gzip: stdin: unexpected end of file at tar: Unexpected EOF in archive. Ipinapakita nito na sira ang file, ngunit hindi kung naputol ito o napalitan.
tar xzf ./actions-runner-linux-x64-2.338.0.tar.gz
lsMga nilalaman ng tarball at mga wala rito
Pagkatapos i-extract, naglalaman ang directory ng config.sh, run.sh, env.sh, safe_sleep.sh, bin/ at externals/. Nasa bin/ ang runner binaries at bin/installdependencies.sh. Nasa externals/ ang naka-bundle na Node runtime na ginagamit para i-execute ang JavaScript actions.
Wala pa ritong svc.sh. Inilalarawan ito ng dokumentasyon ng GitHub bilang script na “ginagawa pagkatapos matagumpay na maidagdag ang runner,” dahil sinusulat ito mula sa template na may nakapaloob nang repository at pangalan ng runner sa service name. Kaya mabibigo ang sudo ./svc.sh install bago ang ./config.sh at magbabalik ng sudo: ./svc.sh: command not found. I-register muna ang runner, saka i-install ang service.
I-install ang mga dependency ng runner
Ang runner ay isang .NET application, kaya nangangailangan ito ng ilang shared library. Umalis sa shell ng runner user at i-install ang mga ito gamit ang sudo, dahil nagsusulat ang script sa system package database.
exit
cd /home/gharunner/actions-runner
sudo ./bin/installdependencies.shSa Ubuntu 24.04, ini-install nito ang libkrb5-3, zlib1g, liblttng-ust1t64, libssl3t64, at libicu74. Sinusubukan ng script ang ilang version name para sa bawat library at ginagamit ang available sa iyong release. Dahil dito, gumagana ang parehong script sa mga mas lumang Ubuntu release at sa Debian.
Kung lalaktawan mo ang hakbang na ito at nawawala ang isa sa mga library, humihinto ang ./config.sh bago ito magsagawa ng anumang operasyon:
Dependencies is missing for Dotnet Core 6.0
Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 6.0 dependencies.Ang nawawalang libicu ay nagbibigay ng parehong payo, ngunit may ibang unang linya, Libicu's dependencies is missing for Dotnet Core 6.0. Parehong nagmumula ang mga ito sa iisang bahagi: sinusuri ng config.sh ang mga bundled library gamit ang ldd, at ng libicu gamit ang ldconfig, bago ito magsimula. Dahil dito, ang unresolved link ay nagpahihinto sa script sa halip na magdulot ng nakalilitong crash sa bandang huli.
I-register ang runner sa iyong repository
Kumuha ng token mula sa repository. Buksan ang Settings, pagkatapos ay Actions, Runners, at New self-hosted runner. Ipinapakita ng page ang registration token. Mag-e-expire ito isang oras matapos itong gawin, kaya i-generate ito kapag handa ka nang i-paste.
Mag-register bilang runner user. Tumangging tumakbo ang config.sh sa ilalim ng 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 \
--replaceIto ang ginagawa ng mga flag na iyon. Tinutukoy ng --name kung paano lilitaw ang runner sa repository, kaya pumili ng pangalang makikilala mo pa rin pagkalipas ng anim na buwan. Nagdaragdag ang --labels ng sarili mong labels; awtomatikong may self-hosted, Linux at X64 na ang runner. Tinutukoy ng --work ang directory kung saan inilalagay ang mga checkout, sa loob ng runner directory. Sinasagot ng --unattended ang mga interactive prompt gamit ang kanilang mga default, na kailangan kapag nasa script ang command. Inaangkin ng --replace ang umiiral nang registration na may parehong pangalan sa halip na mag-fail, na kailangan kapag nire-rebuild mo ang server.
Nagtatapos ang matagumpay na pagtakbo sa mga linyang ito:
√ Runner successfully added
√ Runner connection is good
√ Settings Saved.Nasa runner directory na ang registration bilang .runner, .credentials at .credentials_rsaparams. Tinutukoy ng huling dalawa ang runner na ito sa GitHub, kaya maaaring mag-impersonate rito ang sinumang makakabasa sa mga ito. Ito ang dahilan kung bakit mode 700 ang directory at walang sudo ang user.
I-install ang runner bilang systemd service
Ang ./run.sh sa terminal ay sapat para sa isang test, pero hihinto ito kapag natapos ang SSH session mo. I-install ang service para awtomatikong magsimula ang runner kapag nag-boot. Ipinapaliwanag ng systemd services at timer sa isang VPS ang mismong unit file. Dito, ang svc.sh ang gagawa nito para sa iyo.
exit
cd /home/gharunner/actions-runner
sudo ./svc.sh install gharunner
sudo ./svc.sh start
sudo ./svc.sh statusKailangan ng svc.sh ang root dahil nagsusulat ito ng unit sa /etc/systemd/system at ine-enable ito. Ang argument pagkatapos ng install ay ang user na gagamitin ng service. Tiyaking tahasang ipasa ang gharunner. Kung walang argument, gagamitin ng script ang $SUDO_USER, na iyong admin account. Dahil dito, tatakbo ang bawat job bilang user na maaaring gumamit ng sudo.
Pinangalanan ang unit batay sa repository at runner, sa format na actions.runner.YOUR-USER-YOUR-REPO.vps-runner-1.service. Hindi mo kailangang i-type ito nang manu-mano:
systemctl list-units 'actions.runner.*'
sudo journalctl -u 'actions.runner.*' -n 20 --no-pagerAng maayos na runner ay nagla-log ng √ Connected to GitHub, na sinusundan ng linyang nagtatapos sa Listening for Jobs. Ipinapakita rin ito ng Runners page ng repository bilang Idle. Ang runner na may status na Offline ay maaaring hindi tumatakbo o hindi makakonekta sa GitHub sa port 443.
Magpadala ng job sa runner
Pinipili ng runs-on ang runner batay sa label. Humingi ng self-hosted kasama ang sarili mong label upang hindi mapunta ang job sa runner na hindi mo nilayon.
name: build
on:
push:
branches: [main]
jobs:
build:
runs-on: [self-hosted, linux, vps]
steps:
- uses: actions/checkout@v5
- run: uname -aKung naghihintay ang job sa Waiting for a runner to pick up this job, hindi tugma ang mga label. Dapat mayroon sa runner ang bawat label sa runs-on, kaya kahit isang sobrang salita ay mag-iiwan sa job na naka-queue nang walang anumang error. Ihambing ang listahan sa mga label na ipinapakita sa tabi ng runner sa repository settings.
Bakit hindi dapat pagsamahin ang self-hosted runners at public repositories
Ito ang bahaging madalas nilalaktawan. Malinaw ang guidance ng GitHub: ang self-hosted runners ay “halos hindi dapat gamitin para sa public repositories,” at “walang garantiya na tatakbo ang mga ito sa ephemeral at malilinis na virtual machine, at maaaring patuloy na ma-compromise ng hindi pinagkakatiwalaang code sa isang workflow.”
Simple ang mekanismo. May sarili nitong kopya ng workflow file ang pull request mula sa isang fork. Kung nagpapatakbo ang iyong public repository ng pull request workflows sa iyong runner, maaaring magmungkahi ang sinumang makapag-fork ng repository ng workflow na nagpapatakbo ng kanilang commands sa iyong VPS. Hindi nila kailangan ng write access, dahil ang mismong ipinapanukala nila ang tatakbo.
Napapahina ng approval settings ang panganib na ito pero hindi nila ito inaayos. Sa default policy para sa isang public repository, hinihingi sa maintainer na aprubahan ang workflow ng fork mula sa isang first-time contributor. Itinuturing ng GitHub na first-time contributor ang isang tao hanggang sa ma-merge sa repository ang alinman sa kanilang commit o pull request. Pagkatapos nito, tatakbo ang mga susunod nilang pull request nang walang prompt, at nagbababala mismo ang GitHub na sapat na ang isang maliit na fix na na-merge para mangyari ito. Kaya ang gate ay isang taong nagbabasa ng diff, at madaling hindi mapansin ang payload na nakatago nang tatlong antas sa loob ng build script.
Hindi tumatanggap ng iyong secrets ang isang fork pull request, at read only ang GITHUB_TOKEN nito. Nililimitahan nito ang pinsala sa loob ng GitHub. Wala itong nagagawa para protektahan ang iyong server. May shell ang attacker bilang gharunner, kaya mababasa niya ang bawat file na nababasa ng user na iyon, maaabot ang anumang naaabot ng VPS sa private network nito, at makapag-iiwan ng payload sa ~/.bashrc o sa isang user systemd unit na tatakbo sa susunod na job.
Kapag nag-register gamit ang --ephemeral, tatanggap ang runner ng isang job at pagkatapos ay magde-deregister, kaya hindi mababasa ng isang job ang workspace ng susunod na job. Makakatulong lamang ito kung may nagre-rebuild ng machine o container para sa bawat job, dahil mananatili ang backdoor na isinulat sa home directory ng runner user kahit may bagong registration.
Maikli ang mga susunod na rule. Gamitin ang self-hosted runners para sa private repositories. Kung kailangan mong mag-attach ng isa sa isang public repository, huwag magpatakbo rito ng fork pull requests, huwag magpatakbo ng iba pang serbisyo sa server na iyon, at ituring na disposable ang machine.
Mga Docker job, service container, at anumang workflow step na tumatawag sa docker build ay nangangailangan ng Docker daemon sa runner host. I-install ang Docker sa karaniwang paraan, na saklaw ng Docker at Docker Compose sa isang VPS, at idagdag ang runner user sa docker group.
Unawain muna ang kapalit bago ito gawin. Katumbas ng root ang pagiging miyembro ng docker group, dahil maaaring mag-bind mount ang isang container sa / at tumakbo bilang root sa loob nito. Kaya maaaring basahin at isulat ng workflow na kayang kumonekta sa Docker socket ang bawat file sa VPS, kabilang ang /etc/shadow. Sa isang private repository na may mga pinagkakatiwalaang contributor, maaaring katanggap-tanggap ang kapalit na ito. Sa ibang sitwasyon, inaalis nito ang saysay ng paggamit ng unprivileged user. Pinananatili ng Rootless Docker ang container builds sa loob ng sariling permissions ng runner user, kapalit ng mas mabagal na storage driver at kawalan ng privileged containers.
Mga update at malinis na pag-aalis ng runner
Awtomatikong nag-a-update ang isang self-hosted runner bilang default. Nakikita nito ang bagong release, pinapalitan ang sarili nitong files, at nire-restart ang service, kaya karaniwan ay wala kang kailangang gawin. Para i-off ang self-update, ipasa ang --disableupdate sa ./config.sh kapag nire-register mo ang runner; para sa runner na na-register na, ibig sabihin nito ay i-register itong muli gamit ang flag. Hindi nito hinahayaan ang runner na manatili sa isang bersyon nang tuluyan. Malinaw sa documentation ng GitHub na ang runner na naka-configure gamit ang --disableupdate ay kailangan pa ring i-update nang manual sa loob ng 30 araw mula sa bagong release, kung hindi ay hihinto ang GitHub sa pag-queue ng mga job para rito.
Nananatili ang registration kapag nag-manual update, dahil wala sa tarball ang .runner at .credentials. Ihinto ang service, i-download at i-checksum ang bagong tarball bilang gharunner, i-extract ito sa parehong directory gamit ang tar xzf, pagkatapos ay simulan muli ang service:
cd /home/gharunner/actions-runner
sudo ./svc.sh stop
sudo ./svc.sh startPara alisin ang runner, i-uninstall muna ang service, saka i-deregister ang runner. Mula sa parehong Runners page nakukuha ang removal token, sa ilalim ng sariling Remove button ng runner.
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_HEREKapag dinelete ang directory nang hindi dini-deregister ang runner, mananatili itong nakalista bilang Offline sa repository. Mananatili ito roon hanggang i-click ng isang admin ang Force remove this runner, o hanggang awtomatikong alisin ito ng GitHub makalipas ang 14 na araw na walang koneksyon.
Mga failure mode, kasama ang mga string na makikita mo
Must not run with sudo. Ipinapakita ito ng config.sh at lumalabas kapag pinatakbo ito bilang root. Sinadya ang check na ito dahil ang mga file na pagmamay-ari ng root sa _work ay sumisira sa lahat ng susunod na job na tumatakbo bilang service user. Patakbuhin ang ./config.sh bilang gharunner. Ino-override ng variable na RUNNER_ALLOW_RUNASROOT ang check, pero ipinagpapaliban lamang nito ang problema.
sudo: ./svc.sh: command not found. Nasa tamang directory ka. Hindi pa umiiral ang svc.sh dahil hindi pa nakakumpleto ng registration ang config.sh. I-register ang runner, saka i-install ang service.
Http response code: NotFound from 'POST https://api.github.com/actions/runner-registration'. Karaniwan, hindi valid na registration token ang token. Maaaring nag-expire ito dahil isang oras lamang ang validity nito, o personal access token ang nai-paste kapalit ng registration token mula sa Runners page. Gumawa ng bagong token at i-paste itong muli. Tiyakin ding ang --url ay ang buong repository URL.
Dependencies is missing for Dotnet Core 6.0. Patakbuhin ang sudo ./bin/installdependencies.sh mula sa runner directory bilang root, saka muling mag-register.
Runner Offline pagkatapos ng reboot. Patakbuhin ang systemctl is-enabled 'actions.runner.*'. Kung walang nakalista, hindi kailanman pinatakbo ang ./svc.sh install, kaya umiral lamang ang runner sa loob ng terminal session mo. Kung enabled ang unit at Offline pa rin ang runner, basahin ang journalctl -u 'actions.runner.*' at suriin ang outbound HTTPS.
Napupuno ang disk. Naiipon ang mga checkout, build cache, at Docker image sa ilalim ng _work at sa home directory ng runner user, at walang awtomatikong nagpu-prune ng mga ito. I-monitor ang du -sh /home/gharunner/actions-runner/_work at magdagdag ng naka-schedule na clean-up bago ang disk ang magdulot ng problema.
FAQ
Bakit sinasabi ng sudo ./svc.sh install na command not found?
Dahil wala ang svc.sh sa runner tarball. Ginagawa ito sa runner directory kapag natapos ang pag-register ng ./config.sh, gamit ang pangalan ng repository at runner upang buuin ang service name. Patakbuhin muna ang ./config.sh bilang runner user. Pagkatapos nito, mahahanap ng sudo ./svc.sh install gharunner ang script at magsusulat ito ng unit na pinangalanang actions.runner.OWNER-REPO.RUNNER-NAME.service sa /etc/systemd/system.
Kailangan ko bang magbukas ng firewall port para sa self-hosted runner?
Hindi. Nagbubukas ang runner ng outbound HTTPS connection papunta sa GitHub at pinananatili itong bukas habang naghihintay ng jobs, kaya hindi kailanman nagsisimula ang connection mula sa GitHub papunta sa VPS mo. Payagan ang outbound 443 at panatilihing sarado ang inbound rules. Kung ipinapakitang Offline ang runner kahit tumatakbo ang service nito, suriin ang outbound filtering at DNS sa halip na ang inbound rules.
Maaari ba akong gumamit ng self-hosted runner sa public repository?
Maaari, ngunit hindi ito inirerekomenda ng GitHub. May sarili nitong workflow file ang pull request mula sa fork, kaya sinumang makapag-fork ng repository mo ay maaaring magmungkahi ng mga command na tatakbo sa machine mo. Saklaw lamang ng default approval prompt ang mga contributor na hindi pa nagkaroon ng commit o pull request na na-merge sa repository. Kung ikakabit mo ang runner sa public repository, i-disable ang fork pull request workflows dito, huwag magpatakbo ng ibang workload sa server na iyon, at regular na i-rebuild ang machine.
Bakit nabibigo ang registration gamit ang Http response code: NotFound?
Nagbabalik ng NotFound ang registration call kapag mali ang credential, hindi lamang kapag mali ang URL, kaya nakalilinlang ang mensahe. Nag-e-expire ang registration token isang oras matapos itong ipakita, at hindi tinatanggap ang personal access token para sa call na ito. Buksan muli ang Settings, Actions, Runners, New self-hosted runner, kopyahin ang bagong token, at tiyaking tumutukoy ang value ng --url sa repository kung saan mayroon kang admin rights.