Synopsis #
sshd
is the OpenSSH daemon that accepts incoming SSH connections and provides encrypted remote shell access and secure file transfer. On OpenBSD, sshd
is part of the base system and is enabled by default after installation. Typical uses include secure administration, file transfer via sftp(1)
and scp(1)
, remote command execution, and secure tunneling.
For service control, use rcctl(8). For configuration, edit sshd_config(5). The daemon benefits from pledge(2), unveil(2), and network control with pf(4).
Service Management #
Enable at boot and start immediately with rcctl(8):
# rcctl enable sshd
# rcctl start sshd
# rcctl status sshd
Host keys are generated during installation. If any are missing, create them with ssh-keygen(1):
# ssh-keygen -A
Configuration Basics #
The daemon reads /etc/ssh/sshd_config
. One directive is permitted per line, and lines beginning with #
are comments. Validate changes with sshd(8) and restart via rcctl(8).
# sshd -t
# rcctl restart sshd
A concise baseline configuration:
Port 22
AddressFamily any
ListenAddress 0.0.0.0
ListenAddress ::
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
# Access control
AllowUsers admin
# Session hygiene
ClientAliveInterval 300
ClientAliveCountMax 2
# Subsystem (enabled by default)
Subsystem sftp /usr/libexec/sftp-server
This configuration disables root login and password-based authentication, enables public key authentication, limits access to a specific account, and sets conservative keepalive parameters. Adjust ListenAddress
as required.
Client Configuration #
The OpenBSD base system includes the client programs ssh(1), sftp(1), and scp(1). This section covers key creation, key installation, and common client operations. Client-side configuration is read from ssh_config(5).
Generate an SSH Key Pair #
Create an Ed25519 key pair with an identifying comment. Use ssh-keygen(1). Protect the private key with a passphrase.
$ ssh-keygen -t ed25519 -C "[admin@example.com](mailto:admin@example.com)" -f \~/.ssh/id\_ed25519
For hardware-backed security keys (FIDO/U2F), generate an ed25519-sk
key:
$ ssh-keygen -t ed25519-sk -C "[admin@example.com](mailto:admin@example.com)" -f \~/.ssh/id\_ed25519\_sk
Ensure appropriate permissions on the .ssh
directory and files:
$ chmod 700 \~/.ssh
$ chmod 600 \~/.ssh/id\_\* \~/.ssh/id\_\*.pub
Load Keys into ssh-agent (optional) #
An agent can hold decrypted keys in memory. Start the agent and add the key with ssh-agent(1) and ssh-add(1).
$ eval "\$(ssh-agent -s)"
$ ssh-add \~/.ssh/id\_ed25519
Install the Public Key on the Server #
If the ssh-copy-id
helper is available on the client system, it can append the public key to the remote account’s ~/.ssh/authorized_keys
. The utility is not part of OpenBSD base; when installed, usage is:
$ ssh-copy-id [admin@host.example.com](mailto:admin@host.example.com)
When ssh-copy-id
is not available, append the public key over SSH using standard tools:
$ ssh [admin@host.example.com](mailto:admin@host.example.com) 'mkdir -p \~/.ssh && chmod 700 \~/.ssh && touch \~/.ssh/authorized\_keys && chmod 600 \~/.ssh/authorized\_keys'
$ cat \~/.ssh/id\_ed25519.pub | ssh [admin@host.example.com](mailto:admin@host.example.com) 'cat >> \~/.ssh/authorized\_keys'
To verify the first connection and record the server host key, connect once and confirm the fingerprint. For non-interactive retrieval, ssh-keyscan(1) can populate ~/.ssh/known_hosts
:
$ ssh-keyscan -t ed25519 host.example.com >> \~/.ssh/known\_hosts
Per-Host Client Configuration #
Create a host stanza in ~/.ssh/config
to define defaults for a target. See ssh_config(5).
Host prod
HostName host.example.com
User admin
Port 22
IdentityFile \~/.ssh/id\_ed25519
IdentitiesOnly yes
ForwardAgent no
ForwardX11 no
After saving the file, connect with a short alias:
$ ssh prod
Interactive Login and Remote Command Execution #
Establish an interactive session or execute a single remote command with ssh(1).
$ ssh [admin@host.example.com](mailto:admin@host.example.com)
$ ssh [admin@host.example.com](mailto:admin@host.example.com) 'uname -a'
Secure Copy (scp) #
Transfer files or directories. Use -r
for recursive copies.
$ scp ./report.txt [admin@host.example.com](mailto:admin@host.example.com):/home/admin/
$ scp -r ./site/ [admin@host.example.com](mailto:admin@host.example.com):/var/www/
$ scp [admin@host.example.com](mailto:admin@host.example.com):/var/log/daemon /tmp/daemon.log
SFTP File Transfers #
Open an interactive SFTP session or perform one-off transfers with sftp(1).
$ sftp [admin@host.example.com](mailto:admin@host.example.com)
sftp> pwd
sftp> lpwd
sftp> put ./archive.tar.gz /home/admin/
sftp> get /etc/daily /tmp/daily
sftp> mkdir /home/admin/uploads
sftp> ls -l /home/admin
sftp> exit
Non-interactive SFTP can transfer files directly:
$ sftp [admin@host.example.com](mailto:admin@host.example.com):/etc/daily /tmp/daily
$ sftp /var/log/messages [admin@host.example.com](mailto:admin@host.example.com):/home/admin/
Known Hosts and First-Use Validation #
On first connection, ssh(1) will prompt to trust the server host key and append it to ~/.ssh/known_hosts
. To pre-validate, compare the presented fingerprint with one generated on the server:
# On the server (run as root to read host keys):
# ssh-keygen -l -f /etc/ssh/ssh\_host\_ed25519\_key.pub
Common Options for Reliability and Performance #
Control connection reuse and timeouts in ~/.ssh/config
:
Host \*
ServerAliveInterval 60
ServerAliveCountMax 2
ControlMaster auto
ControlPersist 5m
ControlPath \~/.ssh/cm-%r@%h:%p
ControlMaster
enables multiplexing over a single TCP connection; subsequent sessions to the same host start faster and avoid repeated authentication.
Hardening #
Integrate Algorithm Policy with ssh-audit #
Inventory and assess offered algorithms with ssh-audit
. See the companion chapter: /ssh-audit. Based on audit findings, restrict key exchange (KEX), host-key, and MAC algorithms in sshd_config(5).
A conservative, broadly compatible policy:
# Key exchange
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,\
diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,\
diffie-hellman-group-exchange-sha256
# MACs (encrypt-then-MAC variants)
MACs umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,\
hmac-sha2-512-etm@openssh.com
# Host key algorithms (server authentication)
HostKeyAlgorithms ssh-ed25519,rsa-sha2-256,rsa-sha2-512
When reducing HostKeyAlgorithms
, ensure HostKey
file directives reference only retained types (for example, omit ssh_host_ecdsa_key
if ECDSA is disabled). Validate and reload:
# sshd -t
# rcctl restart sshd
To curate Diffie–Hellman group-exchange parameters, filter /etc/ssh/moduli
to entries of at least 3071 bits; see moduli(5).
# awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe
# mv -f /etc/ssh/moduli.safe /etc/ssh/moduli
# rcctl restart sshd
Re-run ssh-audit
after each change and review for unintended regressions.
Access Control #
Restrict exposure and narrow the authenticated population.
# Bind to explicit addresses and non-standard port if required
Port 22
ListenAddress 192.0.2.10
# ListenAddress 2001:db8::10
# Permit only specific users or groups
AllowUsers admin opsuser
# or:
# AllowGroups wheel ops
With pf(4), limit ingress to trusted sources. See the PF chapters and the pfctl cheat sheet at /pf/cheat_sheet/.
# Example PF fragment (context-dependent)
block in on egress proto tcp to port ssh
pass in on egress proto tcp from 198.51.100.0/24 to port ssh
Reload with pfctl(8):
# pfctl -f /etc/pf.conf
Authentication and Multi-Factor Options #
OpenSSH supports several approaches to multi-factor authentication without external PAM modules.
Public key + password (two independent factors). Require both a private key and a password using sshd_config(5)
AuthenticationMethods
.PubkeyAuthentication yes PasswordAuthentication yes AuthenticationMethods publickey,password
This setting denies access unless both factors succeed.
Security keys (FIDO/U2F). Security-key-backed keys (for example,
sk-ssh-ed25519@openssh.com
) provide possession-plus-touch verification. Generate on the client with ssh-keygen(1):$ ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk
Ensure that server policy allows the corresponding public key algorithm (do not exclude
sk-ssh-ed25519@openssh.com
ifPubkeyAcceptedAlgorithms
is restricted) and that public key authentication remains enabled.Keyboard-interactive second factors via BSD Authentication. OpenBSD uses bsd_auth(3) rather than PAM. Additional BSD Auth backends can supply one-time codes (for example, TOTP) via
keyboard-interactive
. After installing and configuring an appropriate backend, require a second factor with:KbdInteractiveAuthentication yes AuthenticationMethods publickey,keyboard-interactive
Backend selection and provisioning are backend-specific and outside the scope of this chapter.
Additional hardening measures:
# Reduce brute-force surface
MaxAuthTries 3
LoginGraceTime 30
MaxStartups 10:30:100
# Disable features not required
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
GatewayPorts no
PrintMotd no
UseDNS no
Subsystem Isolation and Chrooted SFTP #
Constrain SFTP-only accounts with a chroot and the internal SFTP subsystem:
Match User sftpjailed
ChrootDirectory /home/sftpjailed
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
The chroot directory must be owned by root
and must not be writable by the target account; see details in sshd_config(5).
Monitoring and Troubleshooting #
Check service status and listen sockets:
# rcctl check sshd
# sockstat -4 -6 | grep sshd
Inspect authentication logs (facility auth
):
# tail -f /var/log/authlog
Common issues include syntax errors (sshd -t
), incorrect permissions on ~/.ssh
or authorized_keys
, missing public keys, or firewall policy blocking the port.
Fix user key permissions:
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys
$ chown "$USER":"$USER" ~/.ssh ~/.ssh/authorized_keys