SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor

راهنمای نصب GitHub Actions Runner روی VPS

نحوه راه‌اندازی GitHub Actions runner روی Ubuntu 24.04 با استفاده از systemd. این راهنما شامل مراحل ثبت، بررسی checksum و مدیریت ریسک امنیتی در pull request است.

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

یک runner خودمیزبان (self-hosted) در GitHub Actions چه کاری انجام می‌دهد

یک runner خودمیزبان در GitHub Actions برنامه‌ای است که آن را روی VPS شخصی خود نصب می‌کنید تا از GitHub درخواست کار (job) کرده و آن‌ها را روی سخت‌افزار شما اجرا کند. شما آن را برای یک مخزن (repository) ثبت می‌کنید، به عنوان یک سرویس systemd نصب می‌کنید و پس از هر بار راه‌اندازی مجدد (reboot)، به‌طور خودکار بالا می‌آید. GitHub کار را زمان‌بندی می‌کند و سرور شما عملیات را انجام می‌دهد.

یکپارچه‌سازی مداوم (CI) روی سیستمی که مالکیت آن با شماست، به دو دلیل ارزشمند است. اول اینکه دقایق ساخت (build minutes) دیگر محاسبه و شارژ نمی‌شوند، و دوم اینکه یک job می‌تواند به منابعی دسترسی پیدا کند که فقط در ماشین شما موجود است، مانند یک کش ساخت (build cache) آماده یا یک شبکه خصوصی. هزینه این کار، امنیت است. runner هر دستوری که در فایل workflow آمده باشد را با کاربری که شما تعیین کرده‌اید اجرا می‌کند، بنابراین فایل workflow ذاتاً به معنای اجرای کد از راه دور (remote code execution) است. در یک مخزن خصوصی این موضوع مشکلی ندارد، زیرا فقط افراد مورد اعتماد شما می‌توانند فایلی به آن اضافه کنند. در یک مخزن عمومی، این یک ریسک واقعی است و بخشی که درباره pull requestهای fork شده است، مکانیزم آن را توضیح می‌دهد.

تمام موارد زیر بر اساس Ubuntu 24.04 و نسخه runner 2.338.0 است که نسخه منتشرشده در تاریخ 12 اکتبر 2026 می‌باشد.

پیش‌نیازهای شروع کار

کار را با یک VPS که دارای یک حساب کاربری عادی با دسترسی sudo است شروع کنید؛ همان وضعیتی که در ده دقیقه اول روی یک VPS جدید به آن می‌رسید. نیازی به باز کردن پورت ورودی (inbound) ندارید. runner یک اتصال خروجی (outbound) از نوع HTTPS به GitHub برقرار می‌کند و آن را باز نگه می‌دارد تا منتظر دریافت کار بماند؛ بنابراین GitHub هرگز مستقیماً به سرور شما متصل نمی‌شود. فایروال شما می‌تواند برای دنیای خارج بسته بماند و با این حال، jobها همچنان دریافت خواهند شد.

شما همچنین به دسترسی مدیریتی (admin) روی مخزن (repository) نیاز دارید، زیرا توکن ثبت‌نام در تنظیمات مخزن نمایش داده می‌شود.

ایجاد یک کاربر اختصاصی برای runner

هرگز runner را با دسترسی root یا کاربر مدیریتی خود اجرا نکنید. هر job تمام دسترسی‌های کاربر runner را به ارث می‌برد؛ بنابراین اگر کاربر runner اجازه استفاده از sudo را داشته باشد، یک workflow که دستور sudo را فراخوانی می‌کند، با موفقیت اجرا خواهد شد. یک کاربر بدون دسترسی‌های ویژه (unprivileged) بسازید که مالک هیچ فایلی جز دایرکتوری home خود نباشد. بخش حساب‌های کاربری با کمترین دسترسی روی 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-runner

