Skip to content

SSH Keys

Managed uses SSH keys to connect to your servers for running commands, installing services, and uploading files.

Automatic setup

When you run managed init, the wizard will:

  1. Scan ~/.ssh/ for existing key pairs (id_ed25519, id_rsa, id_ecdsa)
  2. Let you pick an existing key or generate a new one
  3. Save the choice in managed.yaml under defaults

If you run managed apply without a configured SSH key, the same wizard runs automatically.

Generated keys

When you choose "Generate a new key", managed creates an Ed25519 key pair at:

.managed/ssh_keys/managed_ed25519
.managed/ssh_keys/managed_ed25519.pub

These are stored in your project directory (not ~/.ssh/), so each project can have its own key. The .managed/ directory should be added to .gitignore.

Manual setup

You can also generate a key manually:

bash
managed ssh generate-key
managed ssh generate-key --name my-key --dir ~/.ssh

Configuration

SSH key settings live in the defaults section of managed.yaml:

yaml
defaults:
  provider: digitalocean
  ssh_key_name: managed_ed25519
FieldDescription
ssh_key_nameBase name of the key file (looked up in .managed/ssh_keys/ or ~/.ssh/)
ssh_private_key_pathFull path to a private key (overrides directory lookup)
ssh_key_directoryDirectory to search for keys (default: .managed/ssh_keys)

Using an existing key from ~/.ssh

yaml
defaults:
  ssh_key_name: id_rsa
  ssh_private_key_path: ~/.ssh/id_rsa

Using SSH agent

If you use an SSH agent (e.g. 1Password), set the key name to agent:

yaml
defaults:
  ssh_key_name: agent

This skips file-based key lookup and uses the agent for authentication.

How it works

When managed apply creates a server:

  1. Resolves the SSH key from config defaults
  2. Reads the .pub file
  3. Uploads the public key to the cloud provider
  4. Creates the server with that key
  5. Uses the private key for all subsequent SSH connections

The public key is uploaded once per provider, if it already exists with the same content, the upload is skipped.

Server identity (host keys)

The keys above prove who you are to the server. Servers also prove who they are: each one has an SSH identity (its host keys), and managed pins it.

The first time managed connects to a server — the moment it's provisioned or imported, which is a moment you control — the identity the server presents is recorded in the project (ssh_host_keys on the server's saved state). Every later connection requires the server to present that same identity, and is refused before any passwords or commands are sent if it doesn't. This is what stops someone on the network from impersonating your server and capturing credentials.

When a connection is refused you'll see:

✗ Stopped connecting to 'database-1' — it is not the server managed remembers.
  Either it was rebuilt, or something between you and the server is
  intercepting the connection

If you didn't change the server, treat this seriously — don't connect until you understand why its identity changed.

If you did rebuild, restore, or reinstall the server on purpose, accept its new identity and retry:

bash
managed server trust database-1
managed apply

Servers set up before this feature simply have their identity recorded on the next connection — no action needed.