---
title: "Config policies for self-hosted runner"
description: "Learn how to write a policy to restrict which projects can run jobs on a self-hosted runner."
platform: "Cloud, Server"
doc_version: "Server"
last_updated: "2026-10-14"
---

> For current CircleCI product defaults, deprecated patterns, and Cloud/Server differences, see [AGENTS.md](https://circleci.com/docs/AGENTS.md).
>
> For the complete documentation index and site structure, see [llms.txt](https://circleci.com/docs/llms.txt).

# Config policies for self-hosted runner

Follow this how-to guide to learn how to create a config policy to restrict which projects can run jobs on a self-hosted runner resource class. For more information about config policies, see the [Config Policies Overview](https://circleci.com/docs/guides/server/config-policies/config-policy-management-overview/).

When using the `circleci policy` commands, use the `policy-base-url` flag to provide your CircleCI Server domain. For example:

```shell
circleci policy push ./config-policies --owner-id <your-organization-ID> --policy-base-url <your-circleci-server-domain>
```

## Prerequisites

*   Install/update the CircleCI CLI, and ensure you have authenticated with a token before attempting to use the CLI with config policies. See the [Installing the Local CLI](https://circleci.com/docs/guides/server/toolkit/circleci-cli/) page for more information.
    
*   Set up a self-hosted runner. See the [Getting Started](https://circleci.com/docs/runner/runner-overview/#getting-started) section of the Self-hosted runners overview.
    
*   Ensure you have **enabled** config policy evaluation for your organization so that project configurations **will** be evaluated against your organization’s policies when pipelines are triggered:
    
    ```shell
    circleci policy settings --enabled=true --owner-id <your-organization-ID>
    ```
    
    Example output:
    
    ```shell
    {
      "enabled": true
    }
    ```
    
    To find your organization ID and organization slug, select **Org** in the CircleCI web app sidebar to open your organization settings page.
    
    The organization ID is available to copy from the org settings overview page.
    
    > **Image:** screenshot showing where to find your organization ID
    
    Figure 1. Organization ID available in organization settings
    

## 1\. Create your policy

1.  If you have not already done so, create an empty directory to store your policies. For example:
    
    ```shell
    mkdir ./config-policies
    ```
    
2.  Create a new file in this directory for your new policy. Name the file `runner.rego`.
    
3.  Copy the following snippet into the `runner.rego` file you just made:
    
    ```go
    package org
    import data.circleci.config
    
    policy_name["runner_policies"]
    
    enable_hard["resource_class_check"]
    
    resource_class_check = config.resource_class_by_project({ "namespace/resource_class": {"project_UUIDs"}})
    ```
    
    In the following steps you will replace `namespace/resource_class` and `project_UUIDs` with one of your self-hosted runner resource classes, and one of your existing projects. The `runner.rego` policy, once uploaded, will then restrict your specified self-hosted runner to only run jobs from your specified project.
    

## 2\. Update policy with your details

1.  Replace `namespace/resource_class` with one of your runner resource classes:
    
    1.  In the CircleCI web app, go to your self-hosted runner’s inventory page by selecting **Runners** in the sidebar. If you do not see this option, check that you have accepted the CircleCI Runner Terms and created a namespace and resource class, as outlined in the runner installation guides. Here you will see all your available self-hosted runner resource classes.
        
    2.  Replace `namespace/resource_class` in the `runner.rego` file with the name of the resource class that you would like to restrict.
        
    
2.  Replace `project_UUIDs` with a project ID:
    
    1.  In the CircleCI web app, navigate to your projects dashboard by selecting **Projects** in the sidebar. Find the project you want to allow to build on your self-hosted runner, and then click the ellipsis (`…​`) next to that project and select **Project Settings**.
        
    2.  Copy the Project ID from the overview page and replace `project_UUIDs` with this project ID.
        
    

## 3\. Push up your policy bundle

You can now push your new policy to your organization for it to take effect. You have two options:

*   Push the policy manually using the CLI from your local environment.
    
*   Push your changes to your config policy repository if you are [Managing Policies via Your VCS](https://circleci.com/docs/guides/server/config-policies/create-and-manage-config-policies/#manage-policies-with-your-vcs).
    

<Tabs>
<Tab title="Manual">

Create and upload the policy bundle using CircleCI CLI:

```shell
circleci policy push ./config-policies --owner-id <your-organization-ID>
```

If the upload was successful, you will see something like the following:

```shell
{
  “Created”: [“runner_policies”]
}
```

</Tab>
<Tab title="Push to VCS">

Push your changes to `main` and head to the CircleCI web app to see your policy pipeline. This assumes you set up your config policies repository with the sample configuration from the [Config Policies](https://circleci.com/docs/guides/server/config-policies/create-and-manage-config-policies/#manage-policies-with-your-vcs) guide, .

Push to a development branch during policy development to get a diff of your policy bundle when you push your changes.

</Tab>
</Tabs>

If you would like to write tests for your policy, check out the [Test Config Policies](https://circleci.com/docs/guides/server/config-policies/test-config-policies/) guide.

## A more complex example

Once you have this runner restriction policy up and running, you can quickly add more runner resource class/project pairings, and allow multiple projects per runner. To do this you will expand the `resource_class_check` rule.

The following snippet shows two separate runner resource classes (`my-namespace/runner-test1` and `my-namespace/runner-test2`) with allowed projects, the first has two projects in its allowed list.

```go

package org
import data.circleci.config

policy_name["runner_policies"]

enable_hard["resource_class_check"]

resource_class_check = config.resource_class_by_project({
  "my-namespace/runner-test1": {
    "a20ae1c6-d723-4c03-9bb6-01d5b3594e02",
    "2accadd0-c832-489e-b837-4de03def0d35"
  },
  "my-namespace/runner-test2": {
    "637f9136-694e-4105-bb43-1028ffb9043e"
  }
})
```

## Next steps

*   [Create and Manage Config Policies](https://circleci.com/docs/guides/server/config-policies/create-and-manage-config-policies/)
    
*   [Test Config Policies](https://circleci.com/docs/guides/server/config-policies/test-config-policies/)
    
*   [Config Policy Reference](https://circleci.com/docs/reference/config-policy-reference/)