دستور passwd -l رمز عبور را قفل می‌کند تا هیچ‌کس نتواند با استفاده از آن به عنوان gharunner وارد سیستم شود. تنظیم حالت 700 برای دایرکتوری runner اهمیت دارد، زیرا runner اعتبارنامه‌های خود را به صورت متن ساده (cleartext) در آنجا ذخیره می‌کند و ممکن است یک checkout حاوی کدهای منبع خصوصی باشد.

پیش از ادامه، هر دو ویژگی را بررسی کنید:

sudo passwd -S gharunner
sudo -l -U gharunner

دستور passwd -S خطی را چاپ می‌کند که با gharunner L شروع می‌شود؛ جایی که L به معنای قفل بودن رمز عبور است. دستور sudo -l -U gharunner باید با is not allowed to run sudo پاسخ دهد. اگر در عوض لیستی از دستورات مجاز چاپ شد، یعنی حساب کاربری در گروه sudo قرار دارد و ایزولاسیونی که ایجاد کردید از بین رفته است.

دانلود 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 (الگوریتم هش امن، 256 بیتی) زیر برای فایل tarball نسخه 2.338.0 و معماری x64 است. گیت‌هاب مقدار مربوط به نسخه فعلی را در صفحه 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 مشکل را پیدا کند. یک آرشیو ناقص با خطاهای gzip: stdin: unexpected end of file و tar: Unexpected EOF in archive مواجه می‌شود که به شما می‌گوید فایل خراب است، اما مشخص نمی‌کند که آیا فایل ناقص دانلود شده یا جایگزین شده است.

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

محتویات فایل tarball و آنچه در آن وجود ندارد

پس از استخراج، این دایرکتوری شامل config.sh، run.sh، env.sh، safe_sleep.sh، bin/ و externals/ است. bin/ شامل باینری‌های runner و bin/installdependencies.sh می‌باشد. externals/ نیز شامل Node runtime بسته‌بندی‌شده‌ای است که اکشن‌های JavaScript روی آن اجرا می‌شوند.

هنوز فایلی با نام svc.sh وجود ندارد. مستندات GitHub آن را اسکریپتی توصیف می‌کند که «پس از افزودن موفقیت‌آمیز runner ایجاد می‌شود»، زیرا این فایل از روی یک قالب نوشته می‌شود که نام مخزن و نام runner شما در نام سرویس آن گنجانده شده است. بنابراین اجرای sudo ./svc.sh install پیش از ./config.sh با خطای sudo: ./svc.sh: command not found مواجه می‌شود. ابتدا عملیات ثبت (Register) را انجام دهید و سپس سرویس را نصب کنید.

نصب پیش‌نیازهای runner

برنامه runner یک اپلیکیشن .NET است، بنابراین به چند کتابخانه مشترک نیاز دارد. از shell کاربر runner خارج شوید و آن‌ها را با استفاده از sudo نصب کنید، زیرا اسکریپت در دیتابیس بسته‌های سیستم می‌نویسد.

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

در Ubuntu 24.04، این کار بسته‌های libkrb5-3، zlib1g، liblttng-ust1t64، libssl3t64 و libicu74 را فراخوانی می‌کند. اسکریپت برای هر کتابخانه چندین نام نسخه را امتحان می‌کند و نسخه‌ای که در توزیع شما ارائه شده است را نگه می‌دارد؛ به همین دلیل است که یک اسکریپت مشابه روی نسخه‌های قدیمی‌تر Ubuntu و Debian کار می‌کند.

اگر از این مرحله صرف‌نظر کنید و یکی از آن کتابخانه‌ها موجود نباشد، ./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 پیش از شروع، کتابخانه‌های بسته‌بندی‌شده را با ldd و libicu را با ldconfig بررسی می‌کند؛ بنابراین یک لینک حل‌نشده باعث توقف اسکریپت می‌شود تا از بروز یک کرش گیج‌کننده در مراحل بعدی جلوگیری شود.

ثبت Runner در مخزن (Repository)

