推荐使用systemd服务单元文件实现开机自启:创建/etc/systemd/system/myapp.service,配置unit[install]三段,明确声明after、user、workingdirectory、execstart等关键项,执行daemon-reload后enable启用。

直接结论:别再往 /etc/rc.local 里塞脚本了,systemd 是唯一可靠、可审计、可依赖的开机自启动方案。
为什么 rc.local 不推荐用
它在 systemd 环境下只是个兼容层,不保证执行时机(可能早于网络、磁盘挂载完成),没有依赖控制,失败也不报错,日志难查。很多发行版(如新版 Ubuntu/Debian)默认甚至禁用该机制。
- systemd 会忽略
/etc/rc.local中对未就绪资源(如/mnt/data或eth0)的访问 - 脚本中用
sleep 10等“硬等待”是反模式,不可靠且拖慢启动 -
rc.local运行在 root 权限但无 cgroup 隔离,出问题可能拖垮整个启动链
写一个最小可用的 .service 文件
以自启一个 Python 脚本为例(比如 /opt/myapp/start.py),必须明确声明依赖和执行环境:
[Unit] Description=My App Starter After=network.target local-fs.target StartLimitIntervalSec=0 [Service] Type=simple User=appuser WorkingDirectory=/opt/myapp ExecStart=/usr/bin/python3 /opt/myapp/start.py Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target
-
After=决定启动顺序,network.target表示等网络就绪,local-fs.target表示等本地文件系统挂载完 -
Type=simple最常用;若脚本自己 fork 出后台进程,得改用Type=forking并配PIDFile= -
Restart=on-failure只在非 0 退出码时重启,避免无限崩溃循环 - 文件必须存为
/etc/systemd/system/myapp.service(不是/lib/systemd/system/,那是只读系统目录)
启用并验证自启动是否生效
写完配置后不能只 systemctl start myapp 就完事,必须走完整流程:
- 重载配置:
sudo systemctl daemon-reload(否则enable会找不到服务) - 启用开机自启:
sudo systemctl enable myapp.service(本质是在/etc/systemd/system/multi-user.target.wants/下建软链接) - 立即测试启动:
sudo systemctl start myapp,再用sudo systemctl status myapp看输出和 exit code - 查启动日志:
sudo journalctl -u myapp -n 50 --no-pager,比tail /var/log/syslog精准得多
注意:systemctl enable 不等于服务已运行,它只管“下次开机”,当前状态需单独 start。
常见坑:路径、权限、环境变量全不对
systemd 的执行环境极干净,默认不加载 /etc/profile、不继承 shell 的 $PATH,连 ~ 都不能直接展开:
- 所有路径必须写绝对路径,
ExecStart=/usr/bin/python3不能写成python3 -
User=指定的用户必须真实存在,且对WorkingDirectory和脚本有读+执行权限 - 需要环境变量?用
Environment=KEY=VALUE一行行写,别指望.bashrc - 想调试?临时加
StandardOutput=journal+console,让输出同时进 journal 和控制台
最隐蔽的问题是 SELinux/AppArmor 限制——即使配置全对,安全模块也可能拦截 ExecStart。先关掉它们测试,确认逻辑没问题再配策略。











