ติดตั้ง GitHub Actions runner บน VPS ด้วย Ubuntu 24.04
คู่มือติดตั้ง self-hosted GitHub Actions runner บน Ubuntu 24.04 ตั้งแต่สร้าง user ตรวจสอบ checksum ใช้ config.sh ติดตั้ง systemd และทำความเข้าใจความเสี่ยงจาก fork pull request
หน้าที่ของ self-hosted GitHub Actions runner
self-hosted GitHub Actions runner คือโปรแกรมที่คุณติดตั้งบน VPS ของคุณเองเพื่อคอยดึงงานจาก GitHub มาประมวลผลบนฮาร์ดแวร์ของคุณ คุณต้องลงทะเบียน runner เข้ากับ repository หนึ่งแห่ง ติดตั้งเป็น systemd service เพื่อให้โปรแกรมเริ่มทำงานใหม่โดยอัตโนมัติหลังรีบูต โดย GitHub จะเป็นผู้กำหนดตารางงานและเซิร์ฟเวอร์ของคุณจะเป็นผู้ประมวลผล
การทำ CI (continuous integration) บนเครื่องที่คุณดูแลเองมีประโยชน์หลัก 2 ประการ คือ ไม่ต้องเสียค่าใช้จ่ายตามจำนวนนาทีที่ใช้ประมวลผล และงานสามารถเข้าถึงทรัพยากรที่มีเฉพาะบนเครื่องของคุณได้ เช่น build cache หรือเครือข่ายภายใน อย่างไรก็ตาม สิ่งที่ต้องแลกมาคือความปลอดภัย เนื่องจาก runner จะประมวลผลทุกคำสั่งที่ระบุในไฟล์ workflow ด้วยสิทธิ์ของผู้ใช้ที่คุณกำหนดไว้ ดังนั้นไฟล์ workflow จึงเปรียบเสมือนการสั่งรันโค้ดจากระยะไกล (remote code execution) โดยธรรมชาติ สำหรับ private repository กรณีนี้ถือว่ายอมรับได้เพราะมีเพียงบุคคลที่คุณไว้วางใจเท่านั้นที่สามารถเพิ่มไฟล์ดังกล่าวได้ แต่สำหรับ public repository นี่ถือเป็นความเสี่ยงที่สำคัญ ซึ่งเนื้อหาในส่วนที่เกี่ยวกับ fork pull requests จะอธิบายกลไกความเสี่ยงนี้ไว้
เนื้อหาทั้งหมดด้านล่างนี้ใช้ Ubuntu 24.04 ร่วมกับ runner เวอร์ชัน 2.338.0 ซึ่งเป็นเวอร์ชันล่าสุด ณ วันที่ 12 ตุลาคม 2026
สิ่งที่ต้องเตรียมก่อนเริ่ม
เริ่มจาก VPS ที่มีบัญชีผู้ดูแลระบบทั่วไปและสิทธิ์ sudo ซึ่งเป็นสถานะที่ได้หลังทำตาม ขั้นตอนสิบนาทีแรกบน VPS ใหม่ คุณไม่จำเป็นต้องเปิดพอร์ตขาเข้า runner จะเปิดการเชื่อมต่อ HTTPS (hypertext transfer protocol secure) ขาออกไปยัง GitHub และคงการเชื่อมต่อนี้ไว้ระหว่างรอรับงาน ดังนั้น GitHub จะไม่เชื่อมต่อเข้ามายังเซิร์ฟเวอร์ของคุณ ไฟร์วอลล์สามารถปิดกั้นการเชื่อมต่อจากภายนอกทั้งหมดได้ และงานยังคงเข้ามาได้
คุณต้องมีสิทธิ์ผู้ดูแลระบบของ repository ด้วย เนื่องจากโทเค็นสำหรับลงทะเบียนจะแสดงอยู่ในการตั้งค่า repository
สร้างผู้ใช้เฉพาะสำหรับ runner
อย่าเรียกใช้ runner ในฐานะ root หรือผู้ดูแลระบบของคุณเอง งานทุกงานจะสืบทอดสิทธิ์ของผู้ใช้ runner ดังนั้น workflow ที่เรียกใช้ sudo จะทำงานสำเร็จ หากผู้ใช้ runner สามารถใช้ sudo ได้ สร้างผู้ใช้ที่ไม่มีสิทธิ์พิเศษ โดยให้ผู้ใช้นี้เป็นเจ้าของเฉพาะ home directory ของตนเองเท่านั้น บัญชีผู้ใช้ที่มีสิทธิ์น้อยที่สุดบน VPS อธิบายรูปแบบทั่วไป ส่วนต่อไปนี้เป็นการกำหนดค่าที่ใช้ในกรณีนี้
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-runnerpasswd -l จะล็อก password เพื่อไม่ให้ผู้ใดเข้าสู่ระบบในฐานะ gharunner ด้วย password ดังกล่าว การกำหนดโหมด 700 ให้กับ runner directory มีความสำคัญ เนื่องจาก runner จะจัดเก็บข้อมูลรับรองไว้ที่นั่นในรูปแบบข้อความธรรมดา และ checkout อาจมี source code ส่วนตัวอยู่
ตรวจสอบคุณสมบัติทั้งสองรายการก่อนดำเนินการต่อ:
sudo passwd -S gharunner
sudo -l -U gharunnerpasswd -S จะแสดงบรรทัดที่ขึ้นต้นด้วย gharunner L โดย L หมายความว่า password ถูกล็อกไว้ sudo -l -U gharunner ควรแสดงผลเป็น is not allowed to run sudo หากแสดงรายการคำสั่งที่อนุญาตแทน แสดงว่าบัญชีนี้อยู่ใน sudo group และการแยกสิทธิ์ที่เพิ่งตั้งค่าไว้จะไม่ทำงานแล้ว
ดาวน์โหลด runner และตรวจสอบไฟล์ tarball
ให้ดำเนินการในฐานะผู้ใช้ runner ตั้งแต่ขั้นตอนนี้เป็นต้นไป
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"ให้รัน uname -m ก่อนหากคุณไม่แน่ใจเกี่ยวกับสถาปัตยกรรมของระบบ x86_64 จะใช้ไฟล์ linux-x64 ที่ระบุไว้ด้านบน ส่วน aarch64 จะใช้ actions-runner-linux-arm64-${RUNNER_VERSION}.tar.gz
จากนั้นให้ตรวจสอบไฟล์ที่คุณดาวน์โหลดมา ค่า SHA256 (secure hash algorithm, 256 bit) ด้านล่างนี้ใช้สำหรับไฟล์ tarball เวอร์ชัน 2.338.0 x64 โดย GitHub จะแสดงค่าสำหรับ release ปัจจุบันไว้ที่หน้า release และบนหน้าจอ New self-hosted runner ค่านี้จะเปลี่ยนไปในทุกเวอร์ชัน ดังนั้นให้คัดลอกค่าจากแหล่งข้อมูลดังกล่าวเมื่อคุณติดตั้งเวอร์ชันอื่น
echo "af4b794c1bc41d73d40535e3fe092a39f9679cd8d965954c2aca25a05ca41d32 actions-runner-linux-x64-2.338.0.tar.gz" | sha256sum -cการดาวน์โหลดที่สมบูรณ์จะแสดงผลลัพธ์หนึ่งบรรทัดดังนี้:
actions-runner-linux-x64-2.338.0.tar.gz: OKไฟล์ที่ถูกตัดทอนหรือถูกแก้ไขจะแสดงข้อความแจ้งความล้มเหลวและคำเตือน:
actions-runner-linux-x64-2.338.0.tar.gz: FAILED
sha256sum: WARNING: 1 computed checksum did NOT matchอย่าข้ามขั้นตอนการตรวจสอบนี้แล้วปล่อยให้ tar เป็นผู้ตรวจพบปัญหาแทน ไฟล์ archive ที่เขียนข้อมูลไม่ครบจะทำให้เกิดความล้มเหลวด้วย gzip: stdin: unexpected end of file และ tar: Unexpected EOF in archive ซึ่งจะแจ้งให้คุณทราบว่าไฟล์เสียหาย แต่จะไม่ระบุว่าไฟล์ถูกตัดทอนหรือถูกแทนที่
tar xzf ./actions-runner-linux-x64-2.338.0.tar.gz
lstarball มีอะไรบ้าง และไม่มีอะไรบ้าง
หลังจากแตกไฟล์แล้ว ไดเรกทอรีจะมี config.sh, run.sh, env.sh, safe_sleep.sh, bin/ และ externals/ โดย bin/ จะมีไบนารีของ runner และ bin/installdependencies.sh ส่วน externals/ จะมี Node runtime ที่รวมมาให้ ซึ่งใช้รัน action ของ JavaScript
ขณะนี้ยังไม่มี svc.sh เอกสารของ GitHub อธิบายว่าไฟล์นี้เป็นสคริปต์ “ที่สร้างขึ้นหลังจากเพิ่ม runner สำเร็จ” เนื่องจากไฟล์นี้สร้างจากเทมเพลต โดยฝังชื่อ repository และชื่อ runner ของคุณไว้ในชื่อ service ดังนั้น sudo ./svc.sh install ก่อน ./config.sh จะล้มเหลวด้วย sudo: ./svc.sh: command not found ให้ลงทะเบียนก่อน แล้วจึงติดตั้ง service
ติดตั้ง dependencies สำหรับ runner
Runner เป็นแอปพลิเคชัน .NET จึงจำเป็นต้องใช้ shared library บางตัว ให้คุณออกจาก shell ของผู้ใช้ runner แล้วติดตั้ง library เหล่านี้ด้วย sudo เนื่องจากสคริปต์จำเป็นต้องเขียนข้อมูลลงในฐานข้อมูลแพ็กเกจของระบบ
exit
cd /home/gharunner/actions-runner
sudo ./bin/installdependencies.shบน Ubuntu 24.04 ระบบจะดึง libkrb5-3, zlib1g, liblttng-ust1t64, libssl3t64 และ libicu74 มาติดตั้ง สคริปต์จะพยายามตรวจสอบชื่อเวอร์ชันของ library แต่ละตัวและเลือกเวอร์ชันที่ตรงกับรุ่นของระบบปฏิบัติการที่คุณใช้งานอยู่ ซึ่งเป็นเหตุผลว่าทำไมสคริปต์เดียวกันนี้จึงสามารถใช้งานได้ทั้งบน Ubuntu รุ่นเก่าและบน Debian
หากคุณข้ามขั้นตอนนี้ไปและ library ตัวใดตัวหนึ่งขาดหายไป ./config.sh จะหยุดทำงานก่อนที่จะเริ่มดำเนินการใดๆ:
Dependencies is missing for Dotnet Core 6.0
Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 6.0 dependencies.หากขาด libicu จะแสดงคำแนะนำในลักษณะเดียวกันภายใต้บรรทัดแรกที่ต่างออกไปคือ Libicu's dependencies is missing for Dotnet Core 6.0 ทั้งสองกรณีมีที่มาจากแหล่งเดียวกัน คือ config.sh จะตรวจสอบ library ที่รวมมาด้วย ldd และ libicu ด้วย ldconfig ก่อนที่จะเริ่มทำงาน ดังนั้นหากมีลิงก์ที่ไม่ได้รับการแก้ไข สคริปต์จะหยุดทำงานทันทีแทนที่จะปล่อยให้เกิดข้อผิดพลาดที่หาสาเหตุได้ยากในภายหลัง
ลงทะเบียน runner กับ repository ของคุณ
รับ token จาก repository โดยไปที่ Settings จากนั้นเลือก Actions ตามด้วย Runners และ New self-hosted runner หน้าเว็บจะแสดง registration token ซึ่งจะมีอายุการใช้งาน 1 ชั่วโมงหลังจากสร้าง ดังนั้นให้สร้างเมื่อคุณพร้อมที่จะนำไปวางใช้งานเท่านั้น
ลงทะเบียนในฐานะผู้ใช้ runner เนื่องจาก config.sh ไม่อนุญาตให้รันภายใต้ 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คำอธิบายการทำงานของ flag เหล่านี้ --name คือชื่อที่ runner จะปรากฏใน repository ดังนั้นควรเลือกชื่อที่คุณจะยังจำได้ในอีก 6 เดือนข้างหน้า --labels ใช้สำหรับเพิ่ม label ของคุณเอง โดยปกติ runner จะมี label พื้นฐานคือ self-hosted, Linux และ X64 ติดมาให้อยู่แล้วโดยไม่ต้องระบุเพิ่ม --work คือการกำหนดชื่อไดเรกทอรีสำหรับเก็บไฟล์ที่ checkout มา ซึ่งจะอยู่ภายในไดเรกทอรีของ runner --unattended คือการตอบคำถามแบบโต้ตอบด้วยค่าเริ่มต้น ซึ่งเป็นสิ่งที่ต้องการเมื่อรันคำสั่งผ่านสคริปต์ --replace คือการเข้าแทนที่การลงทะเบียนเดิมที่มีชื่อเดียวกันแทนที่จะล้มเหลว ซึ่งเป็นสิ่งที่ต้องการเมื่อคุณสร้างเซิร์ฟเวอร์ขึ้นมาใหม่
การรันที่สำเร็จจะจบลงด้วยบรรทัดเหล่านี้:
√ Runner successfully added
√ Runner connection is good
√ Settings Saved.การลงทะเบียนจะถูกบันทึกไว้ในไดเรกทอรีของ runner ในชื่อ .runner, .credentials และ .credentials_rsaparams ไฟล์สองไฟล์หลังใช้สำหรับระบุตัวตนของ runner นี้ต่อ GitHub ดังนั้นใครก็ตามที่สามารถอ่านไฟล์เหล่านี้ได้จะสามารถสวมรอยเป็น runner นี้ได้ นี่คือเหตุผลที่ไดเรกทอรีต้องถูกตั้งค่าสิทธิ์เป็น 700 และผู้ใช้ต้องไม่มีสิทธิ์ sudo
ติดตั้ง runner เป็นบริการ systemd
การเรียกใช้ ./run.sh ในเทอร์มินัลเหมาะสำหรับการทดสอบครั้งเดียว แต่โปรเซสจะหยุดเมื่อเซสชัน SSH สิ้นสุดลง ให้ติดตั้งบริการเพื่อให้ runner เริ่มทำงานเมื่อระบบบูต บริการและตัวจับเวลาของ systemd บน VPS อธิบายไฟล์ unit โดยละเอียด ส่วน svc.sh จะสร้างไฟล์ดังกล่าวให้คุณ
exit
cd /home/gharunner/actions-runner
sudo ./svc.sh install gharunner
sudo ./svc.sh start
sudo ./svc.sh statussvc.sh ต้องใช้สิทธิ์ root เนื่องจากสคริปต์จะเขียน unit ลงใน /etc/systemd/system และเปิดใช้งาน unit นั้น อาร์กิวเมนต์หลัง install คือผู้ใช้ที่บริการจะทำงานด้วย ให้ระบุ gharunner อย่างชัดเจน หากไม่ระบุอาร์กิวเมนต์ สคริปต์จะใช้ค่าเริ่มต้นเป็น $SUDO_USER ซึ่งเป็นบัญชีผู้ดูแลระบบของคุณ จากนั้นทุกงานจะทำงานด้วยผู้ใช้ที่สามารถใช้ sudo ได้
ชื่อ unit ตั้งตาม repository และ runner ในรูปแบบ actions.runner.YOUR-USER-YOUR-REPO.vps-runner-1.service คุณไม่จำเป็นต้องพิมพ์ชื่อดังกล่าวเอง:
systemctl list-units 'actions.runner.*'
sudo journalctl -u 'actions.runner.*' -n 20 --no-pagerrunner ที่ทำงานปกติจะบันทึก √ Connected to GitHub จากนั้นบันทึกอีกบรรทัดที่ลงท้ายด้วย Listening for Jobs และหน้า Runners ของ repository จะแสดงสถานะเป็น Idle หาก runner แสดงสถานะเป็น Offline แสดงว่า runner ไม่ได้ทำงานหรือไม่สามารถเชื่อมต่อ GitHub ผ่านพอร์ต 443 ได้
ส่งงานไปยัง runner
runs-on ใช้เลือก runner ตาม label ขอ self-hosted พร้อม label ของคุณเอง เพื่อป้องกันไม่ให้งานไปทำงานบน runner ที่ไม่ได้ตั้งใจ
name: build
on:
push:
branches: [main]
jobs:
build:
runs-on: [self-hosted, linux, vps]
steps:
- uses: actions/checkout@v5
- run: uname -aหากงานค้างอยู่ที่ Waiting for a runner to pick up this job แสดงว่า label ไม่ตรงกัน label ทุกตัวใน runs-on ต้องมีอยู่บน runner หากมีคำเกินมาเพียงหนึ่งคำ งานจะยังคงอยู่ในคิวโดยไม่มีข้อผิดพลาดปรากฏที่ใด ตรวจสอบรายการนี้เทียบกับ label ที่แสดงถัดจาก runner ในการตั้งค่า repository
เหตุผลที่ self-hosted runners และ public repositories ไม่ควรใช้ร่วมกัน
นี่คือส่วนที่ผู้คนมักมองข้าม คำแนะนำของ GitHub นั้นชัดเจนตรงไปตรงมา: self-hosted runners "ไม่ควรถูกนำมาใช้กับ public repositories แทบทุกกรณี" และ "ไม่มีการรับประกันว่าจะทำงานใน virtual machines ที่สะอาดและถูกลบทิ้งหลังใช้งาน (ephemeral) จึงอาจถูกโจมตีอย่างถาวรโดยโค้ดที่ไม่น่าเชื่อถือใน workflow ได้"
กลไกการทำงานนั้นเรียบง่าย pull request จาก fork จะนำไฟล์ workflow ของตัวเองมาด้วย หาก public repository ของคุณรัน workflow ของ pull request บน runner ของคุณ ใครก็ตามที่สามารถ fork repository นั้นไปได้ ก็สามารถเสนอ workflow ที่รันคำสั่งของตนเองบน VPS ของคุณได้ โดยไม่จำเป็นต้องมีสิทธิ์เขียน (write access) เพราะสิ่งที่พวกเขากำลังเสนอคือสิ่งที่ถูกนำไปรันจริง
การตั้งค่าการอนุมัติ (approval settings) ช่วยลดความเสี่ยงนี้ได้แต่ไม่ได้แก้ไขปัญหา นโยบายเริ่มต้นสำหรับ public repository จะขอให้ผู้ดูแลระบบอนุมัติ workflow จาก fork ของผู้ร่วมงานครั้งแรก GitHub จะนับว่าบุคคลนั้นเป็นผู้ร่วมงานครั้งแรกจนกว่า commit หรือ pull request ของพวกเขาจะถูก merge เข้าสู่ repository หลังจากนั้น pull request ครั้งถัดไปของพวกเขาจะรันโดยไม่มีการแจ้งเตือน และ GitHub เองก็เตือนว่าการแก้ไขเล็กน้อยที่ถูก merge เข้าไปก็เพียงพอที่จะผ่านเกณฑ์นี้ได้ ดังนั้นด่านตรวจจึงขึ้นอยู่กับมนุษย์ที่อ่าน diff ซึ่ง payload ที่ซ่อนอยู่ลึกสามชั้นใน build script นั้นตรวจสอบได้ยาก
pull request จาก fork จะไม่ได้รับ secrets ของคุณ และ GITHUB_TOKEN ของมันจะเป็นแบบอ่านได้อย่างเดียว ซึ่งจำกัดความเสียหายภายใน GitHub แต่ไม่ได้ช่วยอะไรกับเซิร์ฟเวอร์ของคุณ ผู้โจมตีจะมี shell ในฐานะ gharunner ดังนั้นพวกเขาจึงสามารถอ่านทุกไฟล์ที่ผู้ใช้นั้นอ่านได้ เข้าถึงทุกสิ่งที่ VPS เข้าถึงได้บนเครือข่ายส่วนตัว และทิ้งสิ่งตกค้างไว้ใน ~/.bashrc หรือสร้าง systemd unit ของผู้ใช้ที่รันในระหว่าง job ถัดไป
การลงทะเบียนด้วย --ephemeral ทำให้ runner ยอมรับหนึ่ง job แล้วยกเลิกการลงทะเบียน ดังนั้นหนึ่ง job จึงไม่สามารถอ่าน workspace ของ job ถัดไปได้ แต่วิธีนี้จะช่วยได้ก็ต่อเมื่อมีการสร้างเครื่องหรือ container ใหม่สำหรับทุก job เท่านั้น เพราะ backdoor ที่ถูกเขียนลงใน home directory ของผู้ใช้ runner จะยังคงอยู่แม้จะลงทะเบียนใหม่ก็ตาม
กฎที่ตามมานี้สั้นและกระชับ ให้ใช้ self-hosted runners สำหรับ private repositories หากคุณจำเป็นต้องเชื่อมต่อ runner เข้ากับ public repository ห้ามรัน pull request จาก fork บนนั้น อย่าเก็บสิ่งอื่นใดไว้บนเซิร์ฟเวอร์นั้น และให้ถือว่าเครื่องนั้นเป็นเครื่องที่ใช้แล้วทิ้งได้
งาน Docker และกลุ่มที่มีสิทธิ์เทียบเท่า root
งานในคอนเทนเนอร์ คอนเทนเนอร์บริการ และขั้นตอนใดก็ตามของ workflow ที่เรียกใช้ docker build ต้องมี Docker daemon ทำงานอยู่บนโฮสต์ runner ติดตั้ง Docker ตามวิธีมาตรฐานตามที่ Docker และ Docker Compose บน VPS อธิบายไว้ จากนั้นเพิ่มผู้ใช้ runner ลงในกลุ่ม docker
ทำความเข้าใจข้อแลกเปลี่ยนก่อนดำเนินการ การเป็นสมาชิกกลุ่ม docker เทียบเท่ากับการมีสิทธิ์ root เนื่องจากคอนเทนเนอร์สามารถ bind mount / และทำงานเป็น root ภายในคอนเทนเนอร์ได้ ดังนั้น workflow ที่เชื่อมต่อกับ Docker socket ได้จึงสามารถอ่านและเขียนไฟล์ทุกไฟล์บน VPS รวมถึง /etc/shadow ได้ด้วย สำหรับ repository ส่วนตัวที่มีผู้ร่วมพัฒนาที่เชื่อถือได้ นี่อาจเป็นข้อแลกเปลี่ยนที่ยอมรับได้ แต่ในกรณีอื่นจะทำให้การใช้ผู้ใช้ที่ไม่มีสิทธิ์พิเศษหมดความหมาย Rootless Docker จะจำกัดการ build คอนเทนเนอร์ให้อยู่ภายใต้สิทธิ์ของผู้ใช้ runner เอง โดยแลกกับ storage driver ที่ทำงานช้าลงและไม่สามารถใช้คอนเทนเนอร์ที่มีสิทธิ์พิเศษได้
การอัปเดตและการลบ runner อย่างหมดจด
โดยปกติแล้ว self-hosted runner จะอัปเดตตัวเองโดยอัตโนมัติ เมื่อตรวจพบ release ใหม่ ระบบจะแทนที่ไฟล์เดิมและรีสตาร์ท service ให้เอง ดังนั้นโดยทั่วไปคุณจึงไม่ต้องดำเนินการใดๆ หากต้องการปิดการอัปเดตอัตโนมัติ ให้ส่งแฟล็ก --disableupdate ไปยัง ./config.sh ในขั้นตอนการลงทะเบียน runner สำหรับ runner ที่ลงทะเบียนไปแล้ว คุณต้องลงทะเบียนใหม่โดยเพิ่มแฟล็กดังกล่าวเข้าไป อย่างไรก็ตาม วิธีนี้ไม่ได้หมายความว่าคุณจะสามารถใช้เวอร์ชันเดิมได้ตลอดไป เอกสารของ GitHub ระบุไว้อย่างชัดเจนว่า runner ที่กำหนดค่าด้วย --disableupdate ยังคงต้องได้รับการอัปเดตด้วยตนเองภายใน 30 วันหลังจากมี release ใหม่ มิฉะนั้น GitHub จะหยุดส่งงานเข้าคิวให้ runner นั้น
การอัปเดตด้วยตนเองจะยังคงสถานะการลงทะเบียนไว้ เนื่องจากไฟล์ .runner และ .credentials ไม่ได้รวมอยู่ใน tarball ให้หยุดการทำงานของ service ดาวน์โหลดและตรวจสอบ checksum ของ tarball เวอร์ชันใหม่ในฐานะ gharunner จากนั้นแตกไฟล์ทับลงในไดเรกทอรีเดิมด้วย tar xzf แล้วจึงเริ่มการทำงานของ service อีกครั้ง:
cd /home/gharunner/actions-runner
sudo ./svc.sh stop
sudo ./svc.sh startหากต้องการลบ runner ให้ถอนการติดตั้ง service ก่อน แล้วจึงยกเลิกการลงทะเบียน (deregister) โดยสามารถขอรับโทเค็นสำหรับการลบได้จากหน้า Runners ในตำแหน่งเดียวกับปุ่ม Remove ของ 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_HEREการลบไดเรกทอรีทิ้งโดยไม่ยกเลิกการลงทะเบียนจะทำให้ runner ยังคงแสดงสถานะเป็น Offline อยู่ใน repository ซึ่งจะค้างอยู่ในรายการจนกว่าผู้ดูแลระบบจะคลิก Force remove this runner หรือจนกว่า GitHub จะลบออกโดยอัตโนมัติหลังจากไม่มีการเชื่อมต่อเป็นเวลา 14 วัน
รูปแบบความล้มเหลวและข้อความที่คุณจะพบ
Must not run with sudo: config.sh จะแสดงข้อความนี้และหยุดทำงานเมื่อรันด้วยสิทธิ์ root การตรวจสอบนี้มีเจตนาเพื่อป้องกัน เนื่องจากไฟล์ที่ root เป็นเจ้าของใน _work จะทำให้งานทุกอย่างที่รันในฐานะ service user ในภายหลังเกิดความเสียหาย ให้รัน ./config.sh ในฐานะ gharunner ส่วนตัวแปร RUNNER_ALLOW_RUNASROOT สามารถใช้เพื่อข้ามการตรวจสอบนี้ได้ แต่การใช้งานจะทำให้เกิดปัญหาในขั้นตอนถัดไปแทน
sudo: ./svc.sh: command not found: คุณอยู่ในไดเรกทอรีที่ถูกต้องแล้ว แต่ svc.sh ยังไม่มีอยู่จริง เนื่องจาก config.sh ยังไม่ได้ลงทะเบียนให้เสร็จสมบูรณ์ ให้ทำการลงทะเบียน runner ก่อน แล้วจึงติดตั้ง service
Http response code: NotFound from 'POST https://api.github.com/actions/runner-registration': โดยปกติแล้ว token ที่ใช้ไม่ถูกต้องหรือไม่ใช่ registration token ที่ใช้งานได้ อาจเป็นเพราะ token หมดอายุเนื่องจากมีอายุการใช้งานเพียง 1 ชั่วโมง หรือมีการนำ personal access token มาวางแทนที่ registration token จากหน้า Runners ให้สร้าง token ใหม่และวางใหม่อีกครั้ง พร้อมตรวจสอบว่า --url คือ URL ของ repository แบบเต็ม
Dependencies is missing for Dotnet Core 6.0: ให้รัน sudo ./bin/installdependencies.sh จากไดเรกทอรีของ runner ด้วยสิทธิ์ root จากนั้นทำการลงทะเบียนใหม่อีกครั้ง
Runner ออฟไลน์หลังการรีบูต: ให้รัน systemctl is-enabled 'actions.runner.*' หากไม่มีรายการแสดงขึ้นมา แสดงว่า ./svc.sh install ไม่เคยถูกรันมาก่อน ทำให้ runner มีอยู่แค่ภายใน session ของ terminal เท่านั้น หาก unit ถูกเปิดใช้งานแล้วแต่ runner ยังคงสถานะ Offline ให้ตรวจสอบ journalctl -u 'actions.runner.*' และตรวจสอบการเชื่อมต่อ HTTPS ขาออก
ดิสก์เต็ม: ข้อมูล checkout, build cache และ Docker images จะสะสมอยู่ใน _work และในโฮมไดเรกทอรีของ runner user โดยไม่มีกระบวนการลบข้อมูลอัตโนมัติให้คุณ ให้คอยตรวจสอบ du -sh /home/gharunner/actions-runner/_work และเพิ่มการตั้งเวลาล้างข้อมูลก่อนที่ดิสก์จะเต็มจนระบบหยุดทำงานเอง
FAQ
ทำไม sudo ./svc.sh install ถึงแจ้งว่า command not found?
เพราะ svc.sh ไม่มีอยู่ใน tarball ของ runner มันจะถูกสร้างขึ้นในไดเรกทอรีของ runner เมื่อ ./config.sh ลงทะเบียนเสร็จสิ้น โดยใช้ชื่อ repository และชื่อ runner ของคุณเพื่อสร้างชื่อ service ให้รัน ./config.sh ในฐานะผู้ใช้ runner ก่อน หลังจากนั้น sudo ./svc.sh install gharunner จะพบสคริปต์และเขียน unit ที่ชื่อ actions.runner.OWNER-REPO.RUNNER-NAME.service ลงใน /etc/systemd/system
ฉันจำเป็นต้องเปิดพอร์ต firewall สำหรับ self-hosted runner หรือไม่?
ไม่จำเป็น runner จะเปิดการเชื่อมต่อขาออกผ่าน HTTPS ไปยัง GitHub และคงการเชื่อมต่อไว้ในขณะที่รอรับงาน ดังนั้น GitHub จึงไม่เคยเป็นฝ่ายเริ่มการเชื่อมต่อมายัง VPS ของคุณ ให้คุณอนุญาตการเชื่อมต่อขาออกผ่านพอร์ต 443 และปิดกฎการเชื่อมต่อขาเข้าไว้ตามเดิม หาก runner แสดงสถานะ Offline ในขณะที่ service กำลังทำงานอยู่ ให้ตรวจสอบการกรองการเชื่อมต่อขาออกและ DNS แทนที่จะตรวจสอบกฎการเชื่อมต่อขาเข้า
ฉันสามารถใช้ self-hosted runner บน public repository ได้หรือไม่?
คุณสามารถทำได้ แต่ GitHub ไม่แนะนำให้ทำ pull request จาก fork จะนำไฟล์ workflow ของตัวเองมาด้วย ดังนั้นใครก็ตามที่สามารถ fork repository ของคุณได้ สามารถเสนอคำสั่งที่รันบนเครื่องของคุณได้ การแจ้งเตือนเพื่อขออนุมัติเริ่มต้นจะครอบคลุมเฉพาะผู้ร่วมงานที่ไม่เคยมี commit หรือ pull request ถูก merge เข้าสู่ repository มาก่อนเท่านั้น หากคุณเชื่อมต่อ runner เข้ากับ public repository ให้ปิดการใช้งาน workflow ของ pull request จาก fork บนนั้น อย่าเก็บสิ่งอื่นใดไว้บนเซิร์ฟเวอร์นั้น และให้สร้างเครื่องใหม่ตามกำหนดเวลา
ทำไมการลงทะเบียนถึงล้มเหลวด้วย Http response code: NotFound?
การเรียกใช้งานลงทะเบียนจะตอบกลับเป็น NotFound เมื่อ credential ไม่ถูกต้อง ไม่ใช่แค่เมื่อ URL ผิดเท่านั้น ซึ่งทำให้ข้อความแจ้งเตือนอาจทำให้เข้าใจผิดได้ token สำหรับการลงทะเบียนจะมีอายุการใช้งานหนึ่งชั่วโมงหลังจากที่แสดงผล และ personal access token จะไม่สามารถใช้สำหรับการเรียกใช้งานนี้ได้ ให้เปิด Settings, Actions, Runners, New self-hosted runner อีกครั้ง คัดลอก token ใหม่ และยืนยันว่าค่า --url ชี้ไปยัง repository ที่คุณมีสิทธิ์ระดับผู้ดูแลระบบ (admin rights)