/etc/rc.local(或 /etc/rc.d/rc.local)是 SysV init 時代留下的「使用者自訂啟動腳本」入口。雖然 systemd 已成為主流,但 rc.local 因其簡單直觀,仍被大量腳本、容器啟動指令、廠商專屬安裝程式依賴。本文解析 rc.local 在傳統啟動流程中的位置、systemd 兼容機制、常見坑點與現代替代方案。
/etc/inittab/etc/rc.d/rc.sysinit(系統級初始化:網路、swap、fsck、hostname...)/etc/rc.d/rcN.d/(N = 0-6)S* 開頭腳本啟動服務/etc/rc.d/rc.local(使用者自訂,S99local 或直接在 inittab 呼叫)
# 1. 建立檔案並賦予執行權限
touch /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
# 2. 在各運行等級建立 S99 連結(確保最後執行)
for i in {1..5}; do
ln -sf /etc/rc.d/rc.local /etc/rc.d/rc${i}.d/S99rc.local
done
# rc0.d/rc6.d 通常不需啟動,可建 K99 關閉腳本
systemd 提供 rc-local.service 兼容單元:
# /usr/lib/systemd/system/rc-local.service
[Unit]
Description=/etc/rc.d/rc.local Compatibility
After=network.target
[Service]
Type=forking
ExecStart=/etc/rc.d/rc.local start
TimeoutSec=0
RemainAfterExit=yes
GuessMainPID=no
[Install]
WantedBy=multi-user.target
# 1. 確保 rc.local 存在且可執行
chmod +x /etc/rc.d/rc.local
# 2. 啟用兼容服務
systemctl enable rc-local.service
systemctl start rc-local.service
# 3. 驗證
systemctl status rc-local.service
journalctl -u rc-local.service
| 規範 | 說明 | 錯誤範例 | 正確範例 |
|---|---|---|---|
| Shebang | 首行必須指定解釋器 | 無首行 | #!/bin/bash |
| 絕對路徑 | 所有命令、腳本、配置檔使用絕對路徑 | ./start.sh | /opt/app/start.sh |
| 環境變數 | 明確 export PATH、HOME、LANG 等 | 依賴繼承環境 | export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin |
| 後台執行 | 長期運行程序必須 & 或 nohup,並重導向輸出 | /opt/app/server | nohup /opt/app/server >/var/log/app.log 2>&1 & |
| PID 管理 | 建議寫入 PID 檔,便於停止/重啟腳本管理 | 無 | echo $! > /var/run/myapp.pid |
| 錯誤處理 | 關鍵步驟檢查返回碼,失敗記錄日誌並決定是否中止 | 無檢查 | if ! mount /data; then logger "mount failed"; exit 1; fi |
| SELinux | 自定腳本需正確標籤或放行 | 拒絕執行 | restorecon -v /etc/rc.d/rc.local |
#!/bin/bash
# /etc/rc.d/rc.local
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
export LANG=en_US.UTF-8
# 1. 掛載遠端儲存
mount -t nfs 192.168.1.100:/data /mnt/nfs -o rw,hard,intr 2>>/var/log/rc.local.log
# 2. 設定核心參數(補充 sysctl.conf)
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
echo 65535 > /proc/sys/fs/file-max
# 3. 啟動自製服務(非 systemd 管理)
nohup /opt/myapp/bin/server -c /opt/myapp/conf/app.yml \
>>/var/log/myapp.log 2>&1 &
echo $! > /var/run/myapp.pid
# 4. 防火牆規則(若 firewalld 未就緒)
iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
# 5. 同步硬體時鐘
hwclock --hctosys
exit 0
新專案強烈建議直接撰寫 systemd 單元檔,優勢:
After=、Requires=)Restart=on-failure)MemoryLimit=、CPUQuota=)journalctl -u myservice)PrivateTmp=yes、NoNewPrivileges=yes)
# /etc/systemd/system/myapp.service
[Unit]
Description=My Custom App
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/server -c /opt/myapp/conf/app.yml
Restart=on-failure
RestartSec=5
StandardOutput=append:/var/log/myapp.log
StandardError=append:/var/log/myapp.err
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now myapp.service
rc.local 是「逃生艙」而非「標準艙」。存量系統維持現狀無妨,但請遵守「絕對路徑、環境變數、後台管理、PID 記錄、SELinux」五大鐵律。增量開發請直接擁抱 systemd 單元檔,享受聲明式服務管理的完整紅利。