---
title: "SSH Access"
description: "Connect to remote servers via SSH using Pangolin identity and certificate-based authentication"
---

import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";

<iframe
  className="w-full aspect-video rounded-xl"
  src="https://www.youtube.com/embed/U4O9pESwMEg"
  title="Pangolin SSH Access walkthrough"
  frameBorder="0"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  allowFullScreen
></iframe>

<PangolinCloudTocCta />

<Note>
Only available in [Pangolin Cloud](https://app.pangolin.net/auth/signup) and [Enterprise Edition](/self-host/enterprise-edition).
</Note>

## Overview

Pangolin includes a built-in SSH client so you can connect to remote servers and manage them directly from the terminal. You use your existing Pangolin identity—no separate SSH keys to create or copy. Pangolin generates and signs temporary access keys, pushes them to the remote server, and creates or updates your user account there. All of this happens automatically when you start a connection.

You can SSH into any Pangolin site or private resource. Two components handle SSH on the server side:

<CardGroup cols={2}>
  <Card title="Newt Host" icon="plug" href="#configure-ssh-on-the-newt-host">
    Runs as a daemon and handles SSH for the host it runs on. Use this when the machine you want to SSH into is the same server running Newt.
  </Card>
  <Card title="Hosts Behind Newt" icon="server" href="#configure-ssh-on-hosts-behind-newt">
    Handles SSH for other servers on the same network. Run the auth daemon on each target host; Newt on a bastion proxies connections to them.
  </Card>
</CardGroup>

You connect using the Pangolin CLI as the SSH client. The tunnel can be provided by the CLI or by another Pangolin client (e.g. the macOS app); you can run the GUI for the tunnel and use the CLI only for SSH if you prefer.

## How certificates work

Each organization has a **certificate authority (CA)** used to sign temporary SSH keys.

1. When you run `pangolin ssh <alias>`, the Pangolin client generates a temporary key pair.
2. It sends the public key to the Pangolin server with your identity and the target resource.
3. The server checks that you are allowed to access that resource, then signs the public key with the organization CA and returns it. The CA public key is also sent to the remote server and trusted there.
4. The client connects to the remote host using the temporary private key. The host verifies the certificate with the CA and uses principals in the certificate for access control.

This gives short-lived, auditable access without long-lived keys on the server.

## How users and access are managed

Users are provisioned **just in time** on the remote system. When you connect, Pangolin ensures an account exists for you with the right permissions before the SSH session starts. Your Pangolin identity is mapped to a local username (derived from the part before `@` in your identity; if needed, a suffix is added for uniqueness). The account is created with a home directory and can be granted sudo access as configured.

## Setup: choose your architecture

Newt can provide SSH access for its own host, for other hosts behind it, or for both at the same time.

Before you begin:

- Install Newt on the host that will run the site connector. See [Install Site](/manage/sites/install-site).
- Install the Pangolin CLI on any machine that will initiate `pangolin ssh` sessions. See [Install Clients](/manage/clients/install-client#quick-install-recommended-—-linux-and-macos).

| Layout | Use this when | Newt flags |
|--------|---------------|------------|
| **Newt host only** | Users only need SSH access to the server running Newt | `--auth-daemon` |
| **Hosts behind Newt only** | Users only need SSH access to other servers on the same network as Newt | `--ad-pre-shared-key <pre-shared-key>` |
| **Mixed deployment** | Users need SSH access to the Newt host **and** to other servers behind it | `--auth-daemon --ad-pre-shared-key <pre-shared-key>` |

<Note>
You do not need to choose a single site-wide SSH mode. A single Newt instance can handle **On Site** SSH access for the Newt host and also authenticate **Remote Host** SSH access for other target hosts.
</Note>

## Understand the model

The easiest way to think about SSH in Pangolin is:

1. Each SSH target gets its own **private resource**.
2. That resource decides **how Pangolin reaches that host**.
3. The host itself must be configured to match that resource.

In a mixed deployment, you will create one resource for the Newt host and separate resources for each host behind Newt.

## Start Newt for your layout

With Newt [installed](/manage/sites/install-site), start it with the flags that match your layout:

| Layout | Command |
|--------|---------|
| Newt host only | `sudo newt --id <id> --secret <secret> --endpoint <endpoint> --auth-daemon` |
| Hosts behind Newt only | `sudo newt --id <id> --secret <secret> --endpoint <endpoint> --ad-pre-shared-key <pre-shared-key>` |
| Mixed deployment | `sudo newt --id <id> --secret <secret> --endpoint <endpoint> --auth-daemon --ad-pre-shared-key <pre-shared-key>` |

Relevant environment variables:

| Flag | Environment variable |
|------|----------------------|
| `--id` | `NEWT_ID` |
| `--secret` | `NEWT_SECRET` |
| `--endpoint` | `PANGOLIN_ENDPOINT` |
| `--auth-daemon` | `AUTH_DAEMON_ENABLED=true` |
| `--ad-pre-shared-key` | `AD_KEY` |

See [more environment variables](/manage/sites/configure-site#environment-variables).

<Note>
Replace `<id>`, `<secret>`, and `<endpoint>` with the values from your site configuration in the Pangolin dashboard.
If you use `<pre-shared-key>`, choose a strong random value and reuse the same value on each target host running `pangolin auth-daemon`.
For example, you can generate one with:

```bash
openssl rand -hex 32
```
</Note>

## Configure SSH on the Newt host

If you want SSH access to the Newt host itself, run the `newt` binary directly on that host.
Do not treat this as a normal container use case. Newt needs to work with the host's own SSH configuration and local auth-daemon state, so a standard container deployment is not suitable for this path.

Add or adjust these lines in `/etc/ssh/sshd_config`:

```ini title="/etc/ssh/sshd_config"
TrustedUserCAKeys /etc/ssh/ca.pem
AuthorizedPrincipalsCommand /usr/local/bin/newt auth-daemon principals --username %u
AuthorizedPrincipalsCommandUser root
```

Restart the SSH server:

```bash
sudo systemctl restart ssh
```

## Configure SSH on hosts behind Newt

Do this on every target server behind Newt that should accept SSH.

These hosts need the Pangolin CLI installed because the remote-side SSH integration is provided by `pangolin auth-daemon`. See [Install Clients](/manage/clients/install-client#quick-install-recommended-—-linux-and-macos).

### Step 1: Start the auth daemon

Run the auth daemon with the same pre-shared key used on Newt:

```bash
sudo pangolin auth-daemon --pre-shared-key <pre-shared-key>
```

To use a non-default port, add `--port <port>`. When you create the dashboard resource later, set the same daemon port in that resource's `SSH Access` tab. If you do not set a custom port, the default is **22123**.

#### Run as a systemd service

Create a systemd unit so the auth daemon runs on boot:

```ini title="/etc/systemd/system/pangolin-auth-daemon.service"
[Unit]
Description=Pangolin SSH auth daemon
After=network.target

[Service]
ExecStart=/usr/local/bin/pangolin auth-daemon --pre-shared-key <pre-shared-key>
Restart=always
User=root

[Install]
WantedBy=multi-user.target
```

Replace `<pre-shared-key>` with the same value used on Newt. If you use a custom port (set in the resource's `SSH Access` tab), add `--port <port>` to `ExecStart`. Then:

```bash
sudo systemctl daemon-reload
sudo systemctl enable pangolin-auth-daemon
sudo systemctl start pangolin-auth-daemon
sudo systemctl status pangolin-auth-daemon
```

Ensure the Pangolin CLI binary is at `/usr/local/bin/pangolin`, or update `ExecStart` to the correct path.

### Step 2: Configure `sshd`

Add or adjust these lines in `/etc/ssh/sshd_config`:

```ini title="/etc/ssh/sshd_config"
TrustedUserCAKeys /etc/ssh/ca.pem
AuthorizedPrincipalsCommand /usr/local/bin/pangolin auth-daemon principals --username %u
AuthorizedPrincipalsCommandUser root
```

Restart the SSH server:

```bash
sudo systemctl restart ssh
```

### Step 3: Ensure network connectivity

- **Newt → auth daemon:** Newt must be able to reach the auth daemon port on each target server (default **TCP 22123**; configurable in the resource's `SSH Access` tab and via the auth daemon's `--port` flag).
- **Clients → SSH:** Port **22** must be open for SSH to each target server from wherever your users connect.

<Note>
To change the auth daemon port from the default 22123, configure the same port in the resource's `SSH Access` tab in Pangolin and pass it with `--port` when starting the auth daemon.
The auth-daemon port only needs to be reachable by Newt inside your network. It does not need to be exposed publicly, so restrict it with a firewall or network policy as appropriate for your environment.
</Note>

## Configure resources in the dashboard

After the host-side services are running, create the corresponding private resources in Pangolin.

| Resource type | Destination | Recommended alias | SSH access policy |
|---------------|-------------|-------------------|-------------------|
| Newt host | Usually `127.0.0.1` or `localhost` on the server running Newt | `ssh.<site>.internal`, for example `ssh.prod.internal` | In `SSH Access`, set **SSH Auth Daemon Location** to **On Site** |
| Host behind Newt | The target server | `<host>.<site>.internal`, for example `db-01.prod.internal` | In `SSH Access`, set **SSH Auth Daemon Location** to **Remote Host** |

For each resource:

1. Set the destination to the IP or FQDN of the correct host. For the Newt host itself, this is typically `127.0.0.1` or `localhost`.
2. Set an [alias](/manage/resources/private/alias) using the recommended pattern above.
3. Open the resource's `SSH Access` tab and set **SSH Auth Daemon Location** to match that host:
   `On Site` for the Newt host, or `Remote Host` for a host behind Newt.
4. If the resource points to a host behind Newt, set the daemon port to match that host's auth daemon. Use **22123** unless you changed it with `pangolin auth-daemon --port <port>`.
5. Grant access to the required users or roles.
6. In port restrictions, allow the host's SSH port: **TCP 22** by default, or a custom SSH port if your server uses one.

<Note>
Two ports matter here:

- The **SSH port** is the port users connect to on the target host. This is usually `22`, and it must be allowed in the resource's port restrictions.
- The **daemon port** is the port Newt uses to reach `pangolin auth-daemon` on hosts behind Newt. This is `22123` by default, or whatever you set with `--port`.
</Note>

## Connect

Once the resources and host-side SSH integrations match, users can connect with the alias or resource identifier for the specific host they want:

```bash
pangolin ssh db-01.prod.internal
```

## Signing keys for other applications

You can ask Pangolin to sign a key for a resource without starting an interactive SSH session. Useful for scripts or tools that use SSH with a specific key:

```bash
pangolin ssh sign db-01.prod.internal --key-file /path/to/public/key.pub
```

## Generating passwords for users

If you need a password to be generated for your user on the remote system (e.g. for sudo access or if you have passwords required in your sshd config), you can use:

`--generate-random-password` to have Pangolin generate a random password when users are created on the device

```bash
pangolin auth-daemon --generate-random-password
```

## FAQ

### How long are the temporary keys valid?

When the client requests a signed key from the Pangolin server, the certificate is valid for **5 minutes**. You must start the SSH connection within that window. Once the session is established, it can stay open; the certificate is only needed for the initial authentication.

### Is the SSH connection proxied through Newt?

If the resource points to the **Newt host itself**, no. Your client connects directly to the server running Newt.

If the resource points to a **host behind Newt**, yes. Your client connects to Newt, and Newt proxies the SSH session to the target server. In a mixed deployment, both behaviors can exist at the same time depending on which resource the user selects.

### How are usernames created on the remote server?

Pangolin derives the remote username from your Pangolin identity (the part before `@`). If that name is already taken in the organization, a numeric suffix is added until it is unique. The user is created with a home directory and can be added to sudoers as configured by your organization.

### How does Newt communicate with the external auth daemon?

Newt talks to the auth daemon over **HTTPS**. **TCP 22123** is used by default. When you SSH into a server that uses the external auth daemon, Newt calls the auth daemon on that host to create or update your user and resolve principals. Port 22123 only needs to be open between Newt and the auth daemon hosts on your internal network; it should not be exposed to the internet.

To use a different port, set the port in the resource’s SSH settings in the Pangolin dashboard and pass the same port to the auth daemon with the `--port` flag (e.g. `pangolin auth-daemon --pre-shared-key <key> --port 22124`). Newt and the auth daemon must use the same port.
