SSH Access
AerolVM runs an SSH gateway on port 2220 (configurable via SB_SSH_LISTEN_ADDR). Each sandbox is provisioned with a unique Ed25519 key pair on creation. The private key is returned only in the create response and is not stored by the server.
Key Provisioning
Section titled “Key Provisioning”The SSH private key is available immediately when the sandbox is created. Save it - it cannot be retrieved later.
const sandbox = await client.create({ image: 'ubuntu:22.04' })
const privateKey = sandbox.sshPrivateKey // save this immediatelyconst publicKey = sandbox.sshPublicKey // available later via get()
console.log(privateKey)sandbox = client.create({'image': 'ubuntu:22.04'})
private_key = sandbox.sshPrivateKey # save - only returned on createpublic_key = sandbox.sshPublicKeysandbox, err := client.Create(ctx, sdktypes.CreateSandboxOptions{ Image: "ubuntu:22.04",})if err != nil { log.Fatal(err) }
privateKey := sandbox.SSHPrivateKey // save - only returned by Create()publicKey := sandbox.SSHPublicKeylet sandbox = client.create(CreateOptions { image: "ubuntu:22.04".to_string(), ..Default::default()})?;
let private_key = &sandbox.ssh_private_key; // save - only returned by create()let public_key = &sandbox.data.ssh_public_key;Sandbox sandbox = client.create(new CreateOptions().setImage("ubuntu:22.04"));
String privateKey = sandbox.sshPrivateKey; // save - only returned by create()String publicKey = sandbox.sshPublicKey;Connecting
Section titled “Connecting”The SSH username encodes the sandbox ID and an optional session name:
| Username format | Behavior |
|---|---|
<sandbox-id> | Attach to the default session |
<sandbox-id>+<name> | Attach to the named session |
# Save the private key from the create responseecho "$SSH_PRIVATE_KEY" > ~/.ssh/sandbox_keychmod 600 ~/.ssh/sandbox_key
# Connect to the default sessionssh -i ~/.ssh/sandbox_key -p 2220 sandbox_abc123@<host>
# Connect to a named sessionssh -i ~/.ssh/sandbox_key -p 2220 sandbox_abc123+myshell@<host>Cluster mode
Section titled “Cluster mode”In a multi-node cluster a sandbox is owned by exactly one node, but the leased SSH domain load-balances connections across every ingress node. You connect the same way regardless of which node owns your sandbox:
ssh -i ~/.ssh/sandbox_key -p 2220 sandbox_abc123@<leased-domain>If your connection lands on a node that does not own the sandbox, the gateway authenticates you against the owner's authoritative key and bridges the session to the owner over the cluster's internal mTLS channel. Only your sandbox's public key and the session bytes cross between nodes; the per-sandbox toolbox token never leaves the owner. Key revocation is honored immediately — the authorized key is re-fetched from the owner on every connection, not cached.
Stable host identity
Section titled “Stable host identity”By default each node generates its own SSH host key, so as the leased domain rotates you across nodes your client may warn that the host key changed. To give clients one stable identity, distribute the same host key to every ingress-bearing node:
- Terraform: set the
ssh_host_key_pemvariable (sensitive) to a shared OpenSSH ed25519 private key; bootstrap writes it toSB_SSH_HOST_KEY_PATHon every node. - Ansible: set
ssh.host_keyinconfig/secrets.yml(or pointsandboxd_ssh_host_key_srcat a control-node file);configure-ops.ymlinstalls it.
Leave both unset to keep per-node keys.
Configuration
Section titled “Configuration”| Environment Variable | Default | Description |
|---|---|---|
SB_ENABLE_SSH_GATEWAY | true | Enable or disable the SSH gateway. |
SB_SSH_LISTEN_ADDR | 0.0.0.0:2220 | Address and port for the SSH server. |
SB_SSH_HOST_KEY_PATH | /var/lib/aerolvm/ssh_host_ed25519_key | Host key path. Generated on first start if absent. In cluster mode, point every node at a shared key for a stable host identity. |
Each sandbox accepts exactly one authorized key. There is no shared host-level access.