Forkr runs a dedicated SSH gateway (the forkr-ssh-gateway crate, deployed via k8s/forkr-ssh-gateway.yaml) that is separate from forkr-api. It lets you ssh, sftp, and scp into a box without running sshd inside any box pod, and SSH sessions survive forkr-api restarts. For day-to-day client usage, see SSH via the gateway and the 4kr ssh command. This page covers how the gateway works and how operators configure it.

Addressing

The SSH username selects the target box as <project>--<box>, and the gateway listens on port 2222:
ssh -p 2222 myproject--dev@ssh.<forkr_domain>
sftp -P 2222 myproject--dev@ssh.<forkr_domain>
To avoid repeating the port, add an SSH config alias:
Host forkr-ssh
  HostName ssh.<forkr_domain>
  Port 2222
ssh myproject--dev@forkr-ssh
The 4kr ssh <box> command builds this address for you from the active profile.

Authentication

The gateway accepts public keys from two sources, both configured on the gateway Deployment:
  • FORKR_SSH_GITHUB_USERS: a comma-separated list of GitHub usernames. Their public keys are fetched from GitHub and refreshed periodically (FORKR_SSH_KEYS_REFRESH_SECS, default 300s).
  • FORKR_SSH_AUTHORIZED_KEYS: optional static OpenSSH authorized_keys content, loaded from the Kubernetes secret provisioned by Ansible.

Host key

The gateway loads a stable host key from /var/lib/forks/ssh/host-ed25519 (overridable via FORKR_SSH_HOST_KEY_PATH), mounted from a Kubernetes secret. Persisting the key avoids host-key-changed warnings across redeploys. Generate it once and store it in SOPS, then retrieve and apply it as a secret:
# generate (one-time)
ssh-keygen -t ed25519 -f certs/ssh/host-ed25519 -N ''

# save the key into the SOPS deploy secret
./scripts/save-ssh-hostkey.sh certs/ssh/host-ed25519

# retrieve from SOPS and create/update the k8s secret (namespace forks-system)
./scripts/get-ssh-hostkey.sh --apply
If the k3s API (:6443) is not reachable locally, apply by SSHing into the VM and running kubectl there:
./scripts/get-ssh-hostkey.sh --apply-via-vm
The VM host is resolved from FORKR_DEPLOY_SSH_HOST / FORKR_VM_SSH_HOST or the profile’s deploy_ssh_host / ssh_host.

How it works

The gateway terminates the SSH connection, resolves the target pod by its forks.dev/project and fork labels, and prefers entering the box via CRI/containerd: it uses nsenter into the container’s mount and network namespaces and runs the requested shell, SFTP, or exec command under chroot /volumes. If CRI initialization or session start fails, it falls back to Kubernetes exec (kubectl exec). PTY sessions negotiate terminal size and force TERM=xterm-256color.

Base requirements

SFTP requires an sftp-server binary in the base image (the openssh-sftp-server package), which the box base installs. The gateway looks for it at /usr/lib/openssh/sftp-server, /usr/libexec/sftp-server, or on PATH.

Limitations

  • No port forwarding: ssh -L / ssh -R and direct-tcpip channels are not supported.