Zabezpieczenie SSH: logowanie kluczem, blokada logowania roota, wyłączenie haseł
ed25519 pod Linuksem, macOS i Windows, pułapka cloud-init w /etc/ssh/sshd_config.d, aktywacja przez socket w Ubuntu 24.04, dowód przez sudo sshd -T oraz droga ratunkowa przez konsolę.
Świeżo postawiony serwer trafia na listy skanerów już kilka minut po tym, jak po raz pierwszy odezwie się z sieci. To, co potem do niego puka, wygląda prawie zawsze tak samo: automatyczne przebieranie nazw użytkowników i haseł na porcie 22. Kto wyłączy logowanie hasłem i dopuści wyłącznie klucze, zabiera całej tej klasie ataków grunt spod nóg. Nie osłabia jej, tylko usuwa w całości.
Podstawowe kroki zna większość administratorów. W typowych poradnikach brakuje tego, co dzieje się potem: dlaczego PasswordAuthentication no na obrazach chmurowych regularnie nie odnosi żadnego skutku, dlaczego systemctl reload ssh na serwerze z aktywnym ssh.socket nie robi już tego, czego oczekujesz, oraz jak udowodnić, zamiast mieć nadzieję, że zmiana naprawdę zadziałała. Właśnie o to chodzi w tym poradniku. Wszystkie informacje dotyczą Debiana 13, Debiana 12, Ubuntu 24.04 i Ubuntu 22.04.
Zasada, która ratuje wszystko: dwie sesje
Zanim zmienisz cokolwiek w konfiguracji SSH, otwórz drugie okno terminala i zaloguj się w nim na serwer po raz drugi. Ta druga sesja pozostaje otwarta tak długo, aż z powodzeniem przetestujesz nową konfigurację trzecim, całkowicie nowym połączeniem.
Powód jest czysto techniczny: restart usługi SSH nie kończy istniejących sesji. Trwające połączenia obsługują odgałęzione wcześniej procesy potomne, które przeżywają restart procesu nadrzędnego. Zepsutą konfigurację zauważysz więc dopiero przy kolejnej próbie połączenia, a wtedy stara sesja jest twoją jedyną drogą powrotną. Kto ją zamyka, żeby „zalogować się jeszcze raz, tym razem czysto”, żałuje tego z pewną regularnością.
Sprawdź poza tym, z jaką wersją OpenSSH masz do czynienia, bo od niej zależy kilka szczegółów:
ssh -V
| System | OpenSSH | Domyślny listener |
| Debian 13 (trixie) | 10.0p2 | ssh.service |
| Debian 12 (bookworm) | 9.2p1 | ssh.service |
| Ubuntu 24.04 LTS | 9.6p1 | ssh.socket |
| Ubuntu 22.04 LTS | 8.9p1 | ssh.service |
Jeśli usługi serwera w ogóle nie ma, na przykład w minimalnym obrazie systemu, doinstaluj ją:
sudo apt update
sudo apt install -y openssh-server
Generowanie klucza: ed25519 pod Linuksem, macOS i Windows
Wybierz ed25519. Klucz jest krótki, szybko się go weryfikuje, ma duży zapas bezpieczeństwa, a obsługuje go każda omawiana tu wersja OpenSSH. RSA potrzebujesz już tylko do starych systemów, które nie przyjmują niczego innego, i to z długością co najmniej 4096 bitów.
Linux i macOS
ssh-keygen -t ed25519 -a 100 -C "hani@notebook" -f ~/.ssh/id_ed25519
-a 100 podnosi liczbę rund KDF dla hasła klucza (passphrase) i znacząco podraża ataki offline na sam plik klucza. -C ustawia komentarz, który trafia później do authorized_keys i podpowiada ci, który klucz pochodzi z którego urządzenia. Nadaj hasło klucza. Klucz bez hasła to zwykły plik, który zabierze ze sobą każdy, kto choć na chwilę usiądzie przy twoim komputerze.
Żebyś nie musiał wpisywać hasła klucza przy każdym połączeniu, buforowaniem zajmie się agent:
eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519
Pod macOS zamiast tego umieszczasz hasło klucza w pęku kluczy. Dawny przełącznik -K nazywa się od macOS 12 --apple-use-keychain:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Żeby ustawienie przetrwało restart, do ~/.ssh/config trafia:
Host *
UseKeychain yes
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
Windows
Windows 10 od wersji 1809, Windows 11 oraz Windows Server od 2019 mają klienta OpenSSH na pokładzie. W PowerShellu:
ssh -V
ssh-keygen -t ed25519 -a 100 -C "hani@windows"
Klucz trafia do C:\Users\TwojaNazwa\.ssh\. Jeśli klienta brakuje, doinstaluj go jako funkcję systemu Windows:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Agent jest pod Windows usługą systemową i fabrycznie pozostaje wyłączony:
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
Przeniesienie klucza publicznego na serwer
Na serwer trafia wyłącznie plik z rozszerzeniem .pub. Plik bez rozszerzenia to klucz prywatny i nigdy nie opuszcza twojego komputera.
Wygodna droga pod Linuksem
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@203.0.113.10
ssh-copy-id zakłada katalog ~/.ssh, ustawia poprawne uprawnienia, dopisuje klucz do authorized_keys i sprawdza przy okazji, czy nie ma go tam już wcześniej. Pod macOS narzędzie nie jest dołączone do każdej wersji systemu. Sprawdź to krótko poleceniem command -v ssh-copy-id, a w razie potrzeby przejdź na drogę ręczną.
Droga pod Windows, bez ssh-copy-id
Klient OpenSSH od Microsoftu nie zawiera ssh-copy-id. Oryginał jest skryptem powłoki i nigdy nie został przeniesiony na Windows. Ten sam efekt osiągniesz potokiem:
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh root@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Czai się tu szczegół, który potrafi kosztować wiele godzin: PowerShell, przekazując dane do zewnętrznego programu, dokleja końce wierszy w formacie Windows. W authorized_keys ląduje wtedy niewidoczny znak powrotu karetki na końcu wiersza. Jeśli opatrzyłeś klucz komentarzem przez -C, znak ten trafia do pola komentarza i niczemu nie przeszkadza. Bez komentarza dokleja się do bloku Base64, a logowanie kończy się niepowodzeniem bez żadnego sensownego komunikatu. Dlatego: zawsze ustawiaj komentarz, a w razie wątpliwości posprzątaj raz na serwerze.
sed -i 's/\r$//' ~/.ssh/authorized_keys
Droga ręczna, która działa wszędzie
mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
Następnie dopisz zawartość pliku .pub jako jeden jedyny wiersz. Jeśli plik leży już na serwerze, bo na przykład wgrałeś go wcześniej, zrobisz to od razu:
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
Sprawdź potem, co faktycznie znalazło się w pliku:
ssh-keygen -lf ~/.ssh/authorized_keys
Wynik zawiera odcisk palca i komentarz każdego poprawnego wpisu. Czego tu nie widać, zostało złamane na kilka wierszy albo uszkodzone. Porównaj odcisk palca z odciskiem swojego lokalnego klucza:
ssh-keygen -l -f ~/.ssh/id_ed25519.pub
Jeśli oba są zgodne, transport przebiegł prawidłowo. Teraz, zanim cokolwiek wyłączysz, przetestuj, czy logowanie kluczem w ogóle działa. Dalej idziesz dopiero wtedy, gdy nowe połączenie przechodzi bez pytania o hasło.
Pułapka: /etc/ssh/sshd_config.d i cloud-init
To jest miejsce, w którym większość poradników się kończy, i najczęstszy powód zdania „przecież to wyłączyłem, a ono dalej działa”.
Od Debiana 11 i Ubuntu 22.04 na samej górze pliku /etc/ssh/sshd_config znajduje się wiersz, który wczytuje cały katalog. Sprawdź sam, na której pozycji:
grep -n Include /etc/ssh/sshd_config
Na wszystkich czterech omawianych tu systemach wiersz Include znajduje się na początku, a nie na końcu. I tu dochodzi osobliwość OpenSSH, której nie zna prawie żaden inny język konfiguracji: wygrywa pierwsza znaleziona wartość, a nie ostatnia. To, co leży w pliku w katalogu /etc/ssh/sshd_config.d/, jest więc czytane przed plikiem głównym i bije każdy późniejszy wiersz w sshd_config.
Cloud-init korzysta dokładnie z tego katalogu. Przy pierwszym uruchomieniu zapisuje /etc/ssh/sshd_config.d/50-cloud-init.conf, a w zależności od sposobu udostępnienia serwera widnieje tam PasswordAuthentication yes. Możesz potem wpisywać PasswordAuthentication no do sshd_config tyle razy, ile chcesz: logowanie hasłem i tak pozostanie otwarte. Najpierw zrób sobie rozeznanie:
ls -la /etc/ssh/sshd_config.d/
sudo grep -riE 'passwordauthentication|permitrootlogin|kbdinteractive' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/
Stąd wynika właściwe zalecenie: nie ruszaj sshd_config w ogóle. Załóż zamiast tego własny plik, którego nazwa sortuje się alfabetycznie przed wszystkim, co odkłada tam automatyzacja. Pliki są wczytywane w kolejności posortowanej, 01- idzie przed 50-, a ponieważ wygrywa pierwsza wartość, cloud-init może potem zapisywać swój plik dowolnie wiele razy i tak nie podważy twojego utwardzenia. Na tym polega różnica wobec szeroko rozpowszechnionej rady, żeby zakładać 99-hardening.conf: taki plik przegrywa z cloud-init, i to całkiem po cichu. Ta sama mechanika potrafi się jednak obrócić przeciwko tobie: plik z mniejszym numerem, na przykład 00-cloud.conf, wygrywa z twoim 01-, bo OpenSSH bierze wartość przeczytaną jako pierwszą. Zajrzenie do katalogu opłaca się dlatego również po utwardzeniu.
Zapis utwardzenia, z bezpiecznikiem czasowym jako drogą wycofania
Najpierw rozepnij siatkę bezpieczeństwa. Poniższe polecenie usuwa twój nowy plik automatycznie po dziesięciu minutach i restartuje SSH, o ile do tego czasu go nie przerwiesz:
sudo systemd-run --on-active=10min --unit=ssh-rollback /bin/sh -c 'rm -f /etc/ssh/sshd_config.d/01-hardening.conf; systemctl try-restart ssh.socket ssh.service'
Teraz właściwa konfiguracja:
sudo tee /etc/ssh/sshd_config.d/01-hardening.conf >/dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
PermitEmptyPasswords no
MaxAuthTries 3
EOF
sudo chmod 644 /etc/ssh/sshd_config.d/01-hardening.conf
Dwa wiersze zasługują na wyjaśnienie. KbdInteractiveAuthentication no to nie ozdobnik: jeśli zostanie na yes, PAM może dalej podsuwać pytanie o hasło okrężną drogą interaktywnego wprowadzania z klawiatury, choć PasswordAuthentication jest ustawione na no. Dokładnie dlatego istnieją serwery, które mimo wyłączonego logowania hasłem nadal pytają o hasło.
I jeszcze PermitRootLogin prohibit-password zamiast no: dzięki temu dostęp jako root kluczem zostaje zachowany, a hasła dla roota są wykluczone. Jeśli masz już założonego własnego użytkownika z sudo i sprawdziłeś, że logowanie kluczem na to konto naprawdę działa, ustaw zamiast tego PermitRootLogin no. Wcześniej nie.
Czego nie warto przenosić do własnej konfiguracji, choć zalecają to starsze poradniki: ChallengeResponseAuthentication. Od OpenSSH 8.7 opcja jest już tylko przestarzałym aliasem dla KbdInteractiveAuthentication i w aktualnych wersjach wywołuje w logu komunikat o wycofaniu. Pomiń ją.
Kontrola składni przed włączeniem, bez wyjątku:
sudo sshd -t
Brak jakiegokolwiek wyniku oznacza: plik jest poprawny składniowo. Nie znaczy to, że merytorycznie robi to, czego chcesz. Od tego jest za chwilę sudo sshd -T.
Jeśli test zgłasza zamiast tego Missing privilege separation directory: /run/sshd, to znaczy, że sshd od startu systemu nie uruchomił się ani razu, bo ten katalog powstaje dopiero razem z ssh.service. Dotyczy to przede wszystkim Ubuntu 24.04 z aktywacją przez socket i da się usunąć poleceniem sudo mkdir -p /run/sshd albo sudo systemctl start ssh.service, a na serwerze, na którym właśnie jesteś zalogowany przez SSH, i tak nie wystąpi.
Włączenie: ssh.service, ssh.socket i różnice między dystrybucjami
Tutaj cztery systemy się rozchodzą, a stary nawyk systemctl reload ssh jest złą odpowiedzią wszędzie tam, gdzie port trzyma ssh.socket.
Ubuntu stawia od wersji 22.10 na aktywację przez socket, a Ubuntu 24.04 dostarcza ją domyślnie: tam ssh.socket jest włączony, a ssh.service wyłączony. Debian robi to fabrycznie dokładnie odwrotnie. Debian 13 i Debian 12 dostarczają włączony ssh.service i wyłączony ssh.socket, wbrew rozpowszechnionemu przekonaniu, że Debian 13 przy nowej instalacji przechodzi na socket. Przy aktywacji przez socket to sam systemd nasłuchuje na porcie 22 i dopiero przy przychodzącym połączeniu uruchamia świeży proces sshd. Ma to przyjemny efekt uboczny: zmiany w sshd_config i tak zadziałają przy kolejnym połączeniu, bo każdy proces obsługujący połączenie wczytuje konfigurację od nowa. Przeładowania potrzebujesz tylko dla ustawień dotyczących samego listenera, czyli Port oraz ListenAddress.
Nie zgaduj więc, tylko zapytaj system, która jednostka obsługuje u ciebie tę usługę:
systemctl is-enabled ssh.socket ssh.service
| System | ssh.socket | ssh.service | Cecha szczególna |
| Ubuntu 24.04 LTS | enabled | disabled | Aktywacja przez socket domyślnie, ListenStream na 0.0.0.0:22 oraz [::]:22 |
| Debian 13 (trixie) | disabled | enabled | Accept=no |
| Debian 12 (bookworm) | disabled | enabled | Accept=no |
| Ubuntu 22.04 LTS (a także Debian 11) | disabled | enabled | Accept=yes, czyli osobny proces na każde połączenie przez ssh@.service |
A potem polecenie, które jest poprawne na wszystkich czterech systemach:
sudo sshd -t && sudo systemctl try-restart ssh.socket ssh.service
try-restart restartuje jednostkę tylko wtedy, gdy jest ona faktycznie aktywna, a drugą zostawia nietkniętą. Dzięki temu nie musisz zgadywać. Obie części wymagają uprawnień roota: sshd leży w /usr/sbin i na Debianie nie znajduje się w PATH zwykłego użytkownika, a try-restart i tak sięga do systemd. Bez sudo wywołanie kończy się, zależnie od systemu, komunikatem sshd: command not found albo sshd: no hostkeys available, bo klucze hosta w /etc/ssh są czytelne tylko dla roota.
Równie świadomie żadnego pojedynczego systemctl restart ssh.socket, nawet jeśli to polecenie pojawia się w wielu poradnikach. Na Debianie 13 i Debianie 12 przerywa ono działanie z komunikatem Job failed. See journalctl -xe for details., a w journalu dochodzi do tego ssh.socket: Socket service ssh.service already active, refusing. Nowa konfiguracja nie staje się przy tym aktywna, a test kontrolny nadal zgłasza Permission denied (publickey,password). Na Ubuntu 22.04 i Debianie 11 polecenie przechodzi wprawdzie bez komunikatu błędu, ale zatrzymuje przy tym ssh.service i przestawia hosta na aktywację przez socket. Ponieważ ssh.socket pozostaje tam wyłączony, przy kolejnym restarcie znów rusza ssh.service, tryb pracy przeskakuje więc niepostrzeżenie tam i z powrotem. try-restart na obie jednostki omija jedno i drugie.
Świadomie także żadnego reload: na systemie, na którym port trzyma ssh.socket, systemctl reload ssh kwituje to komunikatem
fatal: Cannot bind any address.
Usługa trafia potem w stan błędu i oddaje swój port. Restart nie ma tego problemu i tak samo nie kończy istniejących sesji.
Jeśli chcesz przenieść port, pojawia się kolejna różnica między dystrybucjami. Ubuntu 24.04 tworzy konfigurację socketu generatorem systemd na podstawie sshd_config, tam po zmianie portu wystarczy:
sudo systemctl daemon-reload
sudo systemctl try-restart ssh.socket ssh.service
Jeśli natomiast na Debianie świadomie przestawiłeś się na ssh.socket, port znajduje się w samej jednostce, a zmiana w sshd_config nie odnosi żadnego skutku. Zapisujesz go wtedy w pliku uzupełniającym przez sudo systemctl edit ssh.socket, z pustym ListenStream= do wyzerowania i drugim wierszem z nową wartością. Wynik sprawdź potem w rzeczywistości, a nie w konfiguracji:
sudo ss -tlnp
Dowód: sshd -T i test kontrolny
Polecenie, które przechodzi bez błędu, nie jest jeszcze dowodem. Dowodem jest rozwinięta konfiguracja całkowita, w której uwzględniono już wszystkie dołączone pliki:
sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin|usepam|port|authorizedkeysfile)'
Oczekiwany wynik wygląda mniej więcej tak:
port 22
permitrootlogin prohibit-password
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
usepam yes
authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2
Jeśli mimo twojego pliku widnieje tam passwordauthentication yes, w katalogu leży plik, który sortuje się alfabetycznie przed twoim. Wróć do rozdziału o kolejności.
Do zapytania o pojedynczą wartość wystarczy to samo polecenie z węższym filtrem:
sudo sshd -T | grep -i passwordauthentication
Za sudo na początku przemawiają dwa powody. Po pierwsze sshd -T czyta klucze hosta, które w /etc/ssh są czytelne tylko dla roota. Po drugie sam sshd leży w /usr/sbin, a ten katalog nie należy na Debianie do PATH zwykłego użytkownika, przez co wywołanie bez sudo kończy się tam komunikatem sshd: command not found. Kto chce ominąć drogę przez sudo, wpisuje pełną ścieżkę /usr/sbin/sshd.
Od OpenSSH 9.3, czyli na Ubuntu 24.04 (9.6p1) i Debianie 13 (10.0p2), dochodzi dodatkowo sshd -G. Opcja rozwija tę samą konfigurację, ale nie wymaga czytelnych kluczy hosta ani istniejącego /run/sshd, co czyni ją przydatną do sprawdzeń w automatyzacji i w kontenerach. Na Debianie 12 (9.2p1), Ubuntu 22.04 (8.9p1) i Debianie 11 (8.4p1) przełącznika jeszcze nie ma, sshd kwituje go tam jako nieznaną opcję. Dla poradnika, który ma obowiązywać wszędzie, właściwym wyborem pozostaje więc sudo sshd -T.
Teraz test kontrolny, i to z nowego terminala, podczas gdy stara sesja pozostaje otwarta. Wymuś logowanie hasłem i wyłącz klucze na czas tej próby:
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password,keyboard-interactive root@203.0.113.10
Poprawnie jest wtedy, gdy zostaniesz odrzucony natychmiast i bez żadnego pytania o hasło:
root@203.0.113.10: Permission denied (publickey).
Decydująca jest zawartość nawiasu. Jeśli widnieje tam (publickey,password) albo pojawia się pytanie o hasło, logowanie hasłem jest nadal otwarte. Dopiero gdy test kontrolny zawiedzie dokładnie tak, jak powinien, a zwykłe połączenie kluczem nadal działa, zamykasz starą sesję i zatrzymujesz bezpiecznik czasowy:
sudo systemctl stop ssh-rollback.timer
Komunikaty błędów, dosłownie
Permission denied (publickey). Serwer przyjmuje tylko klucze, a twój nie pasuje. Wywołaj ssh -v i sprawdź, który plik w ogóle został zaproponowany. Najczęstsze przyczyny: zła nazwa użytkownika, klucz w authorized_keys niewłaściwego użytkownika, albo zablokowałeś roota, a dalej logujesz się jako root.
Authentication refused: bad ownership or modes for directory /home/hani/.ssh Ten wiersz nie pojawia się na twoim ekranie, tylko w logu serwera, widoczny przez sudo journalctl -u ssh -n 50 --no-pager. Nie filtruj przy tym po -t sshd: od OpenSSH 9.8, czyli na Debianie 13 już w stanie fabrycznym, sesje działają we własnym procesie sshd-session, a pod znacznikiem sshd zostają potem tylko komunikaty listenera i ani jedna operacja logowania. Kto chce filtrować po znacznikach, użyje sudo journalctl -t sshd -t sshd-session -n 50 --no-pager. OpenSSH odmawia przyjęcia klucza, gdy katalog domowy, .ssh albo authorized_keys są zapisywalne dla grupy lub dla pozostałych. Poprawka:
chmod go-w ~ && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
WARNING: UNPROTECTED PRIVATE KEY FILE! względnie Load key "/home/hani/.ssh/id_ed25519": bad permissions. Ten sam problem po stronie klienta. Rozwiązuje go chmod 600 ~/.ssh/id_ed25519.
Too many authentication failures Twój agent podsuwa po kolei wszystkie wczytane klucze i przekracza przy tym MaxAuthTries. Ogranicz połączenie do jednego jedynego klucza: ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 hani@203.0.113.10.
sign_and_send_pubkey: no mutual signature supported Stary klucz RSA z podpisem SHA-1 trafia na serwer, który już tego nie przyjmuje. Wygeneruj klucz ed25519, zamiast majstrować przy PubkeyAcceptedAlgorithms.
Bad owner or permissions on C:\Users\hani\.ssh\config Klient Windows sprawdza uprawnienia dostępu do swojego pliku konfiguracyjnego. We właściwościach pliku, w zakładce Zabezpieczenia, usuń dziedziczenie oraz wszystkie wpisy poza twoim kontem użytkownika i SYSTEM.
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! Klucz hosta serwera jest inny niż poprzednim razem. Po ponownej instalacji systemu jest to spodziewane, w innym wypadku nie. Usuń celowo tylko ten jeden wpis poleceniem ssh-keygen -R 203.0.113.10, i tylko wtedy, gdy znasz powód.
Zatrzaśnięte drzwi: droga przez konsolę w panelu klienta
Jeśli obie sesje przepadły i żadne połączenie się już nie nawiązuje, nie jest to utrata danych, tylko objazd. Każdy serwer root KVM i każdy serwer dedykowany KernelHost ma w panelu klienta konsolę, która jest podpięta do wyjścia ekranowego systemu i działa niezależnie od stosu sieciowego serwera. Wejdziesz więc do środka także wtedy, gdy SSH w ogóle już nie nasłuchuje.
- Zaloguj się w panelu klienta, otwórz dotknięty serwer i uruchom konsolę.
- W monicie logowania zaloguj się jako root hasłem nadanym przy udostępnianiu serwera. Logowanie przez konsolę nie przechodzi przez SSH, więc
PermitRootLogingo nie dotyczy. - Cofnij zmianę:
sudo rm /etc/ssh/sshd_config.d/01-hardening.conf - Sprawdź i zrestartuj:
sudo sshd -t && sudo systemctl try-restart ssh.socket ssh.service - Jeśli SSH w ogóle nie działa, pomogą
sudo systemctl status ssh.socket ssh.serviceoraz zajrzenie dosudo journalctl -u ssh -n 50 --no-pager. Kod wyjścia 3 przystatusoznacza tylko, że jedna z dwóch jednostek jest nieaktywna, a na Debianie z wyłączonymssh.socketto sytuacja normalna.
Dwa środki ostrożności oszczędzą ci tej drogi prawie zawsze. Zanotuj hasło roota, zanim wyłączysz logowanie hasłem, bo konsola go potrzebuje. I sprawdź aktywny firewall, zanim przeniesiesz port SSH. Zmiana portu bez pasującego otwarcia zatrzaskuje drzwi równie skutecznie jak zepsuta sshd_config, ale wygląda inaczej: zamiast Permission denied dostajesz Connection timed out.
W skrócie
- Zostaw drugą sesję otwartą, dopóki nie potwierdzisz, że trzecie, nowe połączenie działa.
- ed25519 z
-a 100i hasłem klucza, klucz publiczny przezssh-copy-id, a pod Windows potokiem. - Przetestuj logowanie kluczem, zanim padnie logowanie hasłem.
- Utwardzenie do
/etc/ssh/sshd_config.d/01-hardening.conf, nie dosshd_config. Wygrywa pierwsza znaleziona wartość, stąd niski numer. - Nie zapomnij o
KbdInteractiveAuthentication no, inaczej okrężna droga przez PAM zostaje otwarta. - Włączaj przez
sudo sshd -t && sudo systemctl try-restart ssh.socket ssh.service, a nie przezreloadani pojedynczyrestart ssh.socket. - Wcześniej ustal poleceniem
systemctl is-enabled ssh.socket ssh.service, która jednostka jest w ogóle aktywna. Ubuntu 24.04 korzysta z socketu, a Debian 13 i Debian 12 z usługi. - Dowód przez
sudo sshd -Toraz wymuszoną próbę logowania hasłem z nowej sesji. - Drogą awaryjną jest konsola w panelu klienta, miej na nią przygotowane hasło roota.
Kolejne oczywiste warstwy opisują nasze artykuły o fail2ban oraz o firewallu UFW. Ważniejsze od obu jest to, co właśnie zrobiłeś.
Najczęstsze pytania
Dlaczego logowanie hasłem działa dalej mimo PasswordAuthentication no?
Czy po zmianie w sshd_config muszę zrestartować usługę?
Dlaczego lepiej unikać polecenia reload?
Jak przenieść klucz z Windows na serwer, skoro nie ma tam ssh-copy-id?
Jak udowodnić, że logowanie hasłem jest naprawdę zamknięte?
Co zrobić, jeśli zablokowałem sobie dostęp?
Co jest lepszym wyborem: PermitRootLogin no czy prohibit-password?
2026 KernelHost GmbH. Wszelkie prawa zastrzeżone. Ten poradnik jest chroniony prawem autorskim. Publikowanie go w innych serwisach, w całości, we fragmentach lub w zmienionej formie, wymaga naszej pisemnej zgody. Cytaty z podaniem źródła i z linkiem są jak najbardziej mile widziane.

