راهنمای نصب GitHub Actions Runner روی VPS
نحوه راهاندازی GitHub Actions runner روی Ubuntu 24.04 با استفاده از systemd. این راهنما شامل مراحل ثبت، بررسی checksum و مدیریت ریسک امنیتی در pull request است.
عملکرد یک GitHub Actions runner خود-میزبان (self-hosted)
یک GitHub Actions runner خود-میزبان، برنامهای است که آن را روی VPS شخصی خود نصب میکنید تا از GitHub درخواست کار (job) کرده و آنها را روی سختافزار شما اجرا کند. شما آن را برای یک مخزن (repository) ثبت میکنید، به عنوان یک سرویس systemd نصب میکنید و پس از هر بار راهاندازی مجدد (reboot)، بهطور خودکار اجرا میشود. GitHub کار را زمانبندی میکند و سرور شما آن را انجام میدهد.
استفاده از CI (یکپارچهسازی مداوم) روی سیستمی که مالک آن هستید، به دو دلیل ارزشمند است. دقایق ساخت (build minutes) دیگر محدودیت ندارند و یک کار میتواند به منابعی دسترسی پیدا کند که فقط در اختیار ماشین شماست، مانند کش ساخت (build cache) آماده یا یک شبکه خصوصی. هزینه این کار، امنیت است. این runner هر دستوری که در فایل workflow باشد را با کاربری که برای آن تعریف کردهاید اجرا میکند؛ بنابراین فایل workflow ذاتاً یک اجرای کد از راه دور (remote code execution) است. در یک مخزن خصوصی این موضوع مشکلی ندارد، زیرا فقط افراد مورد اعتماد شما میتوانند فایلی به آن اضافه کنند. در یک مخزن عمومی، این یک ریسک واقعی است و بخش مربوط به pull requestهای fork، این مکانیزم را توضیح میدهد.
تمام موارد زیر مربوط به Ubuntu 24.04 با نسخه runner 2.336.0 است که نسخه فعلی در ژوئیه 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.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"اگر از معماری سیستم خود مطمئن نیستید، ابتدا uname -m را اجرا کنید. x86_64 از فایل linux-x64 در بالا استفاده میکند. aarch64 از actions-runner-linux-arm64-${RUNNER_VERSION}.tar.gz استفاده میکند.
اکنون فایلی را که دانلود کردهاید، تایید کنید. مقدار SHA256 (الگوریتم هش امن، 256 بیتی) زیر برای فایل tarball نسخه 2.336.0 و معماری x64 است. GitHub مقدار مربوط به نسخه فعلی را در صفحه release و در صفحه New self-hosted runner نمایش میدهد. این مقدار با هر نسخه تغییر میکند، بنابراین هنگام نصب نسخههای دیگر، آن را از همانجا کپی کنید.
echo "04cf0be1aff4c3ec3554466c39124ca250e3effd8873bb7e8d68535aa9505d5d actions-runner-linux-x64-2.336.0.tar.gz" | sha256sum -cیک دانلود موفق، یک خط خروجی میدهد:
actions-runner-linux-x64-2.336.0.tar.gz: OKیک فایل ناقص یا تغییریافته، خطا و هشدار زیر را چاپ میکند:
actions-runner-linux-x64-2.336.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.336.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 را روی کتابخانههای بستهبندیشده اجرا میکند، بنابراین یک لینک حلنشده باعث توقف اسکریپت میشود تا از بروز یک کرش گیجکننده در مراحل بعدی جلوگیری شود.
ثبت Runner در مخزن (Repository) خود
یک توکن از مخزن دریافت کنید. به بخش Settings، سپس Actions، سپس Runners و در نهایت New self-hosted runner بروید. این صفحه یک توکن ثبت را نمایش میدهد که با A شروع میشود. این توکن یک ساعت پس از ایجاد منقضی میشود، بنابراین زمانی آن را تولید کنید که آمادهٔ جایگذاری (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عملکرد این پرچمها (Flags) به این صورت است: --name نامی است که runner با آن در مخزن نمایش داده میشود، بنابراین نامی را انتخاب کنید که پس از 6 ماه همچنان برایتان قابل تشخیص باشد. --labels برچسبهای (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 شناسایی میکنند، بنابراین هر کسی که به آنها دسترسی داشته باشد میتواند خود را به جای آن جا بزند. به همین دلیل است که دسترسی دایرکتوری روی 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 یک مشارکتکننده جدید را تأیید کند. پس از اینکه یک بار آن شخص را تأیید کردید، pull requestهای بعدی او بدون درخواست جدید اجرا میشوند. بنابراین، این سد امنیتی به یک انسان وابسته است که باید هر بار تفاوتها (diff) را بررسی کند، و یک payload که در سه لایه پایینتر در یک اسکریپت build پنهان شده باشد، بهراحتی از دید پنهان میماند.
یک pull request از نوع fork، به secrets شما دسترسی ندارد و GITHUB_TOKEN آن فقطخواندنی (read-only) است. این موضوع آسیب در داخل GitHub را محدود میکند، اما هیچ تأثیری بر سرور شما ندارد. مهاجم یک shell با دسترسی gharunner دارد، بنابراین میتواند تمام فایلهایی که آن کاربر قادر به خواندنشان است را بخواند، به هر چیزی که VPS در شبکه خصوصی خود به آن دسترسی دارد برسد و چیزی در ~/.bashrc یا یک unit سیستمعامل systemd باقی بگذارد که در job بعدی اجرا شود.
ثبتنام با --ephemeral باعث میشود runner یک job را بپذیرد و سپس از ثبت خارج شود، بنابراین یک job نمیتواند فضای کاری job بعدی را بخواند. این تنها در صورتی کمک میکند که چیزی ماشین یا container را برای هر job بازسازی کند، زیرا یک backdoor که در دایرکتوری home کاربرِ runner نوشته شده باشد، پس از ثبتنام مجدد نیز باقی میماند.
قوانینی که در ادامه میآیند کوتاه هستند. از self-hosted runnerها فقط برای مخازن خصوصی استفاده کنید. اگر مجبور هستید یکی از آنها را به یک مخزن عمومی متصل کنید، 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 ارتباط برقرار کند، قادر است هر فایلی را روی VPS، از جمله /etc/shadow، بخواند و بنویسد. در یک مخزن خصوصی با مشارکتکنندگان مورد اعتماد، این ممکن است بهای قابل قبولی باشد. در هر جای دیگر، این کار هدف استفاده از کاربر بدون امتیاز (unprivileged) را از بین میبرد. Docker بدون روت (Rootless Docker)، بیلد کانتینرها را در محدوده حقوق خودِ کاربر runner نگه میدارد، اما به قیمت استفاده از درایور ذخیرهسازی کندتر و عدم امکان استفاده از کانتینرهای دارای امتیاز (privileged).
بهروزرسانیها و حذف تمیز runner
یک runner که بهصورت self-hosted اجرا میشود، بهطور پیشفرض خود را بهروز میکند. این برنامه متوجه انتشار نسخه جدید میشود، فایلهای خود را جایگزین کرده و سرویس را مجدداً راهاندازی میکند، بنابراین در حالت عادی نیازی به انجام کاری ندارید. ./config.sh --disableupdate قابلیت بهروزرسانی خودکار را در مواقعی که به یک نسخه ثابت نیاز دارید، غیرفعال میکند. پس از آن، بهروزرسانی بر عهده شماست: مستندات GitHub بهصراحت بیان میکند که runner پیکربندیشده با --disableupdate باید بهصورت دستی بهروزرسانی شود.
یک بهروزرسانی دستی، ثبت (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 در مخزن بهصورت Offline باقی بماند، زیرا GitHub تنها زمانی از حذف آن مطلع میشود که runner این موضوع را اعلام کند یا یک مدیر سیستم بهصورت دستی ورودی آن را حذف نماید.
حالتهای شکست و پیامهایی که مشاهده خواهید کرد
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 عملیات ثبتنام را تکمیل نکرده است. ابتدا runner را ثبت کنید و سپس سرویس را نصب نمایید.
Http response code: NotFound from 'POST https://api.github.com/actions/runner-registration'. توکن ارائه شده یک توکن ثبتنام معتبر نیست. یا منقضی شده است (چون اعتبار آنها یک ساعت است)، یا یک personal access token به جای توکن ثبتنام از صفحه Runners کپی شده است. یک توکن جدید ایجاد کنید و دوباره آن را وارد نمایید.
Dependencies is missing for Dotnet Core 6.0. دستور sudo ./bin/installdependencies.sh را از دایرکتوری runner و با دسترسی root اجرا کنید، سپس دوباره برای ثبتنام اقدام نمایید.
Runner پس از reboot آفلاین است. دستور systemctl is-enabled 'actions.runner.*' را اجرا کنید. اگر خروجی خالی است، یعنی ./svc.sh install هرگز اجرا نشده و runner فقط در طول نشست ترمینال شما وجود داشته است. اگر unit فعال است و runner همچنان Offline باقی مانده، journalctl -u 'actions.runner.*' را مطالعه کرده و اتصالات خروجی HTTPS را بررسی کنید.
دیسک پر میشود. فایلهای checkout، کشهای build و ایمیجهای Docker در مسیر _work و در دایرکتوری home کاربر 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 کند، میتواند دستوراتی را پیشنهاد دهد که روی ماشین شما اجرا شوند. اعلان تأیید (approval prompt) فقط برای اولین اجرای یک مشارکتکننده نمایش داده میشود. اگر runner را به یک مخزن عمومی متصل کردید، اجرای workflow برای pull requestهای fork شده را غیرفعال کنید، هیچ چیز دیگری روی آن سرور نگه ندارید و ماشین را طبق یک برنامه زمانی مشخص بازسازی (rebuild) کنید.
چرا ثبتنام با خطای Http response code: NotFound شکست میخورد؟
فراخوانی ثبتنام زمانی که اعتبارنامه (credential) اشتباه باشد نیز پاسخ NotFound برمیگرداند، نه فقط زمانی که URL اشتباه باشد؛ این موضوع باعث گمراهکننده بودن پیام خطا میشود. توکنهای ثبتنام یک ساعت پس از نمایش منقضی میشوند و personal access token برای این فراخوانی پذیرفته نمیشود. دوباره به بخش Settings، سپس Actions، Runners و New self-hosted runner بروید، توکن جدید را کپی کنید و مطمئن شوید که مقدار --url به مخزنی اشاره دارد که در آن دسترسی مدیریتی (admin) دارید.