یک توکن از مخزن دریافت کنید. به بخش Settings، سپس Actions، سپس Runners و در نهایت New self-hosted runner بروید. صفحه یک توکن ثبت نمایش می‌دهد. این توکن یک ساعت پس از ایجاد منقضی می‌شود، بنابراین زمانی آن را ایجاد کنید که آمادهٔ جای‌گذاری (Paste) آن هستید.

ثبت را با کاربر 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

عملکرد این فلگ‌ها به شرح زیر است: --name تعیین می‌کند که runner چگونه در مخزن نمایش داده شود، بنابراین نامی انتخاب کنید که پس از 6 ماه همچنان برایتان قابل شناسایی باشد. --labels برچسب‌های سفارشی شما را اضافه می‌کند؛ runner به‌صورت پیش‌فرض دارای برچسب‌های 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 status

دستور svc.sh به دسترسی root نیاز دارد، زیرا یک unit را در مسیر /etc/systemd/system می‌نویسد و آن را فعال می‌کند. آرگومان بعد از install کاربری است که سرویس با آن اجرا می‌شود. مقدار gharunner را صریحاً وارد کنید. بدون آرگومان، اسکریپت به صورت پیش‌فرض از $SUDO_USER استفاده می‌کند که همان حساب کاربری مدیر شماست؛ در این صورت، تمام jobها با کاربری اجرا می‌شوند که دسترسی sudo دارد.

نام unit بر اساس مخزن و runner و به فرمت actions.runner.YOUR-USER-YOUR-REPO.vps-runner-1.service تعیین می‌شود. نیازی نیست آن را تایپ کنید:

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

یک runner سالم، عبارت √ Connected to GitHub و سپس خطی که به Listening for Jobs ختم می‌شود را لاگ می‌کند و در صفحه Runners مخزن، وضعیت آن به صورت Idle نمایش داده می‌شود. runnerای که وضعیت آن Offline است، یا در حال اجرا نیست و یا نمی‌تواند در پورت 443 به GitHub متصل شود.

ارسال یک job به runner

runs-on یک runner را بر اساس برچسب (label) انتخاب می‌کند. از self-hosted به همراه برچسب اختصاصی خود استفاده کنید تا job در runner ناخواسته‌ای اجرا نشود.

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

اگر job در وضعیت Waiting for a runner to pick up this job باقی می‌ماند، به این معنی است که برچسب‌ها مطابقت ندارند. تمام برچسب‌های موجود در runs-on باید روی runner تعریف شده باشند؛ بنابراین حتی یک کلمه اضافه باعث می‌شود job بدون نمایش هیچ خطایی در صف باقی بماند. لیست برچسب‌ها را با برچسب‌هایی که در تنظیمات repository کنار runner نمایش داده شده است، مقایسه کنید.

چرا نباید از self-hosted runner برای مخازن عمومی استفاده کرد

این بخشی است که بسیاری از کاربران از آن غافل می‌شوند. راهنمای GitHub صریح است: self-hosted runnerها «تقریباً هرگز نباید برای مخازن عمومی استفاده شوند» و «هیچ تضمینی برای اجرا در ماشین‌های مجازی موقت و پاک ندارند و می‌توانند توسط کدهای غیرقابل‌اعتماد در یک workflow به‌طور دائمی آلوده شوند».

مکانیسم این آسیب‌پذیری ساده است. یک pull request از یک fork، کپی مخصوص به خود از فایل workflow را به همراه می‌آورد. اگر مخزن عمومی شما workflowهای مربوط به pull request را روی runner شما اجرا کند، هر کسی که بتواند مخزن را fork کند، می‌تواند workflowای پیشنهاد دهد که دستورات او را روی VPS شما اجرا کند. آن‌ها نیازی به دسترسی write ندارند، زیرا چیزی که پیشنهاد می‌دهند، همان چیزی است که اجرا می‌شود.

