donnfelker/kamal-skills · Archived

ssh

Configure how Kamal connects to servers over SSH and tune SSHKit connection handling. Use when the user sets the SSH `user` or `port`, authenticate with specific `keys`/`key_data`, force `keys_only`, control agent forwarding (`forward_agent`), load an OpenSSH `config` file, connect through a jump/bastion host with `proxy` or `proxy_command`, debug connection problems with `log_level: debug`, or tune concurrency and pooling (`max_concurrent_starts`, `pool_idle_timeout`, `dns_retries`) when deplo…

First seen Jul 6, 2026

Installation

$ npx skills add donnfelker/kamal-skills --skill ssh

Summary

  • Configure how Kamal connects to servers over SSH and tune SSHKit connection handling.
  • Use when the user sets the SSH `user` or `port`, authenticate with specific `keys`/`key_data`, force `keys_only`, control agent forwarding (`forward_agent`), load an OpenSSH `config` file, connect through a jump/bastion host with `proxy` or `proxy_command`, debug connection problems with `log_level: debug`, or tune concurrency and pooling (`max_concurrent_starts`, `pool_idle_timeout`, `dns_retries`) when deploying to many hosts.
  • Also use when they say "kamal can''t connect to my server," "permission denied (publickey)," "deploy as a non-root user," "kamal through a bastion/jump host," "SSH timeouts deploying to lots of servers," or "change the SSH port for kamal." These map to the `ssh:` and `sshkit:` blocks in `config/deploy.yml`.
  • For first-time project setup, see setup.
  • For defining the hosts and roles you connect to, see servers.

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from donnfelker/kamal-skills · top by installs.

npx skills add donnfelker/kamal-skills

Browse all from donnfelker/kamal-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

License LICENSE
Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0
More metadata
version
1.0.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 8,052 B
  • docs SUMMARY.md 941 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

SSH Connectivity and SSHKit Tuning

You are an expert in deploying applications with Kamal. Your goal here is to get Kamal connecting reliably to the user's servers over SSH, and — when they deploy to many hosts — to tune the SSHKit connection layer so deploys don't stall or fail.

Kamal uses SSH to connect and run commands on your hosts. By default it connects to the root user on port 22, authenticated by your SSH key. Two configuration blocks control this, both in config/deploy.yml:

  • ssh: — who you connect as, on what port, with which keys, and through which proxy.
  • sshkit: — how the underlying SSHKit toolkit manages connection concurrency and pooling.

Before You Start

Read what the user already has before asking questions:

  • config/deploy.yml — check for existing ssh: and sshkit: blocks, and look at the servers: list to see how many hosts you're connecting to.
  • .kamal/secrets — if you'll reference a private key by secret name (key_data), confirm the secret exists here.
  • ~/.ssh/config — existing host aliases, users, ports, or ProxyJump entries may already define how to reach these hosts.

Then run kamal config to print the resolved configuration, including the :ssh_options: Kamal will actually use (user, port, log level). This is the fastest way to confirm what's in effect before changing anything.

How Kamal Uses SSH

Defaults: root user, port 22. When you run kamal setup, Kamal connects to each server over SSH (root by default), installs Docker if missing, and proceeds with the deploy. Root access over SSH is what lets the initial Docker install happen.

If you connect as a non-root user, you may need to bootstrap each server manually first so the user can run Docker. On Ubuntu:

sudo apt update
sudo apt upgrade -y
sudo apt install -y docker.io curl git
sudo usermod -a -G docker app

Step 1: Set the SSH User and Port

All SSH settings live under the ssh: key. Set the login user and port if they differ from the defaults:

ssh:
  user: app
  port: "2222"
  • user defaults to root.
  • port defaults to 22.

If you changed the user to a non-root account, make sure you bootstrapped Docker access for it (see above).

Step 2: Authenticate

By default Kamal authenticates with the keys your ssh-agent offers and your OpenSSH config. To be explicit, point Kamal at specific keys.

Use specific key files

keys is an array of private-key file names used for public-key and host-based authentication:

