To install SSH on Rocky Linux, install openssh-server, enable the sshd service, and make sure firewalld allows the access path you plan to use. Rocky names the service sshd, not ssh.service, which matters when enabling, troubleshooting, or checking logs.
Rocky Linux 10, 9, and 8 all use the sshd systemd service, firewalld for the default host firewall, and SELinux enforcing mode by default. The package names stay consistent across releases, but the SSH configuration layout differs slightly between Rocky 8 and newer releases.
This workflow targets normal Rocky Linux hosts and virtual machines. Container images usually do not run systemd, firewalld, or a full SSH server by default; manage them with Podman or Docker exec sessions unless you intentionally build and publish an SSH-enabled container.
Install SSH Server on Rocky Linux
Refresh package metadata and apply available updates before installing or changing a network login service:
sudo dnf upgrade --refresh
These commands use
sudofor tasks that need root privileges. If your account cannot usesudo, switch to a root shell or ask an administrator to grant the required access before continuing.
Check whether the SSH server package is already present:
rpm -q openssh-server
A Rocky Linux 10 system with the package installed returns a versioned package name similar to this:
openssh-server-9.9p1-14.el10_1.rocky.0.1.x86_64
If RPM reports that the package is not installed, install the server and client packages together:
sudo dnf install openssh-server openssh-clients
Verify the server, client, and shared OpenSSH packages:
rpm -q openssh-server openssh-clients openssh
openssh-server-9.9p1-14.el10_1.rocky.0.1.x86_64 openssh-clients-9.9p1-14.el10_1.rocky.0.1.x86_64 openssh-9.9p1-14.el10_1.rocky.0.1.x86_64
The openssh-server package provides /usr/sbin/sshd, the daemon that accepts incoming SSH connections. The openssh-clients package provides client-side tools such as ssh and ssh-copy-id. The ssh-keygen command comes from the base openssh package, which is pulled in by the server package.
Enable and Start the SSH Service
Rocky Linux names the service sshd, not ssh. Enable it at boot and start it now:
sudo systemctl enable --now sshd
Confirm the daemon is active:
systemctl is-active sshd
active
Confirm it is enabled for future boots:
systemctl is-enabled sshd
enabled
Check that SSH is listening on the default TCP port:
ss -H -ltn 'sport = :22'
Relevant output includes listener rows for IPv4, IPv6, or both:
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 128 [::]:22 [::]:*
Verify the installed OpenSSH client version:
ssh -V
Rocky Linux 10 currently reports:
OpenSSH_9.9p1, OpenSSL 3.5.1 1 Jul 2025
Rocky Linux 9 uses the OpenSSH 8.7p1 branch, while Rocky Linux 8 uses OpenSSH 8.0p1. Those older branches receive security fixes through Rocky Linux maintenance updates instead of tracking the newest upstream OpenSSH release number.
Connect to Remote Servers with SSH
The same OpenSSH client tools can connect from this Rocky Linux system to another server. For a deeper command reference, see the LinuxCapable guide to the ssh command in Linux.
Connect with Password Authentication
Use the standard user@host form, replacing the placeholders with your remote account and server address:
ssh username@server.example.com
A documentation-safe IP example looks like this:
ssh admin@203.0.113.10
On the first connection, SSH shows the remote host fingerprint. Verify that fingerprint through your provider, console, or administrator before typing yes; accepting the wrong fingerprint can trust an impostor host.
Connect on a Custom Port
If the remote server listens on a non-default SSH port, pass the port with -p:
ssh -p 2222 username@server.example.com
Connect with a Private Key
When your private key uses the default path, SSH usually finds it automatically. For a non-default key, point SSH to the file explicitly:
ssh -i ~/.ssh/id_ed25519 username@server.example.com
Configure the SSH Server
OpenSSH reads server settings from /etc/ssh/sshd_config. Rocky Linux 9 and 10 include drop-in files from /etc/ssh/sshd_config.d/ near the top of that file, while Rocky Linux 8 keeps the stock server settings in the main file.
Back up the main server configuration first:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
Check whether your system uses the drop-in include:
sudo grep -Ei '^[[:space:]]*Include[[:space:]]+' /etc/ssh/sshd_config
The grep command filters the file for active Include directives and ignores commented examples.
Rocky Linux 9 and 10 return this include line:
Include /etc/ssh/sshd_config.d/*.conf
On Rocky Linux 9 and 10, create your local overrides in a lower-numbered drop-in such as /etc/ssh/sshd_config.d/01-local-hardening.conf. OpenSSH uses the first value it reads for many directives, so a lower-numbered file can override Red Hat family defaults in 50-redhat.conf.
sudo nano /etc/ssh/sshd_config.d/01-local-hardening.conf
On Rocky Linux 8, add the same active directives directly to /etc/ssh/sshd_config because the stock file does not include the drop-in directory.
Apply Basic SSH Hardening
Use this baseline to disable direct root login, keep public key authentication available, time out dead sessions, and turn off GSSAPI when you do not use Kerberos:
PermitRootLogin no
PubkeyAuthentication yes
ClientAliveInterval 300
ClientAliveCountMax 2
GSSAPIAuthentication no
Keep your current SSH session open while changing authentication settings. Test a second login before disconnecting so a typo or missing key does not lock you out.
Disable Password Authentication After Keys Work
Leave passwords enabled until every administrator has a tested key login. After key-based login works from a second terminal, add this directive to the same SSH server configuration location:
PasswordAuthentication no
On Rocky Linux 9 and 10, this setting belongs in the lower-numbered drop-in if a later Red Hat family drop-in sets a different value. On Rocky Linux 8, keep it in the main sshd_config file.
Restrict SSH to Specific Users or Groups
Use AllowUsers when only named accounts should log in:
AllowUsers admin deploy
Use AllowGroups when membership in one group should control SSH access:
AllowGroups sshusers
Do not add both directives unless you want users to satisfy both checks. Replace the sample names with real local or directory-backed accounts and groups.
Validate and Apply SSH Configuration
Validate the server configuration before applying it:
sudo sshd -t
A valid configuration returns to the prompt without output. If the command prints an error, fix that file and line before applying the change.
Reloading is enough for normal authentication and policy changes, and is less disruptive than a full restart. Use a restart later when you change the listener port:
sudo systemctl reload sshd
Confirm the daemon stayed active:
systemctl is-active sshd
active
Check the effective settings when you need proof that the drop-in or main-file edit won precedence:
sudo sshd -T | grep -Ei '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|gssapiauthentication)[[:space:]]'
The output uses lowercase setting names. Confirm the values match the directives you set, especially permitrootlogin, passwordauthentication, and gssapiauthentication.
Set Up Public Key Authentication
Generate and copy SSH keys from the client machine you use to connect to the Rocky Linux server. That client can be your workstation, another Linux host, or the Rocky Linux system itself if it is making outbound connections.
Generate an SSH Key Pair
Ed25519 keys are compact and strong for modern OpenSSH clients:
ssh-keygen -t ed25519 -C "your_email@example.com"
The interactive prompt starts by asking where to save the key and whether to protect it with a passphrase:
Generating public/private ed25519 key pair. Enter file in which to save the key (/home/user/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_ed25519 Your public key has been saved in /home/user/.ssh/id_ed25519.pub
OpenSSH also prints a unique fingerprint and randomart for the new key. Use a passphrase for interactive administrator keys. Leave it empty only for automation keys that are protected another way, such as a locked-down service account and narrow command permissions.
If an older target system cannot accept Ed25519 keys, generate a 4096-bit RSA key instead:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Copy the Public Key to Rocky Linux
Copy your public key to the Rocky Linux account that should accept SSH logins:
ssh-copy-id username@server.example.com
The first copy still asks for the account password because it uses that login once to append your public key to ~/.ssh/authorized_keys. Test the key login before disabling password authentication:
ssh username@server.example.com
Configure Firewalld for SSH Access
Rocky Linux uses firewalld by default. Before changing firewall rules on a remote server, keep the current SSH session open and make sure you have console access, a provider rescue shell, or another recovery path.
Verify the Default SSH Firewall Service
Check whether the active zone allows the built-in SSH service:
sudo firewall-cmd --query-service=ssh
A system that already allows SSH returns:
yes
If the command returns no, add the service permanently and reload firewalld:
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --query-service=ssh
success success yes
Use a Custom SSH Port
Changing the SSH port is optional. It reduces background noise from automated scans, but it does not replace key authentication, firewall scoping, or fail2ban-style rate limiting.
Install the SELinux management tool if semanage is not available:
sudo dnf install policycoreutils-python-utils
Add the new TCP port to the SELinux SSH port type before restarting sshd:
sudo semanage port -a -t ssh_port_t -p tcp 2222
If SELinux says the port is already defined for another service, choose a different port unless you intentionally want to reassign it to SSH. Use -m only when that reassignment is deliberate:
sudo semanage port -m -t ssh_port_t -p tcp 2222
Verify the SELinux port mapping:
sudo semanage port -l | grep '^ssh_port_t'
ssh_port_t tcp 2222, 22
Open the new port in firewalld while keeping the default SSH service in place for your current session:
sudo firewall-cmd --add-port=2222/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --query-port=2222/tcp
success success yes
Add the new port to your SSH server configuration, using the Rocky 9/10 drop-in or the Rocky 8 main file described earlier. Keep port 22 during the transition so you have the original login path while testing the new one:
Port 22
Port 2222
Validate the configuration, then restart the daemon so the listener set changes. A normal reload is enough for many authentication settings, but Rocky Linux 9 and 10 need a restart before a newly added port appears as a listener:
sudo sshd -t
sudo systemctl restart sshd
Test the new port from a second terminal before changing the firewall rule for port 22:
ssh -p 2222 username@server.example.com
After the custom-port login works, remove Port 22 from your SSH server configuration if you no longer want the daemon listening there. Validate and restart sshd, then confirm the custom port still listens and port 22 no longer returns a listener row:
sudo sshd -t
sudo systemctl restart sshd
ss -H -ltn 'sport = :2222'
ss -H -ltn 'sport = :22'
When the custom-port login still works, remove the broad default SSH service from firewalld:
sudo firewall-cmd --remove-service=ssh --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --query-service=ssh
success success no
If you also use an upstream cloud firewall, security group, router, or provider control panel, update that layer before depending on the custom port.
Restrict SSH to a Trusted Source
For admin-only servers with a static management IP or CIDR range, limit SSH to that trusted source. A firewalld rich accept rule is additive; it does not restrict SSH while the same zone still exposes the broad ssh service or a broad custom port.
Replace the documentation address with your real management IP or CIDR range, then run the relevant rule block in the same terminal session:
TRUSTED_SOURCE="203.0.113.10"
Add and verify a firewalld rich rule for that source:
sudo firewall-cmd --permanent --add-rich-rule="rule family=\"ipv4\" source address=\"$TRUSTED_SOURCE\" service name=\"ssh\" accept"
sudo firewall-cmd --reload
sudo firewall-cmd --query-rich-rule="rule family=\"ipv4\" source address=\"$TRUSTED_SOURCE\" service name=\"ssh\" accept"
success success yes
For a custom SSH port, use a rich rule with the port instead of the built-in ssh service:
sudo firewall-cmd --permanent --add-rich-rule="rule family=\"ipv4\" source address=\"$TRUSTED_SOURCE\" port port=\"2222\" protocol=\"tcp\" accept"
sudo firewall-cmd --reload
sudo firewall-cmd --query-rich-rule="rule family=\"ipv4\" source address=\"$TRUSTED_SOURCE\" port port=\"2222\" protocol=\"tcp\" accept"
success success yes
Test from the trusted source before removing broad firewall access. For the default port, remove the general SSH service rule after the source-limited login works:
sudo firewall-cmd --remove-service=ssh --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --query-service=ssh
success success no
If you previously opened a custom port broadly with --add-port=2222/tcp, remove that broad port rule after the source-limited custom-port login works. The rich rule remains in place for the trusted source:
sudo firewall-cmd --remove-port=2222/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --query-port=2222/tcp
success success no
Audit the final zone state. The services and ports output should not list broad SSH access unless you intentionally kept it open, while the rich rules output should show the trusted-source rule:
sudo firewall-cmd --list-services
sudo firewall-cmd --list-ports
sudo firewall-cmd --list-rich-rules
Troubleshoot SSH on Rocky Linux
ssh.service Could Not Be Found
Rocky Linux uses sshd.service. If systemctl status ssh.service fails, check the correct unit instead:
systemctl status sshd
Use the same service name for enable, start, reload, restart, and log checks.
Connection Refused
A refused connection usually means sshd is stopped or not listening on the port you tried. Check the service first:
systemctl is-active sshd
If the service is not active, inspect recent logs:
sudo journalctl -u sshd --since "10 minutes ago" --no-pager
Validate the configuration before restarting or reloading again:
sudo sshd -t
Permission Denied with Public Keys
Public key failures usually come from a missing key, loose file permissions, or an SELinux label mismatch on the user’s SSH directory. Check the target user’s files:
- Confirm the public key exists in
~/.ssh/authorized_keysfor the account you are logging into. - Set SSH directory permissions with chmod on Linux:
chmod 700 ~/.sshandchmod 600 ~/.ssh/authorized_keys. - Restore SELinux labels for the user’s SSH files with
restorecon -Rv ~/.ssh. - Run
ssh -vvv username@server.example.comfrom the client when you need to see which key the client offered.
ssh-keygen Command Not Found
If ssh-keygen is missing on a minimal system, install the shared OpenSSH package. Add openssh-clients too when you also need ssh and ssh-copy-id:
sudo dnf install openssh openssh-clients
On Rocky Linux 10, 9, and 8, ssh-keygen is provided by openssh, while ssh and ssh-copy-id are provided by openssh-clients.
SELinux Blocks a Custom SSH Port
If sshd fails after a port change, confirm the port is mapped to ssh_port_t:
sudo semanage port -l | grep '^ssh_port_t'
Recent SELinux denials can confirm the cause:
sudo ausearch -m AVC,USER_AVC -ts recent | grep sshd
Add or modify the custom port with semanage port, then rerun sudo sshd -t and restart sshd.
Firewall Blocks SSH Connections
Connection timeouts point more often to firewall or network filtering than to a stopped daemon. Check the service rule for port 22:
sudo firewall-cmd --query-service=ssh
For a custom port, check the exact TCP port:
sudo firewall-cmd --query-port=2222/tcp
A yes result means firewalld allows that local port. If connections still time out, check any cloud security group, router, VPN, container host, or upstream network firewall between the client and the Rocky Linux server.
Update SSH Packages on Rocky Linux
OpenSSH security fixes arrive through Rocky Linux package updates. Update the server and client packages with DNF:
sudo dnf upgrade openssh-server openssh-clients
Restart the daemon after an update when the transaction changes the server package. Keep the current SSH session open and verify a second login before disconnecting:
sudo systemctl restart sshd
Confirm SSH stayed active after the restart:
systemctl is-active sshd
active
Remove SSH Server from Rocky Linux
Do not remove or stop
openssh-serverfrom the same SSH session you depend on for access. Use a local console, provider console, or another confirmed access path first.
Stop and disable the server when you are ready to remove inbound SSH access:
sudo systemctl disable --now sshd
Remove the server package:
sudo dnf remove openssh-server
This leaves the OpenSSH client tools in place if openssh-clients is installed. Remove the client package only if the machine no longer needs outbound SSH commands:
sudo dnf remove openssh-clients
Verify the server package is gone:
rpm -q openssh-server
package openssh-server is not installed
If you edited /etc/ssh/sshd_config directly on Rocky Linux 8, restore the backup before removing cleanup files:
sudo cp /etc/ssh/sshd_config.backup /etc/ssh/sshd_config
Remove only the extra configuration files created during this setup when you want a cleaner reinstall later:
sudo rm -f /etc/ssh/sshd_config.backup /etc/ssh/sshd_config.d/01-local-hardening.conf
If you added a custom SSH port to SELinux or firewalld, remove those local access rules too. Skip any command for a rule you did not create:
sudo semanage port -d -t ssh_port_t -p tcp 2222
sudo firewall-cmd --remove-port=2222/tcp --permanent
sudo firewall-cmd --reload
For a trusted-source rule on the default SSH service, replace the documentation address with the source you allowed, then remove that rule:
TRUSTED_SOURCE="203.0.113.10"
sudo firewall-cmd --permanent --remove-rich-rule="rule family=\"ipv4\" source address=\"$TRUSTED_SOURCE\" service name=\"ssh\" accept"
sudo firewall-cmd --reload
For a trusted-source rule on a custom SSH port, remove the matching port-based rule instead:
TRUSTED_SOURCE="203.0.113.10"
sudo firewall-cmd --permanent --remove-rich-rule="rule family=\"ipv4\" source address=\"$TRUSTED_SOURCE\" port port=\"2222\" protocol=\"tcp\" accept"
sudo firewall-cmd --reload
Deleting host keys is a separate, destructive cleanup step. Clients that previously trusted this server will see a host-key mismatch if you reinstall SSH and new keys are generated.
sudo rm -f /etc/ssh/ssh_host_*
Conclusion
OpenSSH is running on Rocky Linux with the sshd service enabled, firewalld allowing the right access path, and SELinux ready for a custom port when needed. For brute-force protection, pair this setup with Fail2ban on Rocky Linux, then keep the system patched with regular DNF upgrades.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>