تنظیمات تأییدیه (approval settings) این مشکل را بدون حل کردن، کمی تعدیل می‌کنند. سیاست پیش‌فرض برای یک مخزن عمومی از نگهدارنده (maintainer) می‌خواهد که workflow مربوط به fork یک مشارکت‌کننده جدید را تأیید کند. GitHub فردی را تنها تا زمانی که اولین commit یا pull request او در مخزن ادغام (merge) نشده باشد، به عنوان مشارکت‌کننده جدید می‌شناسد. پس از آن، pull requestهای بعدی او بدون هیچ هشداری اجرا می‌شوند و خود GitHub هشدار می‌دهد که یک اصلاح جزئی ادغام‌شده برای رسیدن به این مرحله کافی است. بنابراین، دروازه ورود، یک انسان است که diff را می‌خواند و یک payload که سه لایه پایین‌تر در یک اسکریپت build پنهان شده باشد، به‌راحتی از دید او دور می‌ماند.

یک pull request از نوع fork، به secrets شما دسترسی ندارد و GITHUB_TOKEN آن فقط خواندنی (read-only) است. این موضوع آسیب در داخل GitHub را محدود می‌کند، اما هیچ تأثیری بر سرور شما ندارد. مهاجم یک shell با دسترسی gharunner دارد، بنابراین می‌تواند تمام فایل‌هایی که آن کاربر اجازه خواندنشان را دارد بخواند، به هر چیزی که VPS در شبکه خصوصی خود به آن دسترسی دارد برسد و چیزی را در ~/.bashrc یا یک unit سیستم‌عامل systemd که در job بعدی اجرا می‌شود، باقی بگذارد.

ثبت‌نام با --ephemeral باعث می‌شود runner پس از انجام یک job، خود را از سیستم خارج (deregister) کند، بنابراین یک job نمی‌تواند فضای کاری job بعدی را بخواند. این تنها در صورتی کمک می‌کند که چیزی ماشین یا container را برای هر job بازسازی کند، زیرا یک backdoor که در دایرکتوری home کاربرِ runner نوشته شده باشد، پس از ثبت‌نام مجدد نیز باقی می‌ماند.

قوانینی که در ادامه می‌آیند کوتاه هستند. از self-hosted runnerها فقط برای مخازن خصوصی استفاده کنید. اگر مجبور هستید یکی از آن‌ها را به یک مخزن عمومی متصل کنید، pull requestهای مربوط به fork را روی آن اجرا نکنید، هیچ چیز دیگری روی آن سرور نگه ندارید و با آن ماشین به عنوان یک منبع یک‌بارمصرف (disposable) رفتار کنید.

جاب‌های Docker و گروهی که در واقع root است

جاب‌های کانتینری، کانتینرهای سرویس و هر مرحله از workflow که docker build را فراخوانی می‌کند، به یک Docker daemon روی میزبان runner نیاز دارند. Docker را به روش معمول نصب کنید که در Docker و Docker Compose روی یک VPS پوشش داده شده است، سپس کاربر runner را به گروه docker اضافه کنید.

پیش از انجام این کار، پیامدهای آن را درک کنید. عضویت در گروه docker معادل دسترسی root است، زیرا یک کانتینر می‌تواند / را bind mount کرده و به عنوان root در داخل آن اجرا شود. بنابراین، یک workflow که می‌تواند با سوکت Docker ارتباط برقرار کند، قادر است هر فایلی را روی VPS، از جمله /etc/shadow، بخواند و بنویسد. در یک مخزن خصوصی با مشارکت‌کنندگان مورد اعتماد، این ممکن است بهای قابل قبولی باشد. در هر جای دیگر، این کار هدف استفاده از کاربر بدون امتیاز (unprivileged) را از بین می‌برد. Docker بدون روت (Rootless Docker)، بیلد کانتینرها را در محدوده حقوق خودِ کاربر runner نگه می‌دارد، اما به قیمت استفاده از درایور ذخیره‌سازی کندتر و عدم امکان استفاده از کانتینرهای دارای امتیاز (privileged).

