ByteScope

22

連接埠 22 · SSH

TCPIANA 有指派遠端連線

sshd 監聽的連接埠。後面掛著 `scp`、`rsync`、走 SSH 的 `git`、各種通道,還有 SFTP——所以這裡被拒絕一次,會同時弄壞五件不同的事。

查出是誰占用連接埠 22

照你的系統挑一行貼上去執行。它會直接印出占著這個連接埠的行程,以及它綁在哪個位址上——通常看到這兩件事答案就出來了。

從機器外面確認一次

`nmap -Pn -p 22 host.example.com` 回報的是這個連接埠從機器外面看起來的樣子,而 `-Pn` 直接當目標是活的,所以會丟掉 ping 的主機照樣掃得到。nmap 的定義很精確:`open` 是那裡真的有應用程式在接受連線;`closed` 是連接埠到得了也回了話,但沒有東西在監聽——sshd 停掉時就長這樣;`filtered` 是封包過濾讓探測封包到不了連接埠,所以 nmap 分不出 open 還是 closed,而那道防火牆正是害你的用戶端卡住、而不是乾脆快速失敗的元凶。`--reason` 會印出實際回來的東西,open 是 `syn-ack`,closed 是 `conn-refused`。`-sV` 讀的是版本橫幅,而 SSH 的橫幅就是協定在任何加密之前用明文送出的識別字串,長得像 `SSH-2.0-OpenSSH_9.6`。那串字也正是全網掃描器在收集的東西,所以請當成公開資訊看待。只掃你自己負責的主機。

連不上 22 的時候怎麼讀

你看到的訊息代表什麼
ssh: connect to host host.example.com port 22: Connection refused主機活著也回話了——它的核心送了一個 reset,因為沒有任何行程占著連接埠 22。可能是 sshd 停了或啟動失敗、綁在一個不含你撥過去那個位址的地方,或是改完設定之後改聽別的連接埠了。這個失敗是瞬間回來的,而那個速度就是有用的線索:網路路徑是通的,缺的只有服務。請從主控台或另一條進得去的路,在那台機器上跑你系統對應的探測指令。
ssh: connect to host host.example.com port 22: Connection timed out這是相反的診斷,也正是這兩個值得分清楚的原因。什麼都沒回來:防火牆、雲端安全群組或網路 ACL 正安靜地丟掉你的 SYN,再不然就是你撥的那個位址已經不屬於那台機器了。macOS 會把同一件事講成 `Operation timed out`。你等的那幾十秒就是破綻——被拒絕會立刻回來,被丟掉則要一路坐到連線逾時。用 `nmap --reason` 確認,`filtered` 就是被丟掉。
Permission denied (publickey).TCP、連接埠和 daemon 全都正常——你已經走到認證才失敗,而且這句話直接點名了伺服器唯一願意嘗試的方式。照順序來:先跑 `ssh -v`,讀 `Offering public key` 那幾行,看用戶端實際送出的是哪把金鑰;agent 裡塞了一堆金鑰時,可能還沒輪到對的那把就先耗光伺服器的嘗試次數上限,所以用 `-i` 搭 `IdentitiesOnly=yes` 把它釘死。接著看伺服器端,金鑰必須放在那個帳號的 `~/.ssh/authorized_keys` 裡。OpenSSH 的 `StrictModes` 預設是 yes,所以家目錄、`.ssh` 或 `authorized_keys` 只要是群組或所有人可寫,sshd 就會直接忽略那個檔案,而且不會告訴用戶端任何事——`~/.ssh` 設 700,`authorized_keys` 設 600,擁有者是那位使用者。真正的原因伺服器紀錄會用一行寫清楚,用戶端這邊則永遠不會。
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! ... Host key verification failed.伺服器出示的金鑰,跟 `known_hosts` 裡以那個名字記著的不一樣,而這是少數幾個「反射動作剛好是錯的」的錯誤。不要一上來就 `ssh-keygen -R`:那會刪掉你手上唯一一份「這台主機以前長什麼樣」的紀錄。無害的原因有好幾種——機器重建過、雲端位址被釋放後配給別人的執行個體、那個名字現在解析到另一個後端、或你是透過轉發的連接埠連到了另一台主機;還有一種不無害的,就是有人坐在你和伺服器中間。先把是哪一種確定下來:把 ssh 印出來的指紋,拿去跟在主控台上跑 `ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key` 得到的,或跟執行個體開機紀錄裡那份對照。`ssh-keygen -F host` 會告訴你存起來的那筆在哪裡、內容是什麼。確認過新的指紋之後,`ssh-keygen -R host` 才變成正確的指令。
error: Bind to port 22 on 0.0.0.0 failed: Address already in use.已經有東西占著那個 socket,所以 sshd 起不來。通常是舊的 sshd 還在跑——一次跟自己的關閉搶跑的 restart,或是一份手動編譯的裝置在跟套件管理的服務打架;也有 socket unit 占著 22、你又同時啟動了 service unit 的情況。用上面的指令把持有者找出來,不要用猜的。還有,沒有主控台或第二條進得去的路之前,不要在一個依賴著它的工作階段裡把正在跑的 sshd 停掉。
ssh_exchange_identification: Connection closed by remote hostTCP 連線是成功的,是 sshd 在送出協定橫幅之前就把你掛掉,所以連接埠、路由和防火牆全都沒事。常見原因有三個:fail2ban 之類的東西封鎖了你的來源位址;機器負載高或檔案描述子用盡時 `MaxStartups` 開始丟連線;以及 `AllowUsers`、`DenyUsers` 或 TCP wrappers 這類存取規則。這不是網路故障,是伺服器對你做了決定,而是哪一種,伺服器的紀錄會說。

