---
title: "Add additional SSH keys to CircleCI"
description: "Add additional SSH keys to your CircleCI project so jobs can deploy to servers, push commits, and check out other private repositories."
platform: "Cloud, Server"
doc_version: "Server"
last_updated: "2026-10-20"
---

> 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).

# Add additional SSH keys to CircleCI

When CircleCI checks out your code, the credentials it uses reach only the repository that triggered the pipeline. If a job needs to deploy to a server, push a commit, or clone another private repository over SSH, the job needs a second set of credentials. Add an additional SSH key to your project to give your jobs that access.

## Why add additional SSH keys to a project?

The credentials CircleCI creates for code checkout are deliberately narrow. They are scoped to a single repository. Depending on your pipeline type, they are read-only or are not SSH credentials at all. See [How checkout credentials differ by pipeline type](#how-checkout-credentials-differ-by-pipeline-type) for details. Any other SSH connection from a job needs a key that you provide.

Add an additional SSH key when a job needs to do any of the following:

*   Deploy to a server or service. Hosts such as virtual machines, bastion hosts, and `git.heroku.com` authenticate deployments with an SSH key. See the [Deploy Over SSH](https://circleci.com/docs/guides/server/deploy/deploy-over-ssh/) guide for an example.
    
*   Check out other private repositories. Private dependencies, submodules, and shared scripts live outside the repository that triggered the pipeline, so the checkout credentials cannot read them.
    
*   Push to a repository. Commits for a changelog update, a version bump, or a tag need write access, and checkout credentials are read-only.
    
*   Connect to any other SSH-only service, such as a backup host or an artifact server.
    

Each key is stored encrypted in your project settings. A job can use a key only when its configuration lists that key’s fingerprint, so you control which jobs get access.

The following diagram shows what happens when a job uses an additional SSH key. The job checks out your repository using the access CircleCI set up for the project. The `add_ssh_keys` step then makes your key available to the job. When the job connects to a host over SSH, the target service accepts the connection only if it holds the matching public key.

```mermaid
flowchart LR
    Add[Job checks out your repository,
then add_ssh_keys writes
your private key to ~/.ssh] --> Connect[Job connects over SSH
and SSH offers
your key for that host]
    Connect --> Check{Target service has
the matching
public key?}
    Check -->|Yes| Access[Access granted]
    Check -->|No| Denied[Permission denied]
```

Figure 1. What happens when a job uses an additional SSH key

### Choose between a user key and an additional SSH key

If you want to check out code from additional repositories in GitHub, you can add a user key instead. A user key inherits the access of a GitHub account. See the [Create a User Key](https://circleci.com/docs/guides/server/permissions-authentication/users-organizations-and-integrations-guide/#create-a-user-key) section of the Users, Organizations, and Integrations Guide for steps.

For all other cases, follow the steps on this page to add an additional SSH key. An additional SSH key can also be limited to one repository or one host.

## Prerequisites

Before you add an additional SSH key, make sure you have the following:

*   A project set up in CircleCI.
    
*   Access to the service the job connects to, so you can add the public key. For a deployment, that is the server’s `~/.ssh/authorized_keys` file. For a repository, it is the repository or account settings on your VCS provider.
    
*   `ssh-keygen` installed on your local machine.
    

## 1\. Add the key to your project

Add the private key to CircleCI, and add the matching public key to the service the job connects to.

### 1.1 Create an SSH key pair

CircleCI cannot decrypt SSH keys, so the key must have an empty passphrase. The following command creates an ed25519 key pair with no passphrase.

```console
$ ssh-keygen -t ed25519 -C "<your-email>" -f ~/.ssh/<key-name> -N ""
```

Replace `<your-email>` and `<key-name>` with your own values, and keep the double quotes.

### 1.2 Add the public key to the service

Add the public key (`~/.ssh/<key-name>.pub`) to the service the job connects to. The location depends on the service.

*   For a server you deploy to, append the public key to `~/.ssh/authorized_keys` for the user the job connects as.
    
*   For a repository, add the public key as a deploy key, or to a machine user account, on your VCS provider. For help generating and adding keys, see the following documentation:
    
    *   [GitHub](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent)
        
    

### 1.3 Add the private key to CircleCI

1.  In the CircleCI web app, select your org from the org cards on your user homepage.
    
2.  Select **Projects** from the sidebar and locate your project from the list. You can use the search to help.
    
3.  Select the ellipsis next to your project and select **Project Settings**.
    
    You can also access project settings from each project overview page using the **Settings** button.
    

4.  In the sidebar menu, select **SSH Keys**.
    
5.  Scroll down to the **Additional SSH Keys** section.
    
6.  Select **Add SSH Key**.
    
7.  In the **Hostname** field, enter the key’s associated host (for example, `git.heroku.com`). If you do not specify a hostname, the key will be used for all hosts.
    
8.  In the **Private Key** field, paste the private key you created.
    
9.  Select **Add SSH Key**.
    

Adding a key to your project does not give any job access to it. Next, add the key to each job that needs it. See [2\. Add the key to a job](#add-ssh-keys-to-a-job).

## 2\. Add the key to a job

After you add a key to your project, add it to each job that needs it. Even though all CircleCI jobs use `ssh-agent` to automatically sign all added SSH keys, you **must** use the `add_ssh_keys` key to actually add keys to a container.

1.  Copy the key’s fingerprint from **Project Settings**  **SSH Keys**  **Additional SSH Keys**. CircleCI shows the SHA256 fingerprint.
    
2.  In your configuration file, add the `add_ssh_keys` [Special Step](https://circleci.com/docs/reference/configuration-reference/#add-ssh-keys) to the appropriate [Job](https://circleci.com/docs/guides/server/orchestrate/jobs-steps/), and list the fingerprint. The fingerprint can be SHA256 or MD5. Prefix SHA256 fingerprints with `SHA256:`, and include the colons between character pairs for MD5 fingerprints.
    
    ```yaml
    jobs:
      deploy-job:
        docker:
          - image: cimg/base:2026.10
        steps:
          - add_ssh_keys:
              fingerprints:
                # An MD5 fingerprint, with colons between character pairs
                - "SO:ME:FIN:G:ER:PR:IN:T"
                # A SHA256 fingerprint, prefixed with SHA256:
                - "SHA256:NPj4IcXxqQEKGXOghi/QbG2sohoNfvZ30JwCcdSSNM0"
    ```
    
3.  If the job checks out additional repositories, make sure the public key is added to each of those repositories. Run the `checkout` command **before** `add_ssh_keys`.
    

All fingerprints in the `fingerprints` list must correspond to keys that have been added through the CircleCI application. Fingerprints in CircleCI environment variables will fail.

If the job cannot connect, or uses the wrong key, see the following sections:

*   [Add the host to known\_hosts](#add-the-host-to-known-hosts)
    
*   [Adding multiple keys with blank hostnames](#adding-multiple-keys-with-blank-hostnames)
    
*   [Using specific SSH keys for a job](#using-specific-ssh-keys-for-a-job)
    

## How checkout credentials differ by pipeline type

How much access a job already has depends on how your pipeline checks out code.

*   GitHub and GitHub Enterprise Server pipelines: CircleCI creates a read-only deploy key for the single repository that triggered the pipeline.
    

For a full description of each pipeline type, see the [How CircleCI Checks Out Your Code](https://circleci.com/docs/guides/server/permissions-authentication/users-organizations-and-integrations-guide/#how-circleci-checks-out-your-code) section of the Users, Organizations, and Integrations Guide.

## Add the host to known\_hosts

SSH refuses to connect to a host that is not in `~/.ssh/known_hosts`, unless you disable host key checking. The `checkout` step adds the host keys for GitHub.com and Bitbucket Cloud automatically. You must add the host key yourself in the following cases:

*   You use a custom checkout command instead of the `checkout` step.
    
*   Your job connects to any other host, such as a deployment target.
    

To add a host key, run `ssh-keyscan <host> >> ~/.ssh/known_hosts` in your job before the SSH connection. For steps to verify a host key, see the [Establish the Authenticity of an SSH Host](https://circleci.com/docs/guides/server/permissions-authentication/users-organizations-and-integrations-guide/#establish-the-authenticity-of-an-ssh-host) section of the Users, Organizations, and Integrations Guide.

## Use SSH keys with a self-hosted runner

For a self-hosted runner, ensure that you have an `ssh-agent` on your system to successfully use the `add_ssh_keys` step. The SSH key is written to `$HOME/.ssh/id_rsa_<fingerprint>`, where `$HOME` is the home directory of the user configured to execute jobs, and `<fingerprint>` is the MD5 fingerprint of the key. A host entry is also appended to `$HOME/.ssh/config`, along with a relevant `IdentityFile` option to use the key.

## Adding multiple keys with blank hostnames

If you add multiple SSH keys with blank hostnames to your project, you will need to make some changes to the default SSH configuration provided by CircleCI.

If you have multiple SSH keys for different purposes that have access to the same hosts, the default `IdentitiesOnly no` is set, which causes connections to use `ssh-agent`.

In this scenario, the first key is used regardless of whether it is the correct key. If you have added the SSH key to a container, either set `IdentitiesOnly yes` in the appropriate block, or remove all keys from the `ssh-agent` for the job using `ssh-add -D`. Then, read the added key using `ssh-add /path/to/key`.

## Using specific SSH keys for a job

If you have added multiple SSH keys for the same hostname to your project, SSH may offer the wrong key. To make a command use a specific key, point the command at that key’s file and tell SSH to use only that key.

CircleCI saves each key added with `add_ssh_keys` in `~/.ssh` on the job’s executor. The filename is `id_rsa_` followed by the key’s MD5 fingerprint with the colons removed. For example, the MD5 fingerprint `a3:f9:82:c5:1d:47:9b:e6:88:32:a1:bc:f4:29:7e:15` is saved as `id_rsa_a3f982c51d479be68832a1bcf4297e15`.

1.  Find the MD5 fingerprint of the key. Run the following command on your local machine, using the path to the private key you created. The fingerprint follows `MD5:` in the output.
    
    ```console
    $ ssh-keygen -l -E md5 -f ~/.ssh/<key-name>
    ```
    
2.  Remove the colons from the fingerprint, and add `id_rsa_` to the start. The result is the filename of the key on the executor.
    
3.  In your configuration file, add the key to the job with the `add_ssh_keys` step. Then, in a later `run` step, add the following to your SSH command:
    
    *   `-i ~/.ssh/<filename>` to specify the key file from the previous step.
        
    *   `-o "IdentitiesOnly=yes"` to stop SSH from trying other keys from the SSH agent.
        
    

The following job adds a key and uses it to connect to a host. Replace `<user>@<hostname>` with your own values, and replace the fingerprint and key filename with those of your key.

```yaml
version: 2.1
jobs:
  deploy-job:
    docker:
      - image: cimg/base:2026.10
    steps:
      - add_ssh_keys:
          fingerprints:
            # The fingerprint of the key as shown in Project Settings
            - "a3:f9:82:c5:1d:47:9b:e6:88:32:a1:bc:f4:29:7e:15"
      - run:
          name: Connect with a specific key
          # -i selects the key file, saved as id_rsa_ plus the MD5 fingerprint without colons
          # IdentitiesOnly=yes stops SSH from trying other keys in the agent
          command: ssh -i ~/.ssh/id_rsa_a3f982c51d479be68832a1bcf4297e15 -o "IdentitiesOnly=yes" <user>@<hostname> "echo connected"
workflows:
  deploy:
    jobs:
      - deploy-job
```