{"id":106679,"date":"2025-06-10T21:49:04","date_gmt":"2025-06-10T21:49:04","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=106679"},"modified":"2025-05-12T22:22:44","modified_gmt":"2025-05-12T22:22:44","slug":"introduction-to-github-actions-part-3-self-hosted-runners","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/devops\/introduction-to-github-actions-part-3-self-hosted-runners\/","title":{"rendered":"Introduction to GitHub Actions Part 3: Self-hosted runners"},"content":{"rendered":"\n<p>The <a href=\"https:\/\/www.red-gate.com\/simple-talk\/devops\/introduction-to-github-actions-part-2-github-hosted-runners\/\">previous article<\/a> in this series discussed using GitHub-hosted runners. It covered how to call them in the yaml code, the benefits and drawbacks, how to install software tools, and to call a Docker container on the runner.<\/p>\n\n\n\n<p>Many organizations prefer to use self-hosted runners when GitHub-hosted do not meet their technical or security requirements. For example, a self-hosted runner can be added to Active Directory or Microsoft Entra ID. The downsides are increased costs and management time compared to GitHub-hosted runners.<\/p>\n\n\n\n<p>This article demonstrates how to use a Windows machine for a self-hosted runner, however, you could also use Linux or macOS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-planning\">Planning<\/h2>\n\n\n\n<p>Setting up a runner is simple. You just run provided code on the target VM or computer. Before running the code, consider these settings:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li> Will the runner be specific to this repo or used at the wider organization? <\/li>\n\n\n\n<li> Will the runner belong to a runner group? (More about this later) <\/li>\n\n\n\n<li> Name of the runner <\/li>\n\n\n\n<li> Additional tags <\/li>\n\n\n\n<li> Do you want the runner to run as a service? <\/li>\n\n\n\n<li> If running as a service, what account will be used? Note that this is the account that will run the YAML code. If you are using integrated security to connect to a database, this is the account that will connect depending on the type of connection string you use. <\/li>\n<\/ul>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-setting-up-a-new-runner\">Setting up a new runner<\/h2>\n\n\n\n<p>Setting up a runner is quite simple, and you can even do it on your laptop instead of a VM to try it!<\/p>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\">NOTE: Just like the previous articles, this one has a <a href=\"https:\/\/github.com\/KathiKellenberger\/GitHubActionsExample-Part3\">repository<\/a> with all the code shown that you can download or fork. Set up your new repository before following the steps to create the runner.<\/p>\n\n\n\n<p>Follow these steps to create a runner <em>that is specific to the repository <\/em>on a Windows machine:<\/p>\n\n\n<div class=\"block-core-list\">\n<ol class=\"wp-block-list\">\n<li> On your proposed runner, make sure that the outbound 443 port is open <\/li>\n\n\n\n<li> Navigate to your new GitHub repository <\/li>\n\n\n\n<li> Click Settings <\/li>\n\n\n\n<li> Expand Actions and click <strong>Runners<\/strong> <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"302\" height=\"360\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-1.png\" alt=\"\" class=\"wp-image-106680\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-1.png 302w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-1-252x300.png 252w\" sizes=\"auto, (max-width: 302px) 100vw, 302px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"5\" class=\"wp-block-list\">\n<li> You\u2019ll see this page. Click New self-hosted runner <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1219\" height=\"432\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m.png\" alt=\"A screenshot of a computer\n\nAI-generated content may be incorrect.\" class=\"wp-image-106681\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m.png 1219w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-300x106.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-1024x363.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-768x272.png 768w\" sizes=\"auto, (max-width: 1219px) 100vw, 1219px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"6\" class=\"wp-block-list\">\n<li> Select the operating system and architecture. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1240\" height=\"555\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-1.png\" alt=\"A screenshot of a computer\n\nAI-generated content may be incorrect.\" class=\"wp-image-106682\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-1.png 1240w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-1-300x134.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-1-1024x458.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-1-768x344.png 768w\" sizes=\"auto, (max-width: 1240px) 100vw, 1240px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"7\" class=\"wp-block-list\">\n<li> Scroll down and view the Download code. This code is specific for your runner. <\/li>\n\n\n\n<li> Open a <code>cmd<\/code> window <strong>as an administrator<\/strong> and navigate to the root. Switch it to PowerShell. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"865\" height=\"195\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-black-screen-with-white-text-ai-generated-conte.png\" alt=\"A black screen with white text\n\nAI-generated content may be incorrect.\" class=\"wp-image-106683\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-black-screen-with-white-text-ai-generated-conte.png 865w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-black-screen-with-white-text-ai-generated-conte-300x68.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-black-screen-with-white-text-ai-generated-conte-768x173.png 768w\" sizes=\"auto, (max-width: 865px) 100vw, 865px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"9\" class=\"wp-block-list\">\n<li> Important! The PowerShell execution policy must be set to <code>RemoteSigned<\/code>. Run this code if it\u2019s more restricted: <\/li>\n<\/ol>\n<\/div>\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:ps\" highlight=\"true\" decode=\"true\">Set-ExecutionPolicy RemoteSigned -scope CurrentUser<\/pre><\/div>\n\n\n<div class=\"block-core-list\">\n<ol start=\"10\" class=\"wp-block-list\">\n<li> Copy and run the script from the <strong>Download<\/strong> section of the new runner page one line at a time. The code will be specific to your runner. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1135\" height=\"355\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co.png\" alt=\"A computer screen with white text\n\nAI-generated content may be incorrect.\" class=\"wp-image-106684\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co.png 1135w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-300x94.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-1024x320.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-768x240.png 768w\" sizes=\"auto, (max-width: 1135px) 100vw, 1135px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"11\" class=\"wp-block-list\">\n<li> The next step is to run the <strong>Configure<\/strong> commands. Again, the command is specific to your situation. <\/li>\n\n\n\n<li> Accept the defaults for the settings until you get to the question about setting up a service. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"830\" height=\"317\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-6.png\" alt=\"\" class=\"wp-image-106685\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-6.png 830w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-6-300x115.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-6-768x293.png 768w\" sizes=\"auto, (max-width: 830px) 100vw, 830px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"13\" class=\"wp-block-list\">\n<li> Type <strong>Y<\/strong> and press enter when prompted to set up a service. For now, just use the network service account. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"733\" height=\"175\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-7.png\" alt=\"\" class=\"wp-image-106686\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-7.png 733w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-7-300x72.png 300w\" sizes=\"auto, (max-width: 733px) 100vw, 733px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"14\" class=\"wp-block-list\">\n<li> Open the Services utility and scroll down to GitHub Actions to see your runner service. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"51\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-8.png\" alt=\"\" class=\"wp-image-106687\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-8.png 624w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-8-300x25.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"15\" class=\"wp-block-list\">\n<li> Return to the GitHub Actions Runners configuration page to see the new runner. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"187\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-9.png\" alt=\"\" class=\"wp-image-106688\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-9.png 624w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-9-300x90.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-try-out-the-runner\">Try out the runner<\/h2>\n\n\n\n<p>If you don\u2019t have it already, add the <code>HelloWorld.yaml<\/code> file to your repository. You can copy this file from <a href=\"https:\/\/github.com\/KathiKellenberger\/GitHubActionsExample-Part3\">my repository<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">name: Hello, World\n\n# Controls when the workflow will run, in this case manually\non: workflow_dispatch\n\njobs:\n  PrintHelloWorld:\n    name: Print Hello, World!\n    runs-on: self-hosted\n    steps:\n    - run: echo \"Hello, World!\"\n<\/pre><\/div>\n\n\n\n<p>The only difference between this and the code from the file in <a href=\"https:\/\/www.red-gate.com\/simple-talk\/featured\/introduction-to-github-actions-part-1-getting-started\/\">part 1 of the series<\/a>, is the \u201cruns-on\u201d line. In this case, it\u2019s self-hosted instead of ubuntu-latest.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"507\" height=\"232\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-10.png\" alt=\"\" class=\"wp-image-106689\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-10.png 507w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-10-300x137.png 300w\" sizes=\"auto, (max-width: 507px) 100vw, 507px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>Since this workflow Is set up to only run manually, navigate to <strong>Actions<\/strong> and select <strong>Hello, World<\/strong>. Kick off the run.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1110\" height=\"283\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-11.png\" alt=\"\" class=\"wp-image-106690\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-11.png 1110w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-11-300x76.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-11-1024x261.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-11-768x196.png 768w\" sizes=\"auto, (max-width: 1110px) 100vw, 1110px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>After a successful run, you should see results resembling this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"262\" height=\"264\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-12.png\" alt=\"\" class=\"wp-image-106691\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-12.png 262w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-12-150x150.png 150w\" sizes=\"auto, (max-width: 262px) 100vw, 262px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-removing-a-runner\">Removing a runner<\/h2>\n\n\n\n<p>There may be situations where you need to clean up a runner. Follow these steps to remove the runner you just created.<\/p>\n\n\n<div class=\"block-core-list\">\n<ol class=\"wp-block-list\">\n<li> Navigate to the Runners page and click the ellipsis to bring up Remove Runner. <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"195\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-13.png\" alt=\"\" class=\"wp-image-106692\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-13.png 624w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-13-300x94.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"2\" class=\"wp-block-list\">\n<li> Click <strong>Remove runner<\/strong>. You may be asked to provide some form of authentication and verify that you really want to do this. <\/li>\n\n\n\n<li> Proceed carefully here. There are two methods depending on whether the runner is still available. In this case, it is, so scroll down to Remove and clean up machine (recommended). <\/li>\n<\/ol>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"871\" height=\"646\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-14.png\" alt=\"\" class=\"wp-image-106693\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-14.png 871w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-14-300x223.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-14-768x570.png 768w\" sizes=\"auto, (max-width: 871px) 100vw, 871px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"4\" class=\"wp-block-list\">\n<li> If you are running on Windows, copy the code to a text editor and change to <\/li>\n<\/ol>\n<\/div>\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:ps\" highlight=\"true\" decode=\"true\">.\/config.cmd remove --token &lt;your token&gt;<\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1026\" height=\"316\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-1.png\" alt=\"A computer screen with white text\n\nAI-generated content may be incorrect.\" class=\"wp-image-106694\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-1.png 1026w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-1-300x92.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-1-1024x315.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-computer-screen-with-white-text-ai-generated-co-1-768x237.png 768w\" sizes=\"auto, (max-width: 1026px) 100vw, 1026px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n<div class=\"block-core-list\">\n<ol start=\"5\" class=\"wp-block-list\">\n<li> Delete the actions-runner directory. <\/li>\n<\/ol>\n<\/div>\n\n\n<p>This code removes the runner service as well as the runner configuration on GitHub Actions. If the runner is no longer available, you should use the Force remove method which removes the record from GitHub Actions only.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-organizing-runners-into-groups\">Organizing runners into groups<\/h2>\n\n\n\n<p>During the installation in the \u201cSetting up a new runner\u201d section, you were prompted for the runner\u2019s group. The group setting allows you to create a \u201cpool\u201d of runners, preferably with identical setups. Say for example, you have a workflow that might be called while a previous run on the same or another workflow is still active. In this case, if there were only one runner, the second call would have to wait until the first call completed. By using a group, another idle runner could take care of the second call and run in parallel with the first call.<\/p>\n\n\n\n<p>At the repository level, you can use the default group. Here&#8217;s an example with two runners:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"219\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-16.png\" alt=\"\" class=\"wp-image-106695\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-16.png 624w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-16-300x105.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>When kicking off the <strong>Hello, World<\/strong> workflow twice, it runs once on each runner.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1315\" height=\"223\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-17.png\" alt=\"\" class=\"wp-image-106696\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-17.png 1315w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-17-300x51.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-17-1024x174.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-17-768x130.png 768w\" sizes=\"auto, (max-width: 1315px) 100vw, 1315px\" \/><\/figure>\n\n\n\n<p>\n   \n  \n<\/p>\n\n\n\n<p>When drilling into the runs, each runner is specified.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"389\" height=\"231\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-18.png\" alt=\"\" class=\"wp-image-106697\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-18.png 389w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-18-300x178.png 300w\" sizes=\"auto, (max-width: 389px) 100vw, 389px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"502\" height=\"198\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-19.png\" alt=\"\" class=\"wp-image-106698\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-19.png 502w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-19-300x118.png 300w\" sizes=\"auto, (max-width: 502px) 100vw, 502px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>At the organizational level, you can add more groups, however, you cannot use groups unless you use a paid account. You may have a group of runners on Windows and another group on Linux, for example. Navigate to your organization\u2019s settings where you should see an option for Runner groups under Actions.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"448\" height=\"241\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-20.png\" alt=\"\" class=\"wp-image-106699\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-20.png 448w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-20-300x161.png 300w\" sizes=\"auto, (max-width: 448px) 100vw, 448px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>You can add a new group, then add runners at the organizational level to the groups. In this case, I removed <code>ga_vm1<\/code> from the repository runners and added it to the organization\u2019s runners in the test1 group. The steps are the same except that you copy the installation code from the organization page instead of the repository page (<strong>Organization \ud83e\udc6a Settings \ud83e\udc6a Actions \ud83e\udc6a Runners<\/strong>).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1150\" height=\"528\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-2.png\" alt=\"A screenshot of a computer\n\nAI-generated content may be incorrect.\" class=\"wp-image-106700\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-2.png 1150w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-2-300x138.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-2-1024x470.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-2-768x353.png 768w\" sizes=\"auto, (max-width: 1150px) 100vw, 1150px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>After clicking into <code>test1<\/code>, here\u2019s the runner:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1309\" height=\"804\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-22.png\" alt=\"\" class=\"wp-image-106701\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-22.png 1309w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-22-300x184.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-22-1024x629.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-22-768x472.png 768w\" sizes=\"auto, (max-width: 1309px) 100vw, 1309px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>To specify the group <code>test1<\/code> in the workflow, change the code to this, however, I was not able to complete a successful run since I\u2019m using a free account.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">name: Hello, World - Use a group\n\n# Controls when the workflow will run, in this case manually\non: workflow_dispatch\n\njobs:\n  PrintHelloWorld:\n    name: Print Hello, World!\n    runs-on:\n      group: test1\n    steps:\n    - run: echo \"Hello, World!\"<\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"651\" height=\"343\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-23.png\" alt=\"\" class=\"wp-image-106702\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-23.png 651w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-23-300x158.png 300w\" sizes=\"auto, (max-width: 651px) 100vw, 651px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-using-tags-to-control-runners\">Using tags to control runners<\/h2>\n\n\n\n<p>You have one other option for controlling runners. I\u2019ve found it especially helpful when using a free account, but tags will come in handy for other situations as well. These can be used at the repository level as well as the organization level.<\/p>\n\n\n\n<p>When creating your runner, you can specify one or more tags, but you can also add tags after-the-fact by clicking on the runner name in the settings.<\/p>\n\n\n\n<p>In this example, the runner has a new tag <code>\u201cforHello\u201d<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1108\" height=\"496\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-3.png\" alt=\"A screenshot of a computer\n\nAI-generated content may be incorrect.\" class=\"wp-image-106703\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-3.png 1108w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-3-300x134.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-3-1024x458.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-3-768x344.png 768w\" sizes=\"auto, (max-width: 1108px) 100vw, 1108px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>You must specify all the tags and in the correct order to use the new tag. The new code using a tag to specify the runner looks like this:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">name: Hello, World - Use a tag\n\n# Controls when the workflow will run, in this case manually\non: workflow_dispatch\n\njobs:\n  PrintHelloWorld:\n    name: Print Hello, World!\n    runs-on: [self-hosted, Windows, X64, forHello]\n    steps:\n    - run: echo \"Hello, World!\"<\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"744\" height=\"324\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-25.png\" alt=\"\" class=\"wp-image-106704\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-25.png 744w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106679-25-300x131.png 300w\" sizes=\"auto, (max-width: 744px) 100vw, 744px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-adding-multiple-runners-to-one-vm\">Adding multiple runners to one VM<\/h2>\n\n\n\n<p>You can also set up the runner service more than once on a VM. This might come in handy when a service account must be used for certain jobs while other jobs need another service account.<\/p>\n\n\n\n<p>Create a separate folder and follow the steps to create a runner, except provide a different name. Here, I\u2019ve created a second runner service on the VM and added a tag:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1159\" height=\"415\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-4.png\" alt=\"A screenshot of a computer\n\nAI-generated content may be incorrect.\" class=\"wp-image-106705\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-4.png 1159w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-4-300x107.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-4-1024x367.png 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-computer-ai-generated-content-m-4-768x275.png 768w\" sizes=\"auto, (max-width: 1159px) 100vw, 1159px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>You can\u2019t provide the name of the runner in the yaml code, but you can get around that by using a tag instead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\">Conclusion<\/h2>\n\n\n\n<p>Many organizations require self-hosted runners for security or technical reasons. Runners are easy to set up and manage, but your organization is responsible for the VM costs and management. They can be organized by groups (paid accounts) or by tags to control which runner is used for a particular workflow run.<\/p>\n\n\n\n<p>The next article will cover how to use variables and secrets in your workflows.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The previous article in this series discussed using GitHub-hosted runners. It covered how to call them in the yaml code, the benefits and drawbacks, how to install software tools, and to call a Docker container on the runner. Many organizations prefer to use self-hosted runners when GitHub-hosted do not meet their technical or security requirements&#8230;.&hellip;<\/p>\n","protected":false},"author":110218,"featured_media":106707,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143512],"tags":[5775,159280],"coauthors":[11292],"class_list":["post-106679","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-github","tag-kathikellenbergergithubseries"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106679","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/110218"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=106679"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106679\/revisions"}],"predecessor-version":[{"id":106711,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106679\/revisions\/106711"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/106707"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=106679"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=106679"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=106679"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=106679"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}