Skip to content
Search RunEntLinux

Searches general documentation on RunEntLinux. Each distribution has its own documentation search.

    Browse this documentation

    SSH is the primary method for remote Linux server management and also the most commonly targeted entry point for attackers. This article systematically covers SSH security hardening measures, from key-based authentication to Fail2Ban brute-force protection, helping you build a secure remote access environment.

    Use Key-Based Authentication Instead of Passwords

    Section titled “Use Key-Based Authentication Instead of Passwords”

    Key-based authentication is more secure and convenient than password authentication. Once configured, you should completely disable password login.

    Terminal window
    ssh-keygen -t ed25519 -C "your_email@example.com"

    Follow the prompts. It is recommended to set a passphrase for an additional layer of security:

    Generating public/private ed25519 key pair.
    Enter file in which to save the key (/home/user/.ssh/id_ed25519): Press Enter
    Enter passphrase (empty for no passphrase): Enter passphrase
    Enter same passphrase again: Re-enter passphrase
    Terminal window
    ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip

    Or copy it manually:

    Terminal window
    cat ~/.ssh/id_ed25519.pub | ssh user@server_ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
    Terminal window
    ssh user@server_ip

    If you are no longer prompted for a password (or only need to enter the key passphrase), key-based authentication is working.

    The main SSH configuration file is located at /etc/ssh/sshd_config. After each change, you need to restart the sshd service.

    Terminal window
    sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
    Terminal window
    sudo vi /etc/ssh/sshd_config

    Find or add:

    PermitRootLogin no

    After confirming that key-based login works properly, disable password authentication:

    PasswordAuthentication no

    Also disable other insecure authentication methods:

    ChallengeResponseAuthentication no
    KbdInteractiveAuthentication no

    Changing the SSH port from the default 22 to another port can significantly reduce automated scanning attacks:

    Port 2222

    After changing the port, adjust SELinux and the firewall:

    Terminal window
    # Allow SELinux to use the new port
    sudo semanage port -a -t ssh_port_t -p tcp 2222
    # Allow the new port through the firewall
    sudo firewall-cmd --permanent --add-port=2222/tcp
    sudo firewall-cmd --permanent --remove-service=ssh
    sudo firewall-cmd --reload

    Only allow specific users to log in via SSH:

    AllowUsers admin deploy

    You can also restrict by source IP:

    AllowUsers admin@192.168.1.0/24 deploy@10.0.0.0/8

    Similarly, you can use AllowGroups for group-based authorization:

    AllowGroups sshusers
    Terminal window
    # Create the group and add users
    sudo groupadd sshusers
    sudo usermod -aG sshusers admin
    sudo usermod -aG sshusers deploy
    Terminal window
    # Disable empty password login
    PermitEmptyPasswords no
    # Set maximum authentication attempts
    MaxAuthTries 3
    # Set login timeout (seconds)
    LoginGraceTime 30
    # Disable X11 forwarding (if GUI is not needed)
    X11Forwarding no
    # Specify supported key exchange algorithms (remove weak ones)
    KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
    # Specify supported encryption algorithms
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
    # Specify supported MAC algorithms
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
    # Set client alive check interval
    ClientAliveInterval 300
    ClientAliveCountMax 2
    # Display last login information
    PrintLastLog yes

    Check the configuration syntax:

    Terminal window
    sudo sshd -t

    If there is no output, the syntax is correct. Restart the service:

    Terminal window
    sudo systemctl restart sshd

    The following is a recommended complete security configuration:

    Terminal window
    # /etc/ssh/sshd_config security configuration
    Port 2222
    # Authentication settings
    PermitRootLogin no
    PasswordAuthentication no
    PermitEmptyPasswords no
    ChallengeResponseAuthentication no
    KbdInteractiveAuthentication no
    PubkeyAuthentication yes
    AuthorizedKeysFile .ssh/authorized_keys
    # User control
    AllowUsers admin deploy
    MaxAuthTries 3
    LoginGraceTime 30
    # Security enhancements
    X11Forwarding no
    AllowTcpForwarding no
    AllowAgentForwarding no
    # Session management
    ClientAliveInterval 300
    ClientAliveCountMax 2
    # Logging
    LogLevel VERBOSE
    # Algorithms
    KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

    Fail2Ban monitors log files and automatically bans IP addresses with multiple authentication failures, making it an effective tool against brute-force attacks.

    Terminal window
    sudo dnf install epel-release -y
    sudo dnf install fail2ban -y
    Terminal window
    sudo systemctl enable --now fail2ban

    Do not modify /etc/fail2ban/jail.conf directly. Instead, create a local override configuration:

    Terminal window
    sudo vi /etc/fail2ban/jail.local

    Add the following configuration:

    [DEFAULT]
    # Ban duration (seconds), -1 for permanent ban
    bantime = 3600
    # Detection time window (seconds)
    findtime = 600
    # Maximum number of failures
    maxretry = 3
    # Ban action (using firewalld)
    banaction = firewallcmd-rich-rules
    banaction_allports = firewallcmd-rich-rules
    # Notification email (optional)
    destemail = admin@example.com
    sender = fail2ban@example.com
    action = %(action_mwl)s
    [sshd]
    enabled = true
    port = 2222
    logpath = /var/log/secure
    backend = systemd
    maxretry = 3
    bantime = 3600
    Terminal window
    sudo systemctl restart fail2ban
    Terminal window
    # Check overall status
    sudo fail2ban-client status
    # Check SSH jail details
    sudo fail2ban-client status sshd

    Example output:

    Status for the jail: sshd
    |- Filter
    | |- Currently failed: 2
    | |- Total failed: 15
    | `- File list: /var/log/secure
    `- Actions
    |- Currently banned: 1
    |- Total banned: 3
    `- Banned IP list: 203.0.113.50
    Terminal window
    # Manually unban an IP
    sudo fail2ban-client set sshd unbanip 203.0.113.50
    # Manually ban an IP
    sudo fail2ban-client set sshd banip 203.0.113.100
    # View all banned IPs
    sudo fail2ban-client banned
    1. Generate and deploy SSH keys:

      Terminal window
      # Run on the client
      ssh-keygen -t ed25519 -C "admin key"
      ssh-copy-id -i ~/.ssh/id_ed25519.pub admin@server_ip
    2. After verifying key-based login works, harden the sshd configuration:

      Terminal window
      # Run on the server
      sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
      sudo tee /etc/ssh/sshd_config.d/hardening.conf <<'EOF'
      Port 2222
      PermitRootLogin no
      PasswordAuthentication no
      PermitEmptyPasswords no
      ChallengeResponseAuthentication no
      MaxAuthTries 3
      LoginGraceTime 30
      AllowUsers admin
      X11Forwarding no
      ClientAliveInterval 300
      ClientAliveCountMax 2
      LogLevel VERBOSE
      EOF
    3. Adjust SELinux and firewall:

      Terminal window
      sudo semanage port -a -t ssh_port_t -p tcp 2222
      sudo firewall-cmd --permanent --add-port=2222/tcp
      sudo firewall-cmd --reload
    4. Check the configuration and restart SSH:

      Terminal window
      sudo sshd -t
      sudo systemctl restart sshd
    5. Test the connection on the new port (keep the old session open):

      Terminal window
      # Run in a new terminal
      ssh -p 2222 admin@server_ip
    6. After confirming the new port works, close the old port:

      Terminal window
      sudo firewall-cmd --permanent --remove-service=ssh
      sudo firewall-cmd --reload
    7. Install and configure Fail2Ban:

      Terminal window
      sudo dnf install epel-release fail2ban -y
      sudo tee /etc/fail2ban/jail.local <<'EOF'
      [DEFAULT]
      bantime = 3600
      findtime = 600
      maxretry = 3
      banaction = firewallcmd-rich-rules
      [sshd]
      enabled = true
      port = 2222
      backend = systemd
      EOF
      sudo systemctl enable --now fail2ban
      sudo fail2ban-client status sshd

    After completing these steps, your SSH service will have multiple layers of protection: key-based authentication, a non-standard port, a user whitelist, and automatic banning of brute-force IPs. Using these measures together significantly improves server security.