讓機器跑無人值守的長任務
一台機器能被連入、能跑 bootstrap(把它從空機器設定成可用環境的安裝流程)之後,下一個層次是讓它在你不盯著的時候自己跑完一個長任務——一次耗時的編譯、一個批次作業、一個無人值守的 agent。能不能放著走人,取決於有沒有把三件會中斷無人值守執行的事先解決掉:互動提示、斷線即死、結果出不去。這三件是「讓任務能在無人時順利啟動並交付」的障礙;任務跑起來之後的資源耗盡、OOM、額度或憑證到期是另一條軸(執行期的持久性),最後一段會接到那裡。這篇逐一拆解這三個障礙與對應的解法,並說明它們共同的代價判讀——這些便利大多拿安全性換自主性,該不該開要看這台機器的爆炸半徑。
底下用一個具體情境當例子:在一台用完即丟的測試 VM 上,讓 Claude Code 這類 agent 自己跑完一段工作、把成果推回 GitHub 給你早上 review。同一組障礙換成 overnight 編譯或 cron 批次也成立。
障礙一:互動提示擋住自動執行
無人值守的程序沒有人在鍵盤前,所以任何「停下來等你輸入」的提示都會讓它卡死,其中最常見的是 sudo 密碼。一個要裝套件、改系統設定的任務,跑到 sudo 那行就停在密碼提示、永遠等不到輸入,整個任務卡在那裡直到你回來。
解法是讓這台機器的 sudo 免密碼(NOPASSWD),但這是一個明確的安全取捨、不是預設該開的東西。設定方式是給 sudoers 加一條 NOPASSWD 規則:
1echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/20-nopasswd # $(whoami) 會填入你的登入帳號
2sudo chmod 440 /etc/sudoers.d/20-nopasswd開了 NOPASSWD,等於放棄「sudo 密碼」這道在你被入侵或程序失控時的最後防線。判讀軸是這台機器的爆炸半徑——它持有哪些憑證、能觸及哪些系統,也就是最壞情況下會波及多大範圍。一台範圍受限、沒有任何真實憑證、出事就重建的測試 VM,放棄這道防線換取自動執行是划算的;一台共享主機、生產伺服器、或裝著真實憑證與資料的機器,不該為了方便開 NOPASSWD。關鍵是「可不可丟」不等於「爆炸半徑小」:一台用完即丟的 VM,一旦塞進能碰到生產系統或你帳號的憑證,爆炸半徑就不小了——看的不是機器本身,是它最壞情況能波及什麼。
障礙二:SSH 斷線就把任務一起殺掉
直接在 SSH session 裡跑的程序,會隨著 SSH 連線中斷而一起死掉——你闔上筆電、網路斷一下、或單純關掉終端機,正在跑的任務就沒了。對一個要跑好幾小時的無人值守任務,這條等於「你不能離開」,跟無人值守的目的矛盾。
把任務搬進終端機多工器(zellij、tmux 這類,配置見 模組三)就解決了。多工器的 session 活在那台機器上、獨立於你的 SSH 連線:你在多工器裡啟動任務、然後 detach(卸離),任務繼續在機器上跑,你這頭關掉 SSH 都不影響;之後再連回來 attach(接回)就能看它跑到哪。典型流程是連入機器、起多工器、在裡面啟動任務、detach、走人:
1ssh user@host
2zellij # 起多工器(tmux 同理)
3./run-my-long-task.sh # 在裡面啟動你的長任務(換成你的實際指令)
4# 然後 detach:zellij 預設 Ctrl+o 再按 d(tmux 是 Ctrl+b 再按 d)
5# 此時關掉 SSH 不影響任務,它在 host 上繼續跑
6
7# 之後連回來看進度:再 ssh 進去,然後
8zellij attach # tmux 是 tmux attach判讀訊號是「這個任務跑完前,我會不會斷線」。只要會(過夜、跨小時、不穩的網路),就把它放進多工器;幾秒鐘就結束的指令不需要這層。
障礙三:成果推不出去,等於沒做
無人值守任務的產出留在那台機器上,你看不到——除非它能把結果送出去。最常見的形式是把改動 commit 後 push 回 git 遠端,你在別處 pull 來看。但 push 需要認證,而一台剛連入的機器通常還沒設好推送的憑證,於是任務做完了、commit 也建了,卻卡在 push 那步推不出去,你隔天連回來才發現結果根本沒送出去。
先在這台機器上設好推送認證,這個障礙就消失。用 GitHub CLI 是直接的一條路,它認證後會一併把 git 的 credential helper(git 用來自動帶出認證、不必每次手打的機制)設好,後續 git push 就能用——但 gh auth login 本身是互動式的、要你在場完成一次,屬於離開前的人工前置:
1gh auth login # 選 HTTPS、完成認證、同意設定 git 認證判讀軸是「這個任務的價值要怎麼回到你手上」。如果你打算從遠端(GitHub)看結果,那 push 認證就是必要前置——沒設好,整段工作就被困在機器裡。連帶的紀律是讓任務頻繁 commit 當檢查點、做完務必確認 push 成功:對一個你不在場的任務,「沒推出去」跟「沒做」對你是一樣的。機器若沒裝 gh,也可以用 PAT 走 HTTPS,見 外部連入篇 的私有 repo 段。
把 push 憑證設進這台機器,等於提高了它的爆炸半徑——它現在能動你的 repo 了。這會回頭讓障礙一的 NOPASSWD、以及下面 agent 段的權限放行更該謹慎:最壞情況從「弄壞這台機器」升級成「污染你的 repo」,而後者不是重建一台 VM 就能還原的。所以設了 push 憑證之後,要連帶重估前面那些「因為機器可丟所以放心」的取捨。
額外一層:宿主暫停會連帶停掉任務
當這台機器是跑在某個宿主上的虛擬機,還有一個容易忽略的中斷源:宿主睡著,VM 跟著暫停,裡面的無人值守任務也一起停。你以為它整夜在跑,回來發現它從你離開那刻就凍在那裡。判讀方式是想一下「這台機器的存在依賴什麼」——VM 依賴宿主醒著、雲端主機依賴帳單沒欠費。對 VM 的情況,離開前確保宿主不會自動睡眠(macOS 用 caffeinate、Linux 宿主用 systemd-inhibit 或停用 suspend、Windows 調電源設定,或直接關掉節能的自動睡眠)。
如果無人值守的工作者是 AI agent
當你放著跑的是一個 AI agent,除了上面三個障礙,還多一個它自己的互動提示要處理:agent 預設會在每個有風險的動作前停下來問你確認,而無人值守時沒人回答,它就卡住。對應的是 agent 的「跳過確認」模式(如 Claude Code 的權限放行旗標),讓它不停下來問。這跟 NOPASSWD 是同一類取捨、判讀軸也一樣:放給一個無人盯著的 agent 在一台範圍受限、用完即丟的機器上自主動作是可接受的;在一台有真實資料或共享的機器上不該這樣。降低風險的兩個做法是把 agent 的工作範圍用清楚的指引限定(只動哪些目錄、別碰系統其他地方),以及讓它在分支上做、產出交給你 review,而不是直接動到你會依賴的東西。
下一步
把這三到四個障礙解決掉,一台機器就能在你離開後自己跑完工作、把成果送回你手上。這篇是 外部連入(怎麼連進去)的延伸——從「我連進去手動操作」進到「我設好讓它自己跑」。而要讓那個無人值守的任務在失敗時還留得下可診斷的痕跡,回到 可除錯的 bootstrap 的原則:無人盯著的任務尤其需要把可觀測性內建進去,因為你不在場、只能事後從 log 重建發生了什麼。