實測環境與硬體規格
| 項目 | 實際測試配置 |
| 測試日期 | 2026-10-02 |
| 作業系統 | Ubuntu 24.04.5 LTS |
| 主機數量 | 1 台新建隔離 VM;下列資源為每台配置 |
| CPU | 2 vCPU |
| 記憶體 | 4 GiB |
| 系統磁碟 | 32 GiB;HDD 儲存、VirtIO、ext4 |
| Linux 核心 | 6.8.0-139-generic |
| systemd | 255.4-1ubuntu8.17 |
把腳本交給 systemd 管理,以專用帳號執行、限制可寫路徑,再用 timer 排程。實測成功、結束碼 7 的故障、修復與重新開機後的持續啟用。
文章目錄
本文以全新 Ubuntu 24.04 隔離主機和合成資料實測。套件來自經過簽章驗證、符合 Noble 的套件來源;沒有使用正式資料庫或正式網站的帳號。讀者請依自己的環境確認來源與版本。
圖中是測試主機實際 bash PTY 的執行紀錄,由瀏覽器呈現;提示符統一為 lab$,執行結果未改寫。文字命令另行保留,方便複製。
一、先建立專用執行帳號與目錄
sudo useradd --system --home /var/lib/demo --shell /usr/sbin/nologin demo
sudo install -d -o demo -g demo -m 0750 /opt/demo /var/lib/demo
sudo tee /opt/demo/tick.sh >/dev/null <<'EOF'
#!/bin/sh
set -eu
date -u +%FT%TZ >> /var/lib/demo/runs.log
echo "demo tick completed"
EOF
sudo chown root:root /opt/demo/tick.sh
sudo chmod 0755 /opt/demo/tick.sh
帳號沒有互動登入 shell,腳本由 root 管理,執行結果寫入專用資料目錄。這個例子每次只寫一行時間,沒有網路服務或需要公開的秘密。
二、使用 oneshot 服務與必要的可寫路徑
# /etc/systemd/system/demo.service
[Unit]
Description=Tutorial oneshot task
[Service]
Type=oneshot
User=demo
Group=demo
ExecStart=/opt/demo/tick.sh
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/demo
Type=oneshot 適合執行後結束的任務;這次沒有 RemainAfterExit,成功執行後顯示 inactive 是正常的。判斷成功要看 Result=success 與 ExecMainStatus=0,不能只看是否 active。
三、建立每天的 timer
# /etc/systemd/system/demo.timer
[Unit]
Description=Tutorial timer
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
Unit=demo.service
[Install]
WantedBy=timers.target
sudo systemd-analyze verify /etc/systemd/system/demo.service /etc/systemd/system/demo.timer
sudo systemctl daemon-reload
sudo systemctl enable --now demo.timer
sudo systemctl start demo.service
systemctl show demo.service -p Result -p ExecMainStatus
systemctl is-enabled demo.timer
sudo journalctl -u demo.service -n 5 --no-pager -o cat

日曆時間依主機時區解讀;本次 VM 時區是 Asia/Taipei,腳本紀錄則用 UTC。Persistent=true 可讓符合條件的錯過日曆任務在 timer 再啟動時補做;它不是任務重試或保證每一輪都成功的機制。
四、立即實測觸發,避免只驗證設定存在
sudo systemd-run --unit=demo-trigger-verified --on-active=3s \
--timer-property=AccuracySec=1ms /usr/bin/systemctl start demo.service
sudo tail /var/lib/demo/runs.log
本次觀察到新的實際寫入時間,證明 timer 真的呼叫服務。加上 AccuracySec=1ms 是短時間測試用,避免預設合併喚醒的容許時間影響判斷;每天的 timer 仍保留一般設定。測試時等到新紀錄出現才判定通過,沒有把設定已啟用當作執行成功。
五、重現失敗並查看真正的結束碼
sudo tee /opt/demo/fail.sh >/dev/null <<'EOF'
#!/bin/sh
exit 7
EOF
sudo chmod 0755 /opt/demo/fail.sh
sudo tee /etc/systemd/system/demo-fail.service >/dev/null <<'EOF'
[Service]
Type=oneshot
User=demo
ExecStart=/opt/demo/fail.sh
EOF
sudo systemctl daemon-reload
sudo systemctl start demo-fail.service
systemctl show demo-fail.service -p Result -p ExecMainStatus

此處啟動服務失敗是預期結果;ExecMainStatus=7 對應腳本結束碼。修復腳本後,再清除失敗狀態並重新啟動:
sudo tee /opt/demo/fail.sh >/dev/null <<'EOF'
#!/bin/sh
echo "repaired task completed"
EOF
sudo chmod 0755 /opt/demo/fail.sh
sudo systemctl reset-failed demo-fail.service
sudo systemctl start demo-fail.service
systemctl show demo-fail.service -p Result -p ExecMainStatus
六、重新開機後檢查兩件事
systemctl is-enabled demo.timer
systemctl is-active demo.timer
systemctl list-timers demo.timer --no-pager
sudo systemctl start demo.service
systemctl show demo.service -p Result -p ExecMainStatus
本次重新開機後 timer 仍 active,任務仍可執行。正式使用時應再加入失敗通知、重試政策與資料備份;日誌如果含憑證或業務資料,不能直接貼到公開網站。
這次驗證了什麼
| 驗證項目 | 結果 |
| 專用帳號的 oneshot 任務成功 | 通過 |
| timer 設定與啟用通過 | 通過 |
| 三秒實際觸發有新執行紀錄 | 通過 |
| 結束碼 7 的失敗可重現 | 通過 |
| 修復後結束碼 0 | 通過 |
| 重新開機後 timer 正常 | 通過 |
實測範圍:真正觸發的是三秒的加速測試 timer,並驗證日曆設定與開機啟用;沒有等到隔天 03:30,也未測長期排程準時性、外部通知或所有 sandbox 選項的攻擊抵抗。