卡住了看這裡
照著前面幾篇設定,十次有八九次一次就通。剩下那一兩次卡住的地方,通常就是這八種。找到你看到的錯誤訊息跳過去看,不用整篇從頭讀。
連線逾時(Operation timed out)
症狀
打了 ssh 使用者@主機 之後畫面卡住不動,等了半天,最後跳出 Operation timed out 或 Connection timed out,沒有任何輸入密碼的機會。
原因
- host 名稱打錯字,例如打成
my-serverr。這種情況 SSH 通常立刻回報Could not resolve hostname,不會卡著逾時,看到這個訊息就去檢查拼字,不是本節要處理的狀況。真正會卡著逾時的是 IP 打錯——少一段、錯一個數字,連到一個根本沒人回應的地址。 - 對方的 SSH 不是開在標準的 22 port,你少打了
-p。 - 目標機器正在睡眠,或乾脆是關機的。
- 中間有防火牆擋掉了這個連線——家用路由器、公司網路、飯店 Wi-Fi。機器根本沒收到你的請求。
解法
不要用猜的,一段一段確認。先確認機器本身有沒有回應:
ping 主機位址
ping 完全沒回應?先檢查 IP 有沒有打錯,以及對方機器是不是在睡眠或關機。有些機器會刻意擋 ping,所以不通不代表機器真的連不到,直接跳下一步。
接著確認 SSH 這個 port 有沒有真的開著在監聽:
nc -vzw 5 主機位址 22
把 22 換成對方實際使用的 port。-w 5 是最多等 5 秒,免得遇到被擋掉的 port 時整個指令卡住不動、看不出結果。
三種結果。succeeded 或 open:port 是通的,問題在別的地方。Connection refused:機器收得到,但沒有服務在那個 port 上聽。又逾時:中間有東西把封包整個擋掉,通常是防火牆——要檢查的是路由器設定或所在網路的限制,不是伺服器本身。
Permission denied (publickey)
症狀
SSH 連線一發出去馬上被拒絕,畫面直接印出 Permission denied (publickey).,連輸入密碼的機會都沒有。
原因
伺服器不接受你這把金鑰。最常見的原因是公鑰根本沒放到伺服器上。
另一個原因容易被忽略:~/.ssh 這個資料夾或 authorized_keys 檔案的權限太寬鬆。SSH 對這件事非常嚴格。權限不對,它直接整個忽略這個檔案,跟金鑰內容對不對無關。
解法
如果你還沒把公鑰放上去過,最快的方式是用 ssh-copy-id:它會先用密碼登入一次,自動把你本機的公鑰加進伺服器的 authorized_keys。
ssh-copy-id 使用者@主機
這個做法的前提是伺服器的密碼登入還開著;如果密碼登入已經被關掉(見下面 密碼正確卻被拒絕 那節),就需要請能存取這台機器主控台的人,直接把公鑰內容貼進 ~/.ssh/authorized_keys。
如果公鑰確實在裡面——一行一把,內容完整沒被截斷——卻還是被拒絕,多半就是權限。對照下表檢查。最容易漏掉的是最後一行:~/.ssh 和 authorized_keys 都設對了,但家目錄本身「群組」或「其他人」可寫,StrictModes 一樣拒絕:
| 路徑 | 需要的權限 | 指令 |
|---|---|---|
~/.ssh | 700 | chmod 700 ~/.ssh |
~/.ssh/authorized_keys | 600 | chmod 600 ~/.ssh/authorized_keys |
~(家目錄本身) | 群組、其他人不可寫 | chmod go-w ~ |
改完權限後再試一次連線。如果還是不行,可以在本機加上 -v 看詳細過程,確認 SSH 真的有把你預期的那把金鑰送出去:
ssh -v 使用者@主機
輸出會有五、六十行,你只需要其中兩行。Offering public key: ... 代表你的金鑰真的送出去了,本機這邊沒問題。緊接著出現 Authentications that can continue: publickey,代表伺服器收到了這把金鑰但沒接受——金鑰沒放對或權限不對,照上面的步驟繼續查。
密碼正確卻被拒絕
症狀
你很確定密碼打對了(甚至是複製貼上的),但 SSH 一直跳回 Permission denied, please try again.,或者根本沒有讓你輸入密碼的畫面就結束了。
原因
這通常跟密碼對不對無關。伺服器的 SSH 設定把密碼登入整個關掉了(PasswordAuthentication no)。這是很常見的安全設定,目的是強迫所有人用金鑰登入,斷掉暴力猜測那條路。設定成這樣,密碼一百次都打對也不會被接受。
這裡有一個坑,是整頁卡住最久的地方。新一點的系統會在 sshd_config 最上面放一行 Include /etc/ssh/sshd_config.d/*.conf,把那個資料夾裡的設定檔全部讀進來——Ubuntu 22.10 之後、Debian 12,以及幾乎所有雲端主機的預設映像檔。而 sshd 是先讀到哪個值就用哪個,後面的不會蓋掉前面的。
所以只要 /etc/ssh/sshd_config.d/ 底下有個 50-cloud-init.conf 之類的檔案同樣寫著 PasswordAuthentication no,它就比你在主檔案改的那行更早生效。存檔、重啟、還是被拒絕。
解法
優先做法:改用金鑰登入(做法見上面 Permission denied (publickey) 那節,把你的公鑰放到伺服器的 authorized_keys)。
如果你有這台伺服器的管理權限、也確定想開放密碼登入,才去改設定。先確認有沒有其他檔案會蓋掉你等一下要改的值:
sudo grep -r PasswordAuthentication /etc/ssh/sshd_config /etc/ssh/sshd_config.d/
如果 /etc/ssh/sshd_config.d/ 底下也有檔案設定了 PasswordAuthentication,把那個值一起改掉(或直接註解掉那一行),確認乾淨之後,才編輯 /etc/ssh/sshd_config,把 PasswordAuthentication 那一行改成 yes。
先不要關掉你現在這個連線視窗。改壞 sshd 設定可能讓你之後完全連不進這台機器。確認新設定沒問題之前,留著這個視窗當退路。存檔後先驗證語法:
sudo sshd -t
沒有印出任何錯誤,才重新啟動服務讓設定生效:
sudo systemctl restart ssh
部分發行版的服務名稱是 sshd 而不是 ssh。上面那行找不到服務的話,改試 sudo systemctl restart sshd。接著開一個全新的連線視窗——不是你留著當退路的那個——確認真的能用密碼登入。成功了才關掉舊視窗。
整套環境都建立在 Tailscale 上,所以有個比「把密碼登入對整個網際網路開放」更安全的做法:只允許 Tailscale 網段的連線用密碼,其餘來源仍然只能用金鑰。在 sshd_config 尾端加一段:
Match Address 100.64.0.0/10
PasswordAuthentication yes
Match All
PasswordAuthentication no
找不到 tmux
症狀
Agentmux 提示找不到 tmux,或者你自己連上去手動打 tmux 時看到 command not found: tmux。
原因
目標機器上還沒裝 tmux,而這件事不用你自己動手。Agentmux 會偵測這台機器用的是 apt、yum、dnf、pacman、apk(Alpine)還是 brew,然後透過 SSH 跑對應的安裝指令。多數情況你等它跑完就好。
自動安裝失敗,最常見的原因是 sudo。安裝指令裡帶了它,但這條通道是非互動式的,sudo 沒有終端機可以問你密碼(見下面 sudo: a terminal is required to read the password)。其次是在 Mac 上用 Homebrew 安裝但連線身分是 root——Homebrew 設計上就拒絕以 root 執行。
還有一種少見但容易誤判的情況:tmux 已經裝了,只是裝在 Agentmux 探測 PATH 時沒看到的地方——Linuxbrew 裝在 ~/.linuxbrew,或 MacPorts 裝在 /opt/local/bin。訊息一樣是「找不到 tmux」,但問題是 PATH 沒找對地方,不是沒裝。照下面 claude: command not found,但桌面終端機明明可以跑 那節處理。
解法
先看 Agentmux 跳出的錯誤訊息。如果它要你輸入 sudo 密碼、或提到啟用免密碼 sudo,直接把密碼填進去再試一次,通常比自己另外開視窗快。如果這個管道也失敗,或訊息提到終端機、TTY,再照 sudo: a terminal is required to read the password 那節手動處理。處理完通常自動安裝就會成功,不需要再往下做。
只有排除 sudo 問題之後還是裝不起來,才手動安裝:
# Debian / Ubuntu
sudo apt install -y tmux
# RHEL / CentOS
sudo yum install -y tmux
# Fedora
sudo dnf install -y tmux
# Arch
sudo pacman -S tmux
# Alpine
sudo apk add tmux
# Mac(不要用 root 身分執行)
brew install tmux
claude: command not found,但桌面終端機明明可以跑
症狀
你在 Mac 自己開的 Terminal 裡打 claude,指令正常執行。透過 Agentmux 連進去、或直接 ssh 主機 claude,卻看到 claude: command not found(或 bash: claude: command not found)。同一台機器、同一個帳號,結果不一樣。看起來就像 Agentmux 壞了。
原因
不是 Agentmux 的問題,是 shell 的行為。這是整頁最難自己想通的一個卡點,原理值得花點篇幅講清楚,之後遇到類似的你自己就能判斷。
你平常在 Mac 上開的 Terminal 是一個「互動式登入 shell」。claude 找得到,通常是因為 nvm、npm 或安裝工具在某個設定檔裡加了一行,把它所在的目錄放進 PATH。但「哪個設定檔」在 zsh 和 bash 上不一樣,混著講會誤導,分開說:
zsh(Mac 的預設 shell):互動式登入 shell 依序讀 .zshenv → .zprofile → .zshrc → .zlogin。而 ssh 主機 claude 這種執行單一指令的連線,開的是非互動、非登入的 zsh,只會讀 .zshenv,其餘全部跳過——包含大多數人放 PATH 設定的 .zshrc。
bash:情況比較特別,而且這部分的行為因發行版而異,不是統一的 bash 標準行為。互動式登入 shell 讀的是 .bash_profile(或 .profile),不是 .bashrc;你會覺得 bash 也讀 .bashrc,是因為大多數發行版預設的 .bash_profile 裡,會手動加一段「如果 .bashrc 存在就 source 它」。至於 bash 被 sshd 直接叫起來執行單一指令時(也就是 ssh 主機 claude 這種用法)會不會讀 ~/.bashrc,答案要看發行版:這是編譯時期加上去的 SSH_SOURCE_BASHRC 特例,Debian、Ubuntu 以及它們的衍生版有把這個 patch 補進去,非互動的單一指令 shell 也會讀 ~/.bashrc;但 RHEL、Fedora、Arch 這類發行版用的是官方原始版本的 bash,沒有這個特例,同樣的情境下 ~/.bashrc 根本不會被讀到。就算是在會讀的那些發行版上,幾乎每個預設的 .bashrc,開頭也都放了一段判斷:
case $- in
*i*) ;;
*) return;;
esac
意思是「如果現在不是互動模式,就直接結束,不要往下讀」。這段判斷通常寫在檔案最前面,所以即使 bash 真的把 .bashrc 打開了,也會在讀到你加的 PATH 那行之前就先跳出去,效果跟沒讀到一樣。
zsh 還是 bash,結果都一樣。設定 PATH 的那一行只在你自己開 Terminal 時執行過。SSH 執行單一指令時沒讀到它,PATH 裡自然沒有 claude 的位置,shell 當然說找不到。這跟 claude 有沒有裝好無關。它一直都在,只是沒人告訴這個 shell 去哪裡找。
這也不是為了刁難誰。非互動執行時跳過這些設定檔是刻意的設計,免得每跑一段遠端指令都要先載入一堆給人互動用的別名和提示字元設定,多出那麼多出錯的機會。
補充一點。Agentmux 在 Mac 上探測 PATH 用的是 zsh -lc——登入但非互動——一樣跳過 .zshrc,只讀 .zshenv 和 .zprofile。所以對 Mac 上的 zsh 使用者,把 PATH 設定搬到這兩個檔案不只是讓你手動 SSH 找得到指令,更決定了 Agentmux 自己偵不偵測得到 agent 指令的位置。
解法
最快的做法:找出 claude 的絕對路徑,直接用它呼叫,不要依賴 PATH。在平常跑得動 claude 的那個 Terminal 視窗執行:
which claude
會印出類似 /Users/你的名字/.nvm/versions/node/v20.11.0/bin/claude 的一整串路徑。把它填到 Agentmux 要求輸入 agent 指令的欄位,取代原本的 claude。
如果你是用 nvm 裝 node,這條路徑裡帶著版本號,下次升級就失效,得重新用 which claude 抓一次。不想每次升級都改,用下面的長久做法。
比較長久的做法,依你的 shell 分開處理,不要混用:
如果是 zsh(Mac 預設):把設定 PATH 的那幾行從 .zshrc 搬到 ~/.zshenv。那幾行通常來自 nvm、pyenv,或你自己加的 export PATH=...。搬到 ~/.zprofile 也可以,兩個檔案在 SSH 非互動執行和 Agentmux 探測 PATH 時都讀得到。
如果是 bash:搬到 ~/.profile 或 ~/.bash_profile 不會生效。ssh 主機 claude 開的是非登入 shell,這兩個檔案都不會被讀到。
機器是 Debian、Ubuntu 或它們的衍生版的話,把 PATH 那幾行搬進 ~/.bashrc,放在檔案最前面那段 case $- in ... esac 判斷式「之前」,它就會在互動判斷擋下之前先生效。RHEL、Fedora、Arch 這類發行版則不同,~/.bashrc 在這個情境下本來就不會被讀到,改它沒有任何效果。
不確定自己屬於哪一種?用上面的絕對路徑。那個做法每個發行版都有效,也是唯一保證跨發行版都能用的解法。
搬完之後,開一個新的 SSH 連線測試,確認真的生效了:
ssh 主機 'claude --version'
能印出版本號,就代表 PATH 這次真的在非互動 shell 裡也讀到了。
Tailscale 顯示已連線,SSH 仍連不到
症狀
手機上的 Tailscale App 顯示兩台裝置都是綠燈、在線,但用 Agentmux 或直接 ssh 連過去,還是失敗或整個逾時。
原因
- 連線用的是區網 IP(像
192.168.x.x),不是 Tailscale 給的 MagicDNS 名稱或100.x開頭的 Tailscale IP。區網 IP 只有在同一個 Wi-Fi 底下連得到。手機一切到行動網路,這組 IP 就完全無效。 - 對方裝置的狀態其實剛斷線或正在睡眠,Tailscale App 上顯示的「在線」還沒更新。
- Tailscale 本身正常,但目標機器上的 SSH 服務根本沒開或沒啟動。Tailscale 只負責把兩台機器的網路打通,不會幫你把 SSH 服務打開。
- 最常見的真正原因是 node key 過期。目標機器需要重新驗證,App 裡看起來還是綠燈「已連線」,實際上這台機器已經不在網路裡。到 Tailscale 的後台管理主控台查那台機器是不是被標成需要重新登入,重新驗證一次通常就解決了。
解法
手機上的 Tailscale 沒有指令列可以打,tailscale status 只能在目標機器(要被連線的那台 Mac 或 Linux 機器)上執行:
tailscale status
在目標機器上確認清單裡手機那個節點顯示在線。手機這邊打開 Tailscale App,確認目標機器的狀態同樣正常——沒有變灰,也沒有需要重新登入之類的警示。
兩邊都正常的話,連線時一律用 MagicDNS 名稱(例如 mac-mini.tail1234.ts.net)或 tailscale status 列出的 100.x IP,不要用區網 IP。這樣不管你在家裡的 Wi-Fi 還是外面用行動網路,位址都有效。
以上都沒問題,再到目標機器檢查 SSH 服務本身有沒有啟動。Linux 用 sudo systemctl status ssh;Mac 請見下面 Mac 開了遠端登入卻連不上 那節。
Mac 開了遠端登入卻連不上
症狀
已經在系統設定裡打開「遠端登入」,Mac 也確定連著網路,但 SSH 還是連不上;或者連得上卻被拒絕,而你很確定密碼或金鑰都是對的。
原因
- 「遠端登入」預設只允許「特定使用者」清單裡的帳號登入。你用來連線的那個帳號可能根本不在清單上。
- Mac 進入睡眠之後網路介面跟著休眠,SSH 自然連不到。這跟遠端登入有沒有打開無關,是機器當下對網路請求完全沒反應。
解法
打開「系統設定 → 一般 → 共享」。那是 macOS Ventura 之後的路徑,Ventura 之前是「系統偏好設定 → 共享」,沒有「一般」這一層。找到「遠端登入」,確認開關打開,再點進去看「允許存取」的使用者清單裡有沒有你要連線的那個帳號。或者直接選「所有使用者」。
接著打開「系統設定 → 電池」(筆電)或「系統設定 → 節能」(Mac mini、Mac Studio、iMac 這類長期開機當伺服器用的桌機,上面範例裡的 mac-mini.tail1234.ts.net 就是這種)。把「電腦閒置時進入睡眠」的時間調長或關掉。如果面板上有「喚醒以供網路存取」這個選項,一併打開,讓 Mac 就算睡著也能因為收到連線請求而醒過來回應 SSH。
sudo: a terminal is required to read the password
症狀
透過 Agentmux 或 SSH 執行一段包含 sudo 的指令時,指令直接失敗,印出 sudo: a terminal is required to read the password,完全沒有跑起來的跡象。
原因
sudo 正常情況下會在終端機上跳出「輸入密碼:」,等你打完才往下跑。但這段指令如果是透過非互動的管道執行——SSH 遠端執行單一指令,或 Agentmux 背後幫你跑的安裝流程——根本沒有一個真正的終端機可以顯示提示,也沒有地方讓你打字。sudo 發現沒有 TTY 可用就直接拒絕,不會傻等一個永遠不會來的輸入。
這裡有個常見的誤會:以為剛剛才手動用 sudo 打過密碼,接下來一段時間就不用再問。現代 sudo 確實會記錄「已經驗證過」,但那筆記錄綁的是當下那個 TTY(tty_tickets),不是你的帳號,也不是這台機器。
所以你在互動式 SSH 視窗裡輸入過密碼,Agentmux 之後自動跑指令時開的是另一條全新、沒有 TTY 的連線,對 sudo 來說那是完全不同的一筆記錄,一樣要你重新輸入。不是快取過期,是它查的從來就不是同一筆。
解法
先看 Agentmux 跳出的提示。自動安裝失敗時,它通常會直接請你輸入 sudo 密碼、或改成啟用免密碼 sudo,再重試一次。看到那個欄位就把密碼填進去,往往比自己另外處理快。
這個管道不可用的話,就自己手動 SSH 登入那台機器,開一個正常的互動式 session,在裡面執行一次同樣的指令(例如 sudo apt install -y tmux)並輸入密碼,把事情做完。
這會成功,但不是大家以為的那個理由。它沒有幫 Agentmux 之後的自動流程解鎖什麼——如上所說,兩邊查的 TTY 記錄不是同一筆。它會成功只是因為你自己已經把該裝的東西裝好了。下一次的非互動指令再檢查,發現東西已經在,不需要重裝,卡點就消失了。
如果某個特定指令長期都要透過非互動管道免密碼執行,可以用 sudo visudo 幫它加一條 NOPASSWD 規則,只針對那一條指令放行:
你的帳號 ALL=(ALL) NOPASSWD: /usr/bin/apt
這個安全取捨比看起來嚴重。把 NOPASSWD 開給 apt 這類套件管理員,幾乎等於開放完整 root。apt 可以被要求安裝任意套件,而 APT::Update::Pre-Invoke 這類 hook 還能在安裝過程中以 root 身分執行任意指令。這不是限定範圍的低風險放行,是換一種寫法的免密碼 root。
清楚知道這個代價、也刻意接受,才這樣設定。否則寧可回到上面「先手動裝一次」的做法。也絕對不要直接放行 NOPASSWD: ALL,那等於整台機器的 sudo 都不再需要密碼。