在 Linux 服务器上,通过编写 systemd 单元文件来托管 SSH 隧道进程,是实现开机自启和故障自动重启的标准做法,适合需要长期维持端口转发或安全通道的场景。
先说结论:systemd 能接管进程生命周期,比 crontab 或 nohup 更可靠
- 适合:使用 systemd 初始化系统的 Linux 发行版
- 先准备:配置好 SSH 免密密钥认证
- 验收:通过 systemctl status 确认服务状态
命令速用版
sudo systemctl daemon-reload
sudo systemctl enable ssh-tunnel.service
sudo systemctl start ssh-tunnel.service为什么会这样
SSH 隧道本质上是一个前台运行的进程,如果直接放在后台跑,断网或重启后容易丢失。systemd 作为现代 Linux 的初始化系统,负责管理服务依赖和生命周期。通过编写单元文件,你可以告诉系统这个服务需要在网络就绪后启动,并且在进程意外退出时自动拉起,无需人工干预。
分步处理
1. 准备 SSH 密钥认证
隧道服务无法交互式输入密码,必须使用密钥。在本地生成密钥并公钥上传到服务器:
ssh-keygen -t ed25519
ssh-copy-id user@remote_host确保手动执行 ssh 连接时不需要密码。2. 测试隧道命令
先手动运行一遍隧道命令,确认能通。假设要将远程 8080 端口转发到本地 8080:
ssh -N -L 8080:localhost:8080 user@remote_host注意去掉 -f 参数,因为 systemd 需要前台进程来监控状态。
3. 编写单元文件
创建文件 /etc/systemd/system/ssh-tunnel.service,内容参考:
[Unit]
Description=SSH Tunnel Service
After=network-online.target
Wants=network-online.target
[Service]
User=your_username
ExecStart=/usr/bin/ssh -N -L 8080:localhost:8080 user@remote_host
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target将 your_username 和远程地址替换为实际值。4. 加载并启用
执行以下命令使配置生效并设置开机自启:
sudo systemctl daemon-reload
sudo systemctl enable ssh-tunnel.service
sudo systemctl start ssh-tunnel.service怎么验证是否生效
1. 检查服务状态
运行 systemctl status ssh-tunnel.service,看到 active (running) 表示正常。如果显示 failed,查看下方日志报错。
2. 检查端口监听
使用 ss -tlnp | grep 8080 查看本地是否正在监听指定端口。注意这里使用的是 socket statistics 工具,不是其他代理软件。
3. 验证连通性
尝试访问本地转发的端口,确认数据能通到远程服务。
常见坑
1. 网络依赖问题
如果服务器开机时网络还没好,SSH 连接会失败。务必在 Unit 文件中配置 After=network-online.target 和 Wants=network-online.target,确保网络完全就绪后再启动。
2. 密钥权限错误
SSH 对密钥文件权限很敏感,~/.ssh/id_ed25519 权限应为 600。如果是 root 运行服务,注意密钥属于哪个用户。
3. 主机密钥验证
第一次连接远程主机时会提示确认指纹,这会阻塞服务启动。建议先在手动 ssh 连接时接受指纹,或在命令中加 -o StrictHostKeyChecking=no(需评估安全风险)。
4. 用户权限隔离
Service 中的 User 字段决定了运行身份。如果用普通用户运行,确保该用户有权限读取密钥文件;如果用 root,注意安全风险。