Claude 系統管理員:6 個日常伺服器工作
了解 Claude 能協助完成的 6 類伺服器工作:讀取失敗服務的日誌、撰寫 systemd 單元、檢查 nginx 與 Compose 設定,並掌握絕不可貼上的內容。
Claude for system administrators: 先提供建議,再執行
Claude for system administrators 最適合擔任審查工具。您可以貼上日誌片段、設定檔、不熟悉的命令或錯誤字串,先取得可供核對的說明,再變更伺服器上的任何內容。在您實際執行之前,錯誤答案不會造成損害。因此,讓模型停留在提供建議的一側,是整體安全模型的核心。
在租用的 Linux VPS(virtual private server)上,每週都會遇到 6 類工作。以下每一類都提供可行的提示模式、用來驗證答案的命令,以及應預期的失敗模式。這些工作都不需要模型存取您的伺服器。您可以從瀏覽器分頁,或自己桌面上的視窗貼上內容,因為 Claude 原生支援 Linux,可作為桌面應用程式和 CLI 執行。
在正式環境的伺服器上,順序很重要:先閱讀說明,再自行執行檢查,最後決定是否採取行動。在測試用 VM 上可以使用自主執行。在服務客戶的伺服器上,審查更可靠,因為模型看不到它正在推測的實際狀態。
絕對不可貼上的內容
提示中的所有內容都會離開你的伺服器。以下4類內容必須留在伺服器上:
- 私密金鑰:
~/.ssh/id_ed25519、/etc/ssh/ssh_host_*_key,以及/etc/letsencrypt/live/下的任何 TLS(傳輸層安全性)金鑰。 - 憑證檔案:
.env、~/.aws/credentials、/root/.docker/config.json,以及任何檔案或日誌行中的資料庫密碼。 - 帳戶資料:
/etc/shadow和/etc/gshadow。沒有任何系統管理問題需要密碼雜湊才能回答。 - 任何屬於使用者的內容:電子郵件地址、訂單資料列、包含工作階段 Cookie 或 PII(個人可識別資訊)的請求日誌。
公開金鑰可以貼上。私密金鑰不可以。這兩種檔案乍看之下很相似,因此複製前請先讀取第一行:第一行包含 BEGIN OPENSSH PRIVATE KEY 的檔案絕對不可放入提示中。正確區分 SSH 金鑰資料本身就值得花10分鐘了解。
貼上前先編輯並遮蔽敏感內容,不要依賴自己在200行中找出單一權杖:
sudo journalctl -u myapp -n 200 --no-pager | sed -E 's/(token|secret|password|api[_-]?key)[=:][^[:space:]]+/\1=REDACTED/gI'Docker 有一個特有的陷阱。docker compose config 會將你的 .env 值插入它輸出的內容,因此該輸出本身就是秘密,即使磁碟上的檔案並非秘密。請使用 docker compose config -q;它會驗證內容,但不會輸出任何內容。如需了解允許代理程式查看哪些內容的完整政策,請參閱避免讓 AI 代理程式接觸秘密,其中涵蓋環境層面的做法。
工作 1:這項服務為何失敗?
先執行能提供答案的兩個命令:
systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service -b -n 100 --no-pager -o short-iso貼上這兩個命令的輸出,並補充模型無法猜測的背景資訊:發行版與版本、最近修改的內容、服務是否曾經正常運作,以及故障發生多久。先要求說明機制。
Ubuntu 24.04。myapp.service在我一小時前編輯 unit 之前都正常。以下是systemctl status與最近 100 行 journal。哪一行是第一個真正的錯誤?它代表什麼?先不要提供修正方式。
提示中的「先不要提供修正方式」很重要。日誌通常會把第一次失敗及其引發的重試混在一起,因此要求模型提供修正方式時,它可能只會解釋最後看到的那一行。真正重要的行通常位於雜訊上方約 20 行處。
最後通常會得到類似 Main PID: 1841 (code=exited, status=203/EXEC) 的行。Exit status 203/EXEC 表示 kernel 無法執行 ExecStart 中指定的檔案:路徑不存在,或檔案存在但沒有執行權限。若 #! 行指定的 interpreter 尚未安裝,也會產生相同的狀態。上述情況都可以使用 ls -l 與 head -1 進行驗證。
失敗模式:臆測原因。貼上的內容太少時,模型會以泛用原因補足缺口,例如「連接埠已在使用中」。解法是反問一句:「我提供的內容中,哪一行支持這個判斷?」如果沒有人能在文字中指出原因,這個原因就是猜測。
撰寫 systemd unit 或 cron 項目
提供 unit file 所需的資訊:完整命令、執行時使用的使用者、工作目錄、是否必須等待網路就緒,以及以非零狀態結束時應採取的處理方式。啟用任何項目之前,先確認實際回傳的結果。
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl start myapp.service
systemctl status myapp.service --no-pagersystemd-analyze verify會依照 systemd 的方式解析檔案,因此能找出人眼容易忽略的問題。拼錯的 directive 會輸出 /etc/systemd/system/myapp.service:7: Unknown key name 'Enviroment' in section 'Service', ignoring.。缺少的 binary 會輸出 Command /usr/local/bin/myapp is not executable: No such file or directory。這兩項在 daemon-reload期間都不會顯示錯誤,因此 unit 可能順利載入,卻在實際執行時立即失敗。
撰寫 unit 時,有兩個錯誤特別常見。第一個是 After=network.target。它只表示網路堆疊已設定完成,不代表位址已經存在。服務若繫結至特定 IP,開機時就會因 bind: Cannot assign requested address而失敗。修正方式是搭配 After=network-online.target使用 Wants=network-online.target。第二個是對會 daemonise 的程式使用 Type=simple:systemd 會將第一個程序視為服務,父程序隨即結束,unit 會被標記為已停止,但真正的程序仍在無管理狀態下執行。模型最可能提供這種錯誤,因為它無法只從命令判斷 binary 是否會 fork。因此,在接受草稿前,請先了解 每個 Type= 值向 systemd 保證的行為。
若要檢查排程,不要只讀內容,請實際驗證:
systemd-analyze calendar 'Mon *-*-* 04:00:00'這會輸出正規化後的形式,以及該運算式下次觸發的時間,可直接確認其實際意義。若要在 timer 與 crontab 之間做選擇,VPS 上的 systemd 服務與 timer說明了兩者的取捨。
除非你特別詢問,模型通常不會提醒你 Cron 的這個陷阱。Cron 會以最精簡的環境執行工作,因此 PATH大致等於 /usr/bin:/bin,而且永遠不會讀取 shell profile。某項工作在終端機中貼上執行正常,放到 cron 後卻因 /bin/sh: 1: docker: not found而失敗,原因是該 binary 位於 /usr/local/bin。在 crontab 中使用絕對路徑。如果相較於單行 crontab,unit file 堅持明確寫出使用者、環境與相依條件讓你覺得過於繁瑣,請參閱systemd 要解決的問題,了解這些冗長設定的由來。
工作 3:上線前檢查 nginx 或 Compose 檔案
這項工作的效益最高。貼上檔案,說明預期用途,並要求逐行說明它實際執行的內容。
這個 vhost 應透過 HTTPS 提供example.com,並將/api代理到本機 8080 埠上的服務。請讀回設定內容,並指出任何不符合這項描述的地方。
接著執行了解語法的工具:
sudo nginx -t
docker compose config -qnginx -t 會輸出 nginx: configuration file /etc/nginx/nginx.conf test is successful,或列出檔案名稱與行號,例如 nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12。檔案語法正確時,docker compose config -q 不會輸出任何內容;縮排錯誤時,則會輸出類似 yaml: line 7: did not find expected key 的直接錯誤訊息。
這兩項工具都不會檢查設定意圖。通過 nginx -t 的設定,仍可能將請求代理到錯誤的埠,或在你原本想使用 127.0.0.1 時監聽 0.0.0.0。這個落差正是模型能發揮作用的地方,也是它容易出錯的地方:要求它只修正一個指令時,它往往會重寫整個檔案,並悄悄刪除你原本的兩個指令。請要求它列出變更的行,以及每項變更的原因,然後手動編輯。
確認實際對外暴露的內容:
sudo ss -tulpn如果沒有 sudo,你只能看到正在監聽的 socket,無法看到擁有這些 socket 的程序。如果輸出結果出乎預期,什麼是埠,以及 Linux 如何繫結埠 是較精簡的說明。
工作 4:執行陌生指令前先了解其作用
貼上指令,並針對它提出 4 個問題:每個旗標的作用是什麼、它會寫入什麼、會刪除什麼,以及執行 2 次會發生什麼事。最後一個問題造成的損害,往往比其他問題更嚴重。
以 find /var/log -name '*.gz' -mtime +7 -delete 為例。良好的說明會指出,-mtime +7 會計算完整的 24 小時週期並捨棄零數,因此它會比對至少 8 天前的檔案,而不是 7 天前的檔案。說明也應指出,find 會由左至右計算運算式,因此將 -delete 移到 -name 前面,會刪除起始路徑下的所有內容。第二點在 find 的 man page 中以警告形式列出,而且曾因此讓人失去 /var/log。
再以 rsync -a --delete /srv/app/ /backup/app/ 為例。來源路徑結尾的斜線表示「此目錄的內容」。移除斜線後,結果會是 /backup/app/app/。加入 --delete 後,目的地中來源沒有的內容會被刪除;對鏡像而言這是正確行為,但來源路徑錯誤時就會造成災難。
使用工具驗證,不要依賴模型:
rsync -a --delete --dry-run /srv/app/ /backup/app/ | head -20
find /var/log -name '*.gz' -mtime +7執行 find 時不要加入 -delete,就會取得清單,而不會造成資料遺失。
失敗模式:虛構旗標。模型對於已有 30 年文件紀錄的工具通常可靠,但面對廠商 CLI(command line interfaces)與近期的子命令時可靠度較低,可能產生看似合理、實際不存在的旗標。--help 可在 1 秒內確認結果。引號處理是另一個弱點。因此,當指令包裝 $(...) 運算式時,請閱讀 了解命令替換如何在指令執行前展開,不要直接相信說明。
工作 5:將 shell 歷程轉成操作手冊
你剛花了 2 個小時讓某項功能正常運作。這些知識只存在於終端機回溯內容中,下個月就會消失。
history 200 > /tmp/session.txt讀取該檔案,並在檔案傳送到任何地方前,刪除所有包含密碼、token 或客戶識別碼的行。Shell 歷程是 Linux 主機上最可靠的 secret 尋找位置之一,因為每個人至少都曾經將 secret 直接輸入在命令中。將 HISTCONTROL=ignorespace 設定在你的 ~/.bashrc 中,開頭有空格的命令就完全不會寫入歷程。
能產生可用操作手冊的提示,要求的是檢查,而不只是步驟:
這是一段將全新的 Debian 13 主機設定為可正常運作 Postgres 安裝的 shell 工作階段。請將其整理成編號操作手冊。每個步驟只能有 1 個命令。每個步驟後提供能證明該步驟成功的命令,並說明正常輸出應呈現的內容。標示任何依賴我特定主機的步驟。
失敗模式:整理成過於簡潔的故事。你的工作階段中有 1 個步驟曾經做錯 2 次,之後才修正;模型會將這個步驟平滑帶過,因為省略它後,逐字稿看起來更整潔。將操作手冊與歷程比對,並補回修正內容。模型也會自行編造看似合理的驗證命令,因此請在儲存檔案前執行它寫出的每一項檢查。如果操作手冊涵蓋首次開機,請對照 新 VPS 上的前 10 分鐘 閱讀,避免把已解決的問題整理成更差的版本。
工作 6:將錯誤訊息轉換為修正方法
貼上完整的字串、產生該訊息的命令,以及訊息出現前唯一變更的項目。要求依可能性排序原因,並為每個原因提供一個可區分的命令,讓答案能透過測試驗證。
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)。請依可能性排序原因,並為每個原因提供一個可確認或排除該原因的命令。
這個錯誤的成因沒有歧義:其他程序已經占用 port 80,而 sudo ss -tulpn | grep ':80 ' 會指出該程序。常見情況包括失敗的 reload 留下第二個 nginx master,或 Apache 被當作相依服務載入,並由自己的套件啟動。
失敗模式:透過掩蓋原因來讓修正方法生效。chmod 777、--privileged、停用 SELinux,以及以 root 身分執行服務,都會讓錯誤消失。在模型說明狹隘權限為何不足之前,拒絕任何會放寬權限的修正方法。該說明才是真正的答案。替代方案只能讓錯誤不再顯示。
它可靠地會弄錯的地方
- 它看不到你的伺服器。每個回答都只根據你貼上的內容產生,而且不會告訴你提供的摘錄過短。
- 它對版本的判斷會偏移。套件名稱與預設旗標會隨發行版和版本變更,而模型會將所有版本的資訊平均混在一起。
- 即使錯了,它仍能流暢作答。虛構的運作機制讀起來與正確機制完全相同,因此上述每個原因都附有可用來驗證的命令。
- 在長時間工作階段中,它會失去脈絡。兩小時對話開頭的資訊,到了結尾可能不再影響回答。
最後一點比較像是工作方式的問題,而不完全是模型本身的問題。實際的解法是在長時間 Claude Code 工作階段中管理脈絡:縮短工作階段,每次只處理一項任務。
將代理程式放在伺服器本機
以上內容都只需要複製貼上,因此模型不會接觸你的機器。代理程式在伺服器上執行後,會讀取檔案並執行命令,風險也會隨之改變:錯誤的命令可能導致服務中斷。請為它建立專用的非特權使用者,不要使用 root。熟悉其行為期間,請讓它離開正式環境伺服器,並先建立 snapshot。在 VPS 上安全執行 Claude Code 說明 sandbox 與權限模型。在 tmux 中操作 Claude Code 則處理另一個問題,因為 SSH(secure shell)連線中斷會讓前景代理程式在工作途中停止。請依照建立服務帳號的方式建立此帳號,VPS 上的最小權限使用者 詳細說明了相關做法。
FAQ
Claude 能直接讀取我的伺服器日誌嗎?
不能自行讀取。聊天介面只能看到您貼上的文字。Claude Code 是在伺服器上以命令列工具執行,能以啟動它的使用者權限讀取檔案及執行命令,因此涉及較高的信任層級。一般支援問題只需貼上經過遮蔽的 100 行摘錄,會比授予代理程式 shell 存取權更快速也更安全。
我絕對不應從伺服器貼上哪些內容?
私密金鑰、.env 檔案及其他認證資料儲存區、/etc/shadow,以及任何屬於使用者的資料。日誌摘錄中的 token 在送入提示詞前應先遮蔽。有一種不易察覺的情況:docker compose config 的輸出會將您的 .env 值插入其中,因此請使用 docker compose config -q;它會驗證檔案,但不會輸出任何內容。
讓 Claude 在正式環境 VPS 上執行命令安全嗎?
請將它視為一名不了解環境的新系統管理員:讀取可以,寫入則需要審查。在正式環境中,請先要求它說明原因,再自行執行命令。如果確實要讓代理程式執行命令,請提供一個沒有廣泛 sudo 權限的專用非特權帳號,並先在預備環境的主機上開始。這樣發生錯誤時,代價是重新建置,而不是造成服務中斷。
Claude 為什麼會建議不存在的旗標?
因為它會預測看似合理的文字,而合理的旗標看起來與真實旗標完全相同。這在廠商提供的 CLI 和較新的子命令中最常發生,因為模型所依據的文件內容可能不足,或文件後來已經變更。--help 和 man 才是判定依據;任何會刪除或覆寫資料的命令,都應先執行 dry run。
啟用 systemd unit 前,如何檢查它?
執行 sudo systemd-analyze verify /etc/systemd/system/myapp.service。它會使用 systemd 自身的剖析器解析檔案,回報未知指令及其行號,並標示遺失或不可執行的 ExecStart 二進位檔。接著執行 daemon-reload、start,並閱讀 systemctl status,再執行 enable,因為能順利載入的 unit 仍可能在首次執行時失敗。