به‌روزرسانی‌ها و حذف تمیز runner

یک runner که به‌صورت self-hosted اجرا می‌شود، به‌طور پیش‌فرض خود را به‌روز می‌کند. این برنامه متوجه انتشار نسخه جدید می‌شود، فایل‌های خود را جایگزین کرده و سرویس را مجدداً راه‌اندازی می‌کند، بنابراین در حالت عادی نیازی به انجام کاری ندارید. برای غیرفعال کردن به‌روزرسانی خودکار، هنگام ثبت runner، پرچم --disableupdate را به ./config.sh ارسال کنید؛ برای runnerهایی که قبلاً ثبت کرده‌اید، این کار به معنای ثبت مجدد آن با استفاده از این پرچم است. این کار به شما اجازه نمی‌دهد که برای همیشه روی یک نسخه باقی بمانید. مستندات GitHub به‌صراحت بیان می‌کند که runner پیکربندی‌شده با --disableupdate همچنان باید ظرف 30 روز پس از انتشار نسخه جدید به‌صورت دستی به‌روزرسانی شود، در غیر این صورت GitHub ارسال jobها به آن را متوقف می‌کند.

به‌روزرسانی دستی، ثبت (registration) را حفظ می‌کند، زیرا .runner و .credentials در فایل tarball وجود ندارند. سرویس را متوقف کنید، tarball جدید را دانلود کرده و checksum آن را با gharunner بررسی کنید، سپس آن را با tar xzf روی همان دایرکتوری استخراج کرده و در نهایت سرویس را دوباره راه‌اندازی کنید:

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

برای حذف runner، ابتدا سرویس را uninstall کرده و سپس 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

حذف دایرکتوری بدون انجام عملیات deregister، باعث می‌شود runner در مخزن (repository) همچنان با وضعیت Offline نمایش داده شود. این وضعیت تا زمانی که مدیر سیستم روی گزینه Force remove this runner کلیک کند یا GitHub پس از 14 روز عدم اتصال، آن را به‌طور خودکار حذف کند، باقی می‌ماند.

حالت‌های شکست و پیام‌های خطای مربوطه

Must not run with sudo. اگر config.sh با کاربر root اجرا شود، این پیام را چاپ کرده و متوقف می‌شود. این بررسی عمدی است، زیرا فایل‌هایی که مالکیت آن‌ها متعلق به root در مسیر _work باشد، تمام وظایف بعدی که توسط کاربر سرویس اجرا می‌شوند را مختل می‌کنند. دستور ./config.sh را به عنوان کاربر gharunner اجرا کنید. متغیر RUNNER_ALLOW_RUNASROOT این بررسی را نادیده می‌گیرد، اما استفاده از آن فقط باعث می‌شود خرابی در مرحله‌ای دیرتر رخ دهد.

sudo: ./svc.sh: command not found. شما در دایرکتوری درستی هستید. فایل svc.sh هنوز وجود ندارد، زیرا config.sh فرآیند ثبت (registration) را کامل نکرده است. ابتدا runner را ثبت کنید و سپس سرویس را نصب نمایید.

Http response code: NotFound from 'POST https://api.github.com/actions/runner-registration'. معمولاً توکن وارد شده، یک توکن ثبت معتبر نیست. یا توکن منقضی شده است (چون اعتبار آن‌ها فقط 1 ساعت است)، یا یک personal access token به جای توکن ثبت از صفحه Runners کپی شده است. یک توکن جدید ایجاد کنید و دوباره آن را وارد کنید، همچنین بررسی کنید که --url آدرس کامل URL مخزن باشد.

Dependencies is missing for Dotnet Core 6.0. دستور sudo ./bin/installdependencies.sh را از دایرکتوری runner و با دسترسی root اجرا کنید، سپس دوباره برای ثبت اقدام نمایید.