ssh:
  keys: [ "~/.ssh/id.pem" ]

Supply a key from a secret

key_data is an array where each element is a secret name (resolved from .kamal/secrets):

ssh:
  key_data:
    - SSH_PRIVATE_KEY

This is the preferred way to inject a key in CI. You can also pass a raw PEM string here, but that is deprecated.

Force a single identity

If your ssh-agent offers many identities (a common cause of Too many authentication failures), set keysonly: true so Kamal uses only the keys from keys and keydata:

ssh:
  keys_only: true
  keys: [ "~/.ssh/id.pem" ]

OpenSSH config and agent forwarding

  • config controls whether the default OpenSSH config files (~/.ssh/config, /etc/ssh_config) are loaded. It defaults to true. Set it to false to ignore them, or to a path (or array of paths) to load specific files.
  • forward_agent controls whether your local SSH agent is forwarded to the remote host. It defaults to true (SSHKit's default).
ssh:
  config: [ "~/.ssh/myconfig" ]
  forward_agent: false

See [references/ssh-options.md](references/ssh-options.md) for the full ssh: key reference.

Step 3: Connect Through a Jump / Bastion Host

If your servers aren't reachable directly, route the connection through a proxy (bastion/jump) host.

Proxy host

proxy takes the form <host> or <user>@<host>:

ssh:
  proxy: root@proxy-host

Custom proxy command

For older versions of SSH that need an explicit command, use proxy_command:

ssh:
  proxy_command: "ssh -W %h:%p user@proxy"

Agent forwarding through a jump host

Set forward_agent: false when connecting through a jump host or tunnel that does not support agent forwarding — for example, Cloudflare Access for Infrastructure with SSH:

ssh:
  proxy: bastion.example.com
  forward_agent: false

Step 4: Debug Connection Issues

When a deploy fails with an SSH error (permission denied, timeouts, host key problems), raise the log level. log_level defaults to fatal; set it to debug to see the underlying SSH negotiation:

ssh:
  log_level: debug

Use this together with kamal config (to confirm the resolved user/port/keys) to pinpoint whether the problem is authentication, the wrong port, or the proxy.

Step 5: Tune SSHKit for Many Servers

The SSHKit defaults are sufficient for most deployments. Reach for the sshkit: block when you deploy to a large number of hosts and see connection storms, DNS hiccups, or reconnection churn.

sshkit:
  max_concurrent_starts: 10
  pool_idle_timeout: 300
  dns_retries: 3
Key Default What it does
maxconcurrentstarts 30 Caps how many SSH connections Kamal opens at once. Lower it when opening many connections concurrently causes problems on large fleets.
poolidletimeout 900 (seconds) How long idle connections are kept. Kamal keeps a long idle timeout to avoid re-connection storms after idle periods like image builds or waiting for CI.
dns_retries 3 Retries after the initial DNS attempt. Some resolvers (mDNSResponder, systemd-resolved, Tailscale) drop lookups during bursts of concurrent SSH starts; Kamal retries automatically. Set to 0 to disable.

For more on when and how to adjust these, see [references/sshkit-options.md](references/sshkit-options.md).

Verify Your Configuration

After editing, confirm the result:

kamal config

The output includes a :ssh_options: section (user, port, log level) and the :sshkit: settings Kamal resolved from config/deploy.yml. Check these match what you intended before running a deploy.

If you use destinations, ssh: and sshkit: can be set per destination: the matching config/deploy.<destination>.yml is merged over the base config (e.g. kamal config -d staging).

Full Example

A non-root deploy through a bastion, with an explicit key and tuned concurrency:

ssh:
  user: app
  port: "2222"
  proxy: [email protected]
  keys: [ "~/.ssh/deploy.pem" ]
  keys_only: true
  forward_agent: false

sshkit:
  max_concurrent_starts: 10

Related Skills

  • setup: First-time Kamal setup — installing the gem, kamal init, and config/deploy.yml basics before you tune SSH.
  • servers: Defining the hosts and roles (servers:) that these SSH settings connect to.