連接埠 22 上跑的是什麼

IANA 把 22 指派給 `ssh`,也就是 Secure Shell 協定,TCP、UDP、SCTP 都登記了,實務上只有 TCP 在用。這個連接埠上的一個監聽者扛的遠不只互動式 shell:`scp`、跑在 SSH 上的 `rsync`、`git clone git@host:repo`、`ssh -L` 和 `-D` 的通道、`ProxyJump` 的跳板,還有 SFTP 子系統——所謂 SFTP 就只是這個,跟連接埠 21 的 FTP 一點關係都沒有。OpenSSH 文件寫明的預設值是 `sshd_config` 裡的 `Port 22`,綁哪幾張介面則由 `ListenAddress` 決定;這兩個指令都可以寫不只一次,所以一台伺服器同時在 22 和另一個連接埠上正常回應,是完全合理的。動手找行程之前先知道一件事:現在有好幾個發行版會附上 SSH 的 systemd socket unit,在 `ssh.socket` 是啟用單元的主機上,占著連接埠 22 的是 `systemd`,`sshd` 要等連線進來才存在。這是正常的,不代表有別的東西搶了它。把 SSH 從 22 搬走也不是改一行就好:改 `sshd_config` 的 `Port`、在主機防火牆開新的連接埠,SELinux 的系統還要再用 `semanage port -a -t ssh_port_t -p tcp 2222` 登記一次。少了最後這步,sshd 會啟動、把綁定失敗寫進紀錄,而你被鎖在一台從其他任何角度看都很健康的機器外面。新連接埠一定要在第一條連線還開著的時候,從第二個工作階段去測。

連接埠 22 該不該對外開

連接埠 22 是少數幾個「開出去講得過去」的管理用連接埠,因為傳輸是加密的,而且用戶端會在送出任何機密之前先驗證伺服器的主機金鑰。但那跟安全不是同一回事。22 上的監聽者幾小時內就會被發現,接著開始承受一股無趣但不會停的猜密碼流量,目標是 `root`、`admin`、`ubuntu`、`git` 還有另外幾百個名字。真正會改變結果的措施有三個:只用金鑰,並設 `PasswordAuthentication no`——這個選項在 OpenSSH 文件裡的預設值是 `yes`,而各發行版兩個方向都改過,所以請去讀正在跑的設定,不要用猜的;`PermitRootLogin` 最寬也只到文件預設的 `prohibit-password`,能設 `no`更好;再加一個像 fail2ban 這樣的速率限制,讓來源位址失敗幾次就被封鎖,它主要幫你換來的是看得懂的紀錄。把 daemon 搬到高位連接埠可以大幅減少雜訊,但幾乎沒有減少風險,因為針對性的掃描幾秒鐘就找得到。真正有效的是在防火牆上收緊來源位址、把整批機器藏在一台用 `ProxyJump` 走的跳板後面讓只有它在 22 上回應,或是乾脆要求先連 VPN。不管選哪一個,都要從一個已經登入的第二工作階段去驗證——每一次把自己鎖在門外,都是從「只用重新連線來確認的變更」開始的。

服務
SSH
傳輸協定
TCP
登記狀態
IANA 有指派
分類
遠端連線

站上可以搭配的工具

這些全都在你的瀏覽器裡跑,不會上傳任何東西。

相關連接埠

查 22 的時候,通常也會順手看一下這幾個。

常見問題

明明就有東西在用,指令卻什麼都沒印出來?

幾乎都是權限問題。lsofss 會列出 socket,但別人的行程它不會顯示所有者,所以由系統帳號、容器執行環境或 launchd 啟動的服務,在你補上 sudo 之前就只是一個沒有主人的監聽項。Windows 則是反過來:netstat 什麼都沒有,綁定卻還是失敗,那代表這個號碼落在 Hyper-V、WSL2 或 Docker Desktop 開機時預留的範圍裡。

占著連接埠的那個行程可以直接砍掉嗎?

先看清楚它是什麼。沒收乾淨的開發伺服器砍掉沒事;正在寫入的資料庫不行,其他東西依賴的系統服務也不行。如果持有者是容器,請停容器,不要砍主機看到的那個行程——砍了執行環境只會把它拉起來。遇到真的不能動的,把自己的服務換一個連接埠反而更快。

為什麼本機連得到,別台機器就連不到?

因為它綁在 127.0.0.1 而不是 0.0.0.0。每一頁的指令之所以會把綁定位址跟行程名一起印出來,就是為了這件事:綁在回送位址上的服務,不管防火牆怎麼設,都只有這台機器自己連得到。現在不少框架是刻意這樣預設的,所以通常是一個參數的問題,不是 bug。如果已經是 0.0.0.0 還是不通,下一個要懷疑的就是主機防火牆或雲端的安全群組。

把服務換到冷門的連接埠會比較安全嗎?

幾乎沒有幫助。掃全網的機器持續在掃整段範圍,換號碼買到的是幾個小時,不是安全,代價卻是每個同事都得記住它。它確實能讓針對預設埠的無差別掃描少污染一點日誌,這算是實際但有限的好處。真正會改變結果的是認證、限制來源位址的防火牆,以及一開始就不要讓它對外。

連接埠 22 還是卡住嗎?看完整的連接埠對照表,或是回到上面,從你實際看到的那行錯誤往回追。