وضعیت Offline بودن Runner پس از reboot. دستور systemctl is-enabled 'actions.runner.*' را اجرا کنید. اگر خروجی خالی است، یعنی ./svc.sh install هرگز اجرا نشده و runner فقط در طول نشست ترمینال شما وجود داشته است. اگر unit فعال است و runner همچنان Offline است، journalctl -u 'actions.runner.*' را مطالعه کرده و ارتباط خروجی HTTPS را بررسی کنید.

پر شدن دیسک. فایل‌های checkout، کش‌های build و ایمیج‌های Docker در مسیر _work و در دایرکتوری خانگی کاربر runner انباشته می‌شوند و هیچ فرآیندی به‌طور خودکار آن‌ها را پاکسازی نمی‌کند. مسیر du -sh /home/gharunner/actions-runner/_work را مانیتور کنید و یک برنامه پاکسازی زمان‌بندی‌شده اضافه کنید تا پیش از آنکه دیسک به صورت اضطراری پر شود، فضای کافی آزاد گردد.

FAQ

چرا sudo ./svc.sh install خطای command not found می‌دهد؟

زیرا svc.sh در فایل tarball مربوط به runner وجود ندارد. این فایل زمانی که ./config.sh ثبت‌نام را به پایان می‌رساند، در دایرکتوری runner ایجاد می‌شود و از نام مخزن و نام runner شما برای ساختن نام سرویس استفاده می‌کند. ابتدا ./config.sh را با کاربر runner اجرا کنید. پس از آن، sudo ./svc.sh install gharunner اسکریپت را پیدا کرده و یک unit با نام actions.runner.OWNER-REPO.RUNNER-NAME.service در مسیر /etc/systemd/system می‌نویسد.

آیا نیاز است پورت فایروال را برای یک self-hosted runner باز کنم؟

خیر. runner یک اتصال خروجی HTTPS به GitHub برقرار می‌کند و آن را تا زمان دریافت job باز نگه می‌دارد، بنابراین GitHub هرگز اتصالی به VPS شما برقرار نمی‌کند. دسترسی خروجی روی پورت 443 را مجاز کنید و قوانین ورودی (inbound) خود را بسته نگه دارید. اگر با وجود فعال بودن سرویس، وضعیت runner به صورت Offline نمایش داده می‌شود، به جای قوانین ورودی، فیلترینگ خروجی و DNS را بررسی کنید.

آیا می‌توانم از self-hosted runner روی یک مخزن عمومی استفاده کنم؟

می‌توانید، اما GitHub توصیه می‌کند این کار را انجام ندهید. یک pull request از یک fork، فایل workflow مخصوص به خود را دارد، بنابراین هر کسی که مخزن شما را fork کند می‌تواند دستوراتی را پیشنهاد دهد که روی ماشین شما اجرا شوند. اعلان تأیید پیش‌فرض فقط شامل مشارکت‌کنندگانی می‌شود که هرگز commit یا pull request آن‌ها در مخزن ادغام نشده است. اگر runner را به یک مخزن عمومی متصل می‌کنید، workflowهای مربوط به fork pull request را روی آن غیرفعال کنید، هیچ چیز دیگری روی آن سرور نگه ندارید و ماشین را طبق یک برنامه زمانی مشخص بازسازی (rebuild) کنید.

چرا ثبت‌نام با خطای Http response code: NotFound شکست می‌خورد؟

فراخوانی ثبت‌نام زمانی که اعتبارنامه (credential) اشتباه باشد نیز پاسخ NotFound می‌دهد، نه فقط زمانی که URL اشتباه باشد؛ این موضوع باعث گمراه‌کننده بودن پیام خطا می‌شود. توکن‌های ثبت‌نام یک ساعت پس از نمایش منقضی می‌شوند و personal access token برای این فراخوانی پذیرفته نمی‌شود. دوباره به بخش Settings، Actions، Runners و New self-hosted runner بروید، توکن جدید را کپی کنید و تأیید کنید که مقدار --url به مخزنی اشاره دارد که در آن دسترسی مدیریتی (admin) دارید.

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