Get started - it's free!
Log in
© 2025

Tailscale GitHub Action

The Tailscale GitHub Action is a GitHub Action that lets you connect your Tailscale network (known as a tailnet) to a GitHub Actions workflow.

You can access devices in your tailnet directly from your GitHub workflow, which opens up a range of possibilities:

  • Securely deploy your application to an internal server (even if you're using a GitHub-hosted runner).
  • Securely reach your self-hosted runners for specific platforms.
  • Reach your database of test data without leaving it exposed on the internet.
  • Access an internal deployment monitoring tool.

Prerequisites

Before using the Tailscale GitHub Action, ensure you have the following:

  1. A Tailscale account with Owner, Admin, or Network admin permissions.
  2. A GitHub repository that you have admin access to (required to set up the GitHub Action).
  3. At least one configured tag.
  4. An OAuth client ID and secret OR an auth key.
  5. A runner image version >= 2.237.1 (required to support running Node.js 24).

How it works

When you add the Tailscale GitHub Action to your workflow, subsequent steps in your GitHub Action can then access nodes in your tailnet. For example, the workflow could access a node that has a database of test data.

The Tailscale GitHub Action requires an OAuth client ID and secret OR an auth key that uses a tag identity and is reusable, ephemeral, and (if applicable) pre-approved.

We recommend that you use an OAuth client ID and secret. The OAuth client requires the auth_keys scope. You store the OAuth client ID and secret as GitHub encrypted secrets. OAuth clients are not associated with any user in your tailnet you must create tag to identify the GitHub runner. When you identify a device (such as GitHub runner) with a tag, it automatically applies the access permissions granted to that tag.

When your workflow runs, it uses the OAuth client ID and secret to create an ephemeral node. The ephemeral node can then access devices in your tailnet based on the access permissions granted to the tag you use to identify the GitHub runner.

Any ephemeral node that the Tailscale GitHub Action creates using an OAuth client is pre-approved on tailnets that use device approval.

The GitHub Action logs out the ephemeral node immediately after the CI workflow completes, at which point the control server automatically removes the ephemeral node from your tailnet. The next time the action runs, it creates a new ephemeral node that's only available for the new workflow.

Add the Tailscale GitHub Action to a workflow

  1. Create at least one tag for the ephemeral nodes that the Tailscale GitHub Action will create. For example, tag:ci, which is used for this example. The access permissions that you grant to the tags are applied to the nodes that will be created by the workflow.

  2. Set up a Tailscale OAuth client. You'll need the value of your OAuth Client ID and Client secret. If you are using an auth key instead of an OAuth client, refer to Using an auth key.

  3. Create a GitHub repository secret with the name TS_OAUTH_CLIENT_ID and assign your OAuth Client ID as the secret value.

  4. Create a GitHub repository secret with the name TS_OAUTH_SECRET and assign your OAuth Client secret as the secret value.

  5. In your GitHub Actions workflow, connect to your tailnet using the Tailscale GitHub Action. For example:

    - name: Tailscale
      uses: tailscale/github-action@v4
      with:
        oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
        oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
        tags: tag:ci
    

oauth-client-id and oauth-secret are your OAuth Client ID and Client secret, respectively. tags is a comma-separated list of the tags applied to the ephemeral nodes that the GitHub Action creates. These tags must already exist in your tailnet.

When the action runs, it creates an ephemeral node. The node can access nodes in your tailnet, subject to the access rules applied to the specified tag or tags. In the rest of your workflow, access other nodes in your tailnet as needed.

The ephemeral node is automatically cleaned up shortly after the action finishes.

Auth key considerations

If you are using an auth key instead of an OAuth client, it's best practice to ensure that the key type uses a tag identity, is reusable, and is ephemeral. If the tailnet uses device approval, ensure that the key type is also pre-approved.

To use the auth key for your workflow, create a GitHub secret with the name TAILSCALE_AUTHKEY and the value set to your auth key. Then use the authkey field to reference the secret in your workflow. For example:

- name: Tailscale
  uses: tailscale/github-action@v4
  with:
    authkey: ${{ secrets.TAILSCALE_AUTHKEY }}

Ping to verify connectivity

Information about new tailnet devices, such as the ephemeral node created by this GitHub Action, takes some time to propagate across your tailnet, and you might experience brief delays. These devices only allow connections from your GitHub workflow node after they have received this information. Tailscale recommends that you check connectivity to the intended devices by specifying their IP addresses or hostnames using the ping parameter. The GitHub Action waits up to three minutes to verify either direct or relayed connectivity to the listed peers.

For example:

- name: Tailscale
  uses: tailscale/github-action@v4
  with:
    ping: 100.x.y.z,machine-1.my-tailnet.ts.net,machine-2

If you do not wish to use the ping feature, or you do not know the peer tailnet devices at the time of installing Tailscale in the workflow, consider using the tailscale ping command in your own workflow step:

tailscale ping my-target.my-tailnet.ts.net

Tailscale client version

Tailscale does not update the client version for the Tailscale GitHub Action every time there is a new Tailscale client release. The default version specified in the base YAML file remains unchanged for long periods of time. It changes only when there is a meaningful reason to do so.

If you would like to set the version yourself, add a version entry to your workflow:

  - name: Tailscale
    uses: tailscale/github-action@v4
    with:
      oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
      oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
      tags: tag:ci
      version: 1.66.0

If you would like to specify the latest stable version, set the version to latest.

  - name: Tailscale
    uses: tailscale/github-action@v4
    with:
      oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
      oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
      tags: tag:ci
      version: latest

If you would like to specify the latest unstable version, set the version to unstable.

  - name: Tailscale
    uses: tailscale/github-action@v4
    with:
      oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
      oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
      tags: tag:ci
      version: unstable

You can find the latest Tailscale stable version number at our stable release track, and the latest unstable version number at our unstable release track. For Linux and Windows, this uses the version published at https://pkgs.tailscale.com/unstable, and macOS uses the HEAD of the main branch of https://github.com/tailscale/tailscale/.

Cache Tailscale binaries

Caching can reduce download times and download failures on runners with slower network connectivity. Caching is enabled by default.

You can opt out of caching Tailscale binaries by passing 'false' to the use-cache input:

  - name: Tailscale
    uses: tailscale/github-action@v4
    with:
      oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
      oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
      use-cache: 'false'

Last updated Oct 14, 2025