How to Install SSH on Rocky Linux 10, 9, and 8

Last updated Friday, May 15, 2026 4:31 pm Joshua James 10 min read

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 sudo for tasks that need root privileges. If your account cannot use sudo, 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_keys for the account you are logging into.
  • Set SSH directory permissions with chmod on Linux: chmod 700 ~/.ssh and chmod 600 ~/.ssh/authorized_keys.
  • Restore SELinux labels for the user’s SSH files with restorecon -Rv ~/.ssh.
  • Run ssh -vvv username@server.example.com from 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-server from 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.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Let us know you are human: