Skip to content
Search Fedora

    Browse this documentation

    SSH on Fedora: service configuration, key-based login and hardening

    sshd configuration on Fedora is laid out differently from most distributions: the main file is nearly empty and the real configuration lives in sshd_config.d/*.conf. On top of that, crypto-policies owns the cipher suite, so copying online tutorials often changes nothing.

    Measured on F45.

    Terminal window
    rpm -q openssh-server
    sudo grep -vE "^#|^$" /etc/ssh/sshd_config
    openssh-server-10.5p1-1.fc45.x86_64
    Include /etc/ssh/sshd_config.d/*.conf
    AuthorizedKeysFile .ssh/authorized_keys
    Subsystem sftp /usr/libexec/openssh/sftp-server

    The main file has three effective lines. Everything else is in the drop-in directory:

    Terminal window
    sudo ls /etc/ssh/sshd_config.d/
    40-redhat-crypto-policies.conf
    50-cloud-init.conf
    50-redhat.conf

    Which means: put your changes in a new 99-*.conf — do not touch the main file, and do not touch the 40- one.

    crypto-policies overrides your cipher settings

    Section titled “crypto-policies overrides your cipher settings”

    Look at 40-redhat-crypto-policies.conf:

    Terminal window
    sudo cat /etc/ssh/sshd_config.d/40-redhat-crypto-policies.conf
    # This system is following system-wide crypto policy. The changes to
    # crypto properties (Ciphers, MACs, ...) will not have any effect in
    # this or following included files. ...

    In other words: writing Ciphers, MACs or KexAlgorithms into sshd_config.d/ mostly does nothing, because the system-wide crypto policy decides first. For a stricter suite, change the policy:

    Terminal window
    update-crypto-policies --show
    DEFAULT
    Terminal window
    sudo update-crypto-policies --set FUTURE # stricter suite set, takes effect on reboot
    sudo update-crypto-policies --set DEFAULT # revert

    See the configuration that actually applies

    Section titled “See the configuration that actually applies”

    Do not read files; read the effective values:

    Terminal window
    sudo sshd -T
    Port 22
    AddressFamily any
    ListenAddress [::]:22

    sshd -T expands includes and defaults into the final configuration. This is always step one in troubleshooting, not reading file by file.

    The client side has the same tool:

    Terminal window
    ssh -G <host> | grep -E "^(user|port|identityfile|proxyjump)"

    Generate an ed25519 pair (shorter and faster than RSA; what OpenSSH 10 recommends):

    Terminal window
    ssh-keygen -t ed25519 -C "alice@laptop"
    +----[SHA256]-----+
    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHiplpcIlutsQhEAyomGV8+ntl2VIaba3xiHIsrxRY2A alice@laptop

    File permissions:

    Terminal window
    ls -l ~/.ssh/
    -rw-------. 1 labuser labuser 97 Oct 25 17:37 authorized_keys

    The rules are rigid: private key 600, authorized_keys and config 600, the .ssh directory 700. If permissions are too open, sshd ignores the file and logs a line — which shows up as “the key is uploaded but it still asks for a password”.

    Copy the key to the server:

    Terminal window
    ssh-copy-id alice@server

    It appends the public key to ~/.ssh/authorized_keys and fixes the permissions.

    PathModeNote
    ~/.ssh700too open and sshd ignores it
    ~/.ssh/id_ed25519600the private key, never shared
    ~/.ssh/id_ed25519.pub644public key, safe to distribute
    ~/.ssh/authorized_keys600server-side public keys
    /etc/ssh/sshd_config600main config (three lines on Fedora)
    /etc/ssh/sshd_config.d/*.conf600the drop-ins that actually apply
    /etc/ssh/ssh_host_*_key600host private keys — back them up or clients will see a fingerprint change

    Write a new file; do not edit the main configuration:

    Terminal window
    sudo tee /etc/ssh/sshd_config.d/99-hardening.conf >/dev/null <<'EOF'
    PermitRootLogin no
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    MaxAuthTries 3
    ClientAliveInterval 300
    ClientAliveCountMax 2
    EOF
    sudo sshd -t # syntax check, always
    sudo systemctl reload sshd

    sshd -t only validates; on a typo it points at the line number. Reloading without running -t is how people lock themselves out.

    On Cloud images this is already the default:

    Terminal window
    sudo cat /etc/ssh/sshd_config.d/50-cloud-init.conf
    PasswordAuthentication no

    Changing the port takes three steps, not one:

    Terminal window
    sudo tee /etc/ssh/sshd_config.d/99-port.conf >/dev/null <<'EOF'
    Port 2222
    EOF
    sudo sshd -t && sudo systemctl reload sshd

    Do not forget the firewall and SELinux:

    Terminal window
    sudo firewall-cmd --permanent --add-port=2222/tcp && sudo firewall-cmd --reload
    sudo semanage port -a -t ssh_port_t -p tcp 2222

    Change only sshd and the result is “configured correctly, still cannot connect”. See firewalld and SELinux.

    Terminal window
    ss -tlnp | grep :22 # 1) is it listening
    sudo sshd -T | head -5 # 2) what configuration applies
    sudo sshd -t # 3) is the syntax valid
    journalctl -u sshd -n 30 --no-pager # 4) why authentication failed
    sudo ausearch -m AVC -ts recent # 5) is SELinux blocking it

    In step 4, Failed publickey for alice and Invalid user are completely different problems: the first is a wrong key or over-permissive permissions, the second is a user that does not exist.