Secure SSH Configuration 2026
As of writing this, I am in the process of setting up my new V-Server. This also means configuring a lot of things, including SSH. I tried to create a secure configuration and it seems like most guides are outdated as they do not even consider post-quantum cryptography yet. In case I got anything wrong please let me know on GitHub or here (once I implement comments)!
For all settings that are not listed below, the default should be fine in my oppinion. E.g. X11Forwarding is no by default and protocol 2 doesn’t exist anymore since SSHv1 was disabled.
Additionally, I have not yet used hardware devices, such as YubiKeys. Those would improve the security further and there are other guides out there. I might write something about those once I tried them myself.
Another nice addition to this configuration is setting up Fail2Ban and taking other general security considerations into account as there are many guides out there on how to further harden a server.
Settings and Reasoning
AllowAgentForwarding no- If the server is compromised, forwarded agents could be abused to authenticate on other hosts.AllowStreamLocalForwarding no- Prefent local socket pivoting attacks.AllowTcpForwarding no- Prevents tunneling traffic and makes lateral movement harder.AllowUsers [REDACTED]- Instead of usingAllowGroups, I only allow individual users access since it is basically only my own user account.AuthenticationMethods publickey- Only allow authentication using strong asymetric crypto, when using MFA a setting such asAuthenticationMethods publickey,keyboard-interactive:pamseems suitable.CASignatureAlgorithms- The default algorithms1 should be fine for most use cases. However, it might be a good choice to remove everything related toRSAandSHA256. And to also add a post-quantum algorithm e.g.sntrup761x25519-sha512@openssh.cominstead. I don’t want to argue if NIST curves should be trusted, make your own choice on that.Ciphers- Default2 should be fine, NEVER use anything related to3desorcbcmode! Optionally, throw outaes128andaes192from the defaults.ClientAliveCountMax 2- Allow 2 keepalive failures before disconnect to prevent stale, abondoned and hijacked connections.ClientAliveInterval 300- Send keepalive message every 5 minutes.Compression no- Prevent compression (CRIME-style side channel) attacks.DisableForwarding yes- Disable all forwarding features.HostKey-Ed25519is probably a reasonable choice (HostKey /etc/ssh/ssh_host_ed25519_key) after setting it up correctly.HostKeyAgent none- I don’t need to useSSH_AUTH_SOCKsince I don’t have hardware security modules, remote key agents, key management systems, or similar in place. To me it is not clear what the default is according to the man page.HostKeyAlgorithms- The Default3 list is quite long. If compatibility allows, keepssh-ed25519and maybersa-sha2-512,rsa-sha2-256. Even though the elliptic curve discrete logarithm problem and the RSA factoring problem are both vulnerable to Shor´s algorithm, host key compromise affects current authentication and not past session confidentiality. Thus post-quantum security is more important in regard to the key exchange and apparantly not available yet (ssh -Q HostKeyAlgorithms).IgnoreUserKnownHosts- I use the default (no) for convenience but e.g. in enterprise settings it might be a good choice to prevent users from overriding centralized host trust usingyes.KbdInteractiveAuthentication- Default as keyfiles are used in my setup, only useyeswhen needed for 2FA e.g. withAuthenticationMethods publickey,keyboard-interactive:pam.KexAlgorithms- The default4 list already includes post-quantum algorithms. For additional security (and if possible) throw out everythingdiffie-hellmanrelated. Even better; only keepsntrup761x25519-sha512@openssh.comand maaayyyybeeecurve25519-sha256.ListenAddress- My server only has one IP and I want SSH to be publicly reachable, so no changes needed. However, depending on the setup it might be wise to restrict the network interface that SSH listens on.LoginGraceTime 20- Limit login process since keyfiles are used anyway. Reduce brute-force, annoy scanners.LogLevel VERBOSE- Log key fingerprints and auth details for forensics.MACs- Once again many defaults5. Keephmac-sha2-512-etm@openssh.comand if necessaryhmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com. Everything else depends on necessity.Match- Depending on the setup it might be interesting to use conditional configuration blocks. I don’t use them though.MaxAuthTries 2- Using a manager / saved connections there should be no reason to fail a login. Reduce brute-force, annoy scanners.MaxSessions 2- Limit e.g. resource exhaustion attacks.MaxStartups 3:30:10- Controls how many unauthenticated SSH connections are allowed simultaneosly. Format isstart:rate:full. Afterstart(3) connections, SSH begins dropping now ones with a probability ofrate / 100(30%) and increases the value linearly until all connection attempts are refused whenfullis reached. Helps mitigate attacks such as brute-force, connection flooding, resource exhaustion, and similar.ModuliFile- The default (/etc/ssh/moduli) is fine but make sure to have 4096-bit primes available when using. More modern algorithms (e.g.curve25519-sha256) that don’t use Diffie-Hellman group exchange don’t need this anymore anyway.PasswordAuthentication no- Only allow keyfiles.PermitRootLogin no- No login withrootuser.PermitUserRC no- There are risks (e.g. backdoors, persistence, data exfiltration, …) when executing scripts from~/.ssh/rcon login without much benefit.PerSourceMaxStartups 2- Further limits brite-force attacks by only allowing 2 unauthenticated SSH connections per source IP.Port 22- Changing the default port e.g. to2222does not improve security but there might be less noise from scanners.PubkeyAcceptedAlgorithms- Once again many defaults6. Once again good choices aressh-ed25519,sk-ssh-ed25519@openssh.comwith whatever is needed for compatibility e.g.rsa-sha2-512,rsa-sha2-256.PubkeyAuthOptions- Can be used to add further restrictions to public key authentication e.g. requiring physical touch on a FIDO key. Currently not in use by me though it would be better. If a FIDO key is available, look into those settings further!RekeyLimit 512M 1h- Default isnonewhich means that rekeying is performed after the cipher’s default amount of data has been sent or received and no time based rekeying is done. Default is somewhere between 1G and 4G of data but it should be fine to add a time limit and to set a reasonable limit for all ciphers.RequiredRSASize 3072- Minimum RSA key size allowed,4096should be better even though3072should work for now. If possible without much effort and when not being lazy use4096.RevokedKeys /etc/ssh/revoked_keys- To revoke keys quickly instead of removing everyauthorized_keysentry usessh-keygen -k -f revoked_keys compromised_key.pub.StreamLocalBindUnlink yes- Prevent denial-of-service e.g. when someone didtouch /tmp/docker.sockand one wants tossh -L /tmp/docker.sock:/var/run/docker.sock server. Probably very arguable what setting is safer under which considerations.Subsystem sftp internal-sftp -f AUTHPRIV -l INFO- Restricts the logs and documents e.g. file uploads, downloads, directory listings, and so on.SyslogFacility AUTHPRIV- Restricts the authentication logs.TCPKeepAlive no- Can be spoofed. UseClientAliveIntervalandClientAliveCountMaxinstead.TrustedUserCAKeys- Only needed when using a CA that can sign SSH user certificates (e.g./etc/ssh/ca.pub). Allows some neat features as for example, short-lived certificates, and scalable identity management. Not needed for my small setup but good to know about this feature.UnusedConnectionTimeout 5m- Disconnect after 5 minutes when connection has been successfull but there are no open channels. Once again helps with buggy SSH clients and connection flooding related issues.UsePAM yes- Enables the pluggable authentication modules which allows for settings such as MFA or password policies. Make sure to disable eitherPasswordAuthentication(as suggested above) orKbdInteractiveAuthenticationas it serves as an equivalent role to password authentication.
Final Configuration
AllowAgentForwarding no
AllowStreamLocalForwarding no
AllowTcpForwarding no
AllowUsers [REDACTED]
AuthenticationMethods publickey
CASignatureAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
ClientAliveCountMax 2
ClientAliveInterval 300
Compression no
DisableForwarding yes
HostKey /etc/ssh/ssh_host_ed25519_key
HostKeyAgent none
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256
LoginGraceTime 20
LogLevel VERBOSE
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
MaxAuthTries 2
MaxSessions 2
MaxStartups 3:30:10
PasswordAuthentication no
PermitRootLogin no
PermitUserRC no
PerSourceMaxStartups 2
Port 22
PubkeyAcceptedAlgorithms ssh-ed25519,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256
RekeyLimit 512M 1h
RequiredRSASize 4096
StreamLocalBindUnlink yes
Subsystem sftp internal-sftp -f AUTHPRIV -l INFO
SyslogFacility AUTHPRIV
TCPKeepAlive no
UnusedConnectionTimeout 5m
UsePAM yes
The configuration can also be found on GitHub.
-
ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,rsa-sha2-512,rsa-sha2-256↩ -
chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com↩ -
ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,rsa-sha2-512,rsa-sha2-256↩ -
sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256↩ -
umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1↩ -
ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,rsa-sha2-512,rsa-sha2-256↩