---
title: Set Up a Standalone Private Action Runner
description: >-
  Install, connect, manage, and update a standalone private action runner that
  you deploy and manage yourself with Docker or Helm.
breadcrumbs: Docs > Actions > Private Actions > Set Up a Standalone Private Action Runner
---

> For the complete documentation index, see [llms.txt](https://docs.datadoghq.com/llms.txt).

# Set Up a Standalone Private Action Runner

{% callout %}
# Important note for users on the following Datadog sites: app.ddog-gov.com, us2.ddog-gov.com

{% alert level="danger" %}
This product is not supported for your selected [Datadog site](https://docs.datadoghq.com/getting_started/site.md). ({% placeholder "user-datadog-site-name" /%}).
{% /alert %}

{% /callout %}

## Overview{% #overview %}

The standalone private action runner is a dedicated container you can install and manage independently of the Datadog Agent with Docker or Helm. It is supported and in maintenance mode: it continues to receive security and stability updates, and no new features are planned. For new deployments, and to use Execution Policies, run the runner in the Datadog Agent instead. See [Set up a private action runner in the Datadog Agent](https://docs.datadoghq.com/actions/private_actions/set_up_agent_based.md).

Setting up the runner takes three steps:

1. **Install** the runner with Docker, Docker Compose, or Kubernetes.
1. **Connect** the runner to Datadog with a connection.
1. **Update** the runner as new versions are released.

A standalone runner is always **owned**: creating one, through either method below, always registers it under the creating user, authorized with [Connections](https://docs.datadoghq.com/actions/connections.md).

## Prerequisites{% #prerequisites %}

- Docker, or a Kubernetes cluster.
- Network access to Datadog at `https://` and `https://config.`.

## Install the runner{% #install-the-runner %}

1. In Datadog, navigate to [**Action Catalog > Private Action Runners**](https://app.datadoghq.com/actions/private-action-runners), and click **New Private Action Runner**.
1. Enter a name for your runner and select the allowed actions.
1. Create a directory on your host where the runner can store its configuration, such as `./config`.
1. Deploy your runner by following the steps for your container platform:

{% tab title="Docker" %}

1. Click **Docker**.
1. Run the provided `docker run` command on your host, replacing `./config` with the path to the directory you created for the runner configuration.

**Note**: You can safely ignore the error `DATADOG TRACER DIAGNOSTIC - Agent Error: connect ECONNREFUSED`.
{% /tab %}

{% tab title="Docker Compose" %}

1. Click **Docker Compose**.
1. Create a `docker-compose.yaml` file and add the provided YAML, or add the `runner` stanza to an existing Docker Compose file.
1. Replace `./config` with the path to the directory you created for the runner configuration.
1. Run `docker compose up -d`.

**Note**: You can safely ignore the error `DATADOG TRACER DIAGNOSTIC - Agent Error: connect ECONNREFUSED`.
{% /tab %}

{% tab title="Kubernetes (Helm)" %}

1. Click **Kubernetes**.
1. Confirm that `kubectl` and `helm` are installed, and that you have sufficient permissions to create Kubernetes resources in your cluster.
1. Follow the instructions provided in the app to enroll the runner, generate the config, add the Private Action Runner Helm repository, and install the chart.
1. Run `kubectl get pods -w` and verify the private action runner pod's status becomes **Ready**.

{% /tab %}

## Alternative: programmatic installation{% #alternative-programmatic-installation %}

As an alternative to the UI-based setup above, you can enroll and configure a standalone runner programmatically using your API key and application key. This approach is suited to automated deployments, CI/CD pipelines, and infrastructure-as-code workflows. Like the UI-based setup, this always creates an owned runner. Despite the `--with-api-key` flag's name, this path still requires an application key: the runner uses both credentials together to register itself and assign the application key's owner as the runner's Editor.

To set up the runner programmatically:

1. Provide your Datadog API and application keys through the `DD_API_KEY` and `DD_APP_KEY` environment variables.
1. Pass the `--with-api-key` flag to the runner container.

{% tab title="Docker" %}

```bash
export DD_API_KEY="<YOUR_API_KEY>"
export DD_APP_KEY="<YOUR_APP_KEY>"

docker run -d \
  -e DD_BASE_URL=https://<span class="js-region-param region-param" data-region-param="dd_site"></span> \
  -e DD_PRIVATE_RUNNER_CONFIG_DIR=/etc/dd-action-runner/config \
  -e DD_API_KEY="$DD_API_KEY" \
  -e DD_APP_KEY="$DD_APP_KEY" \
  -e RUNNER_NAME=<YOUR_RUNNER_NAME> \
  -v ./config:/etc/dd-action-runner/config \
  gcr.io/datadoghq/private-action-runner:v1.21.0 \
  --with-api-key
```

{% /tab %}

{% tab title="Docker Compose" %}

```yaml
services:
  private-runner:
    image: gcr.io/datadoghq/private-action-runner:v1.21.0
    command: ["--with-api-key"]
    environment:
      DD_API_KEY: ${DD_API_KEY}
      DD_APP_KEY: ${DD_APP_KEY}
      DD_BASE_URL: https://<span class="js-region-param region-param" data-region-param="dd_site"></span>
      DD_PRIVATE_RUNNER_CONFIG_DIR: /etc/dd-action-runner/config
      RUNNER_NAME: my-compose-runner
    volumes:
      - "./config:/etc/dd-action-runner/config"
```

Run with:

```bash
export DD_API_KEY="<YOUR_API_KEY>"
export DD_APP_KEY="<YOUR_APP_KEY>"
docker compose up -d
```

{% /tab %}

{% tab title="Kubernetes" %}
Generate the runner configuration:

```bash
export DD_API_KEY="<YOUR_API_KEY>"
export DD_APP_KEY="<YOUR_APP_KEY>"

docker run \
  -e DD_BASE_URL=https://<span class="js-region-param region-param" data-region-param="dd_site"></span> \
  -e DD_PRIVATE_RUNNER_CONFIG_DIR=/etc/dd-action-runner/config \
  -e DD_API_KEY="$DD_API_KEY" \
  -e DD_APP_KEY="$DD_APP_KEY" \
  -e RUNNER_NAME="my-runner" \
  -v ./config:/etc/dd-action-runner/config \
  gcr.io/datadoghq/private-action-runner:v1.21.0 \
  --with-api-key --enroll -f helm-values > values.yaml
```

Deploy the Helm chart:

```bash
helm upgrade --install <RELEASE_NAME> datadog/private-action-runner -f values.yaml
```

{% /tab %}

When the runner shows **Ready to use**, create a connection for it, or view it on the **Private Action Runners** page.

## Custom CA certificates{% #custom-ca-certificates %}

If your organization uses a custom certificate authority (CA) to issue certificates for internal services, such as HTTP endpoints or Jenkins, you can configure a standalone private action runner to trust that CA.

{% tab title="Docker" %}
Add the `SSL_CERT_DIR` environment variable and mount your certificate to the `docker run` command, replacing `<PATH_TO_YOUR_CA_CERTIFICATE>` with the path to your CA certificate file:

```bash
docker run -d \
  -e DD_BASE_URL=https://<span class="js-region-param region-param" data-region-param="dd_site"></span> \
  -e DD_PRIVATE_RUNNER_CONFIG_DIR=/etc/dd-action-runner/config \
  -e DD_API_KEY="$DD_API_KEY" \
  -e DD_APP_KEY="$DD_APP_KEY" \
  -e RUNNER_NAME=<YOUR_RUNNER_NAME> \
  -e SSL_CERT_DIR=/etc/dd-action-runner/config/ca-certificates \
  -v ./config:/etc/dd-action-runner/config \
  -v <PATH_TO_YOUR_CA_CERTIFICATE>:/etc/dd-action-runner/config/ca-certificates/ca.crt \
  gcr.io/datadoghq/private-action-runner:v1.21.0 \
  --with-api-key
```

{% /tab %}

{% tab title="Docker Compose" %}
Add the `SSL_CERT_DIR` environment variable and mount your certificate in your `docker-compose.yaml` file, replacing `<PATH_TO_YOUR_CA_CERTIFICATE>` with the path to your CA certificate file:

```yaml
services:
  private-runner:
    environment:
      SSL_CERT_DIR: /etc/dd-action-runner/config/ca-certificates
    volumes:
      - "<PATH_TO_YOUR_CA_CERTIFICATE>:/etc/dd-action-runner/config/ca-certificates/ca.crt"
```

{% /tab %}

{% tab title="Kubernetes" %}

1. Create a ConfigMap containing your CA certificate:

   ```bash
   kubectl create configmap my-ca-cert --from-file=ca.crt=./my-custom-ca.pem
   ```

1. In your Helm `values.yaml` file, reference the ConfigMap:

   ```yaml
   runner:
     customCaCert:
       configMapName: my-ca-cert
   ```

1. Apply the updated values:

   ```bash
   helm upgrade --install <RELEASE_NAME> datadog/private-action-runner -f values.yaml
   ```

{% /tab %}

## Connect the runner{% #connect-the-runner %}

A standalone runner is always owned and uses the Connections authorization model. A connection stores the credentials for a service and pairs them with the runner. To create a connection and pair it with your runner, see [Connections](https://docs.datadoghq.com/actions/connections.md). For how permissions on the runner itself work, see [Manage access to owned runners](https://docs.datadoghq.com/actions/private_actions/enroll_runner.md#manage-access-to-owned-runners).

## Manage the runner{% #manage-the-runner %}

### Edit connections or delete a runner{% #edit-connections-or-delete-a-runner %}

From the **Private Action Runner** page in Action Catalog, you can view all your private runners together with the workflows or apps that use each one. To edit the connections for a runner, click **View Details**. Click the trash can icon to delete a runner.

### Change the allowlist{% #change-the-allowlist %}

To edit the allowlist for a standalone runner, edit the `actionsAllowlist` section of the `config.yaml` file in your runner's environment, then restart the runner by restarting your container or deployment.

## Update the runner{% #update-the-runner %}

Choose the tab that matches how you installed the runner. Use the current `v1.21.0` version rather than a hardcoded tag.

{% tab title="Docker" %}
Find the current ID of your container:

```bash
docker ps
```

Stop the container:

```bash
docker stop <id>
```

Start a new container with [the latest image](https://api.datadoghq.com/api/v2/on-prem-management-service/runner/latest-image). Environment variables are not needed: everything is configured in the `config/config.yaml` file.

```bash
docker run -d \
  -e DD_PRIVATE_RUNNER_CONFIG_DIR=/etc/dd-action-runner/config \
  -v ./config:/etc/dd-action-runner/config \
  gcr.io/datadoghq/private-action-runner:v1.21.0
```

After confirming the new version is working, remove the old container:

```bash
docker rm <id>
```

{% /tab %}

{% tab title="Docker Compose" %}
Navigate to the directory containing your `docker-compose.yaml` file and update the image version:

```yaml
services:
  private-actions-runner:
    image: gcr.io/datadoghq/private-action-runner:v1.21.0
```

Start the container again:

```bash
docker compose up -d
```

{% /tab %}

{% tab title="Helm" %}
There are two options for upgrading with Helm:

1. **(Recommended)** Upgrade the chart, which uses the latest version of the runner. There may be changes to the chart; review [the changelog](https://github.com/DataDog/helm-charts/blob/main/charts/private-action-runner/CHANGELOG.md).
1. Upgrade the runner only, without upgrading the chart.

**Upgrading the chart (recommended):**

```bash
helm repo update
helm upgrade <RELEASE_NAME> datadog/private-action-runner -f ./values.yaml
```

**Upgrading the runner only:** specify the runner version in `values.yaml` under the `common.image.tag` key with a value from [the chart's values file](https://github.com/DataDog/helm-charts/blob/main/charts/private-action-runner/values.yaml):

```yaml
common:
  image:
    tag: v1.21.0
```

Then run:

```bash
helm upgrade <RELEASE_NAME> datadog/private-action-runner -f ./values.yaml
```

{% /tab %}

## Further reading{% #further-reading %}

Additional helpful documentation, links, and articles:

- [Private Actions Overview](https://docs.datadoghq.com/actions/private_actions.md)
- [Set up a private action runner in the Datadog Agent](https://docs.datadoghq.com/actions/private_actions/set_up_agent_based.md)
- [Connections](https://docs.datadoghq.com/actions/connections.md)
