SSH远程连接进阶:免密登录、跳板机、端口转发

2225 字
11 分钟
SSH远程连接进阶:免密登录、跳板机、端口转发

SSH 不仅仅是 ssh user@ip,进阶用法包括:密钥认证免密登录、~/.ssh/config 多主机管理、ProxyJump 跳板穿越、本地/远程/动态端口转发、SSHFS 远程挂载。本文覆盖这些技巧的完整配置和常见坑,附 6 个踩坑记录。

实测环境:Debian 12 客户端 + Ubuntu 22.04 服务器,OpenSSH 9.6。

1. 密钥认证——告别密码#

1.1 生成密钥对#

Terminal window
# 推荐 ed25519(比 RSA 更快更安全)
ssh-keygen -t ed25519 -C "bioinfo@lab-server"
# 一路回车即可(或设个密码保护私钥)
# 默认生成:~/.ssh/id_ed25519(私钥)和 ~/.ssh/id_ed25519.pub(公钥)

如果你用的是旧系统只支持 RSA:

Terminal window
ssh-keygen -t rsa -b 4096 -C "bioinfo@lab-server"

1.2 把公钥上传到服务器#

Terminal window
# 方法1:ssh-copy-id(最简单)
ssh-copy-id user@192.168.1.100
# 方法2:手动追加(适用于权限受限的环境)
cat ~/.ssh/id_ed25519.pub | ssh user@192.168.1.100 \
'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys'

上传完测试一下:

Terminal window
ssh user@192.168.1.100
# 应该不用密码直接进去了

1.3 安全加固#

在服务器上编辑 /etc/ssh/sshd_config

Terminal window
# 禁用密码登录(配好密钥后再做!)
PasswordAuthentication no
# 禁用 root 直接登录
PermitRootLogin no
# 改个非标准端口(减少暴力破解)
Port 2222
# 重启 sshd
sudo systemctl restart sshd

⚠️ 在禁用密码登录前一定确认密钥能用,保留一个已登录的终端窗口以防万一。

2. ~/.ssh/config——多主机管理神器#

经常要连多台服务器:集群登录节点、数据存储服务器、云上的 GPU 实例……每次都敲一长串 IP 和参数太累了。~/.ssh/config 解决这个问题。

~/.ssh/config
Host cluster
HostName 192.168.1.100
User bioinfo
Port 22
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
Host gpu-server
HostName 10.0.0.50
User zhang
Port 2222
IdentityFile ~/.ssh/gpu_key
Host cloud-node
HostName ec2-11-22-33-44.compute-1.amazonaws.com
User ubuntu
IdentityFile ~/.ssh/aws_key.pem

配好后登录就简单了:

Terminal window
# 之前
ssh zhang@10.0.0.50 -p 2222 -i ~/.ssh/gpu_key
# 之后
ssh gpu-server

ServerAliveInterval 60 是防止连接因空闲被断开——每 60 秒发一个心跳包,对尤其重要(跑个 BWA 就要几小时,回来发现终端断了真的很崩溃)。

3. 跳板机——访问内网集群#

很多学校/公司的计算集群只开放一个跳板机(bastion)对外,集群节点都在内网。你需要先 SSH 到跳板机,再从跳板机跳到计算节点。

3.1 传统做法(两次 SSH)#

Terminal window
ssh user@bastion.example.com # 先到跳板机
ssh compute-node-01 # 再从跳板机跳到计算节点

每次传文件还得 scp 两次,烦。

3.2 ProxyJump——一步到位#

~/.ssh/config
Host bastion
HostName bastion.example.com
User bioinfo
Host compute-01
HostName 10.0.1.10
User bioinfo
ProxyJump bastion
# 或 ProxyJump user@bastion.example.com

配置好之后直接 ssh compute-01,SSH 会自动经过跳板机转发,你感觉不到中间那层。

3.3 scp/rsync 也支持跳板#

Terminal window
# scp 通过跳板传文件到内网节点
scp -o ProxyJump=user@bastion.example.com data.txt compute-01:/data/
# rsync 同理
rsync -avz -e 'ssh -J user@bastion.example.com' ./results/ compute-01:/data/results/

如果你在 ~/.ssh/config 里配好了 ProxyJump,连 -J 都不用加——直接 scp data.txt compute-01:/data/ 就行。

3.4 多层跳板#

有的环境需要穿两层甚至三层:

~/.ssh/config
Host gateway
HostName gw.example.com
User bioinfo
Host internal
HostName 10.0.0.5
User bioinfo
ProxyJump gateway
Host deep-node
HostName 192.168.1.50
User bioinfo
ProxyJump internal # 自动处理:local → gateway → internal → deep-node

SSH 会按 ProxyJump 链条自动建立隧道,你只需要 ssh deep-node

4. 端口转发——生信三大场景#

4.1 本地端口转发(-L):把远程服务映射到本地#

最常见的场景:你在服务器上起了 Jupyter Notebook 或 RStudio Server,想在本地浏览器打开。

Terminal window
# 在本地执行:把远程8888端口映射到本地8888
ssh -L 8888:localhost:8888 user@server
# 然后在本地浏览器打开 http://localhost:8888
# 就像 Jupyter 跑在本地一样!

格式:-L 本地端口:目标主机:目标端口。这里的 localhost 是相对于服务器的(从服务器角度看的目标主机)。

生信实战:访问集群内网的数据库

Terminal window
# UCSC Genome Browser 在集群内网的一台机器上跑着
# 映射到本地
ssh -L 8080:internal-db:8080 user@bastion
# 本地浏览器访问 http://localhost:8080 即可

4.2 远程端口转发(-R):让外面能访问你本地的服务#

和内网穿透一个道理。比如你在笔记本上跑了一个数据可视化服务,想让服务器上的同事也能看:

Terminal window
# 在本地执行:把本地的3000端口暴露到服务器的9000端口
ssh -R 9000:localhost:3000 user@server
# 同事在服务器上访问 http://localhost:9000 就能看到你的可视化

生信场景: 你在本地分析数据用 RStudio,想让合作者在远程服务器上看到你的结果。或者反过来——帮远程同事调试环境。

4.3 动态端口转发(-D):SSH 当 SOCKS 代理#

Terminal window
# 在本地起一个 SOCKS5 代理
ssh -D 1080 user@server
# 浏览器或程序配置代理:SOCKS5, 127.0.0.1:1080
# 之后所有流量都走服务器出去

生信场景:服务器有学校订阅的期刊数据库访问权限,你在家办公时通过 -D 代理就能访问付费文献。

5. SSHFS——把远程目录挂载到本地#

有时候你不想 scpscp 去,而是想直接把远程目录当本地盘操作:

Terminal window
# 安装
sudo apt install sshfs -y
# 挂载远程目录
mkdir ~/remote_data
sshfs user@server:/opt/bioinfo/data ~/remote_data
# 之后就能像操作本地文件一样操作远程文件
ls ~/remote_data/
cp ~/remote_data/sample.fastq.gz ./
# 卸载
fusermount -u ~/remote_data

生信场景: 用本地 IDE(VS Code/PyCharm)直接打开远程服务器上的代码目录编辑,像本地项目一样方便。VS Code 的 Remote-SSH 插件其实底层也是类似原理。

6. 防止断线——tmux/screen + SSH#

跑一个比对要 8 小时,如果 SSH 断线,进程会收到 SIGHUP 信号被杀死。解决方案:tmux 或 screen。

Terminal window
# 1. 先 SSH 到服务器
ssh user@server
# 2. 启动 tmux 会话
tmux new -s pipeline
# 3. 在 tmux 里跑你的任务
bwa mem -t 8 /opt/refs/hg38.fa sample_R1.fastq.gz sample_R2.fastq.gz | \
samtools sort -o sample.bam
# 4. 按 Ctrl+B 然后 D 分离(detach),任务继续在后台跑
# 5. 你可以关掉 SSH,回家,第二天重新连上
ssh user@server
tmux attach -t pipeline # 恢复会话,看到任务已经跑完了

ServerAliveInterval 能防止空闲断开,但防不了网络波动。tmux 才是真正的断线保护。

7. 踩坑记录#

坑1:authorized_keys 权限错误导致密钥认证失败#

症状:密钥明明配好了,SSH 还是要密码。

排查:

Terminal window
# 在服务器上检查权限
ls -la ~/.ssh/
# authorized_keys 应该是 600(-rw-------)
# .ssh 目录应该是 700(drwx------)
# 修复
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

SSH 对权限极其敏感。权限太宽松(如 644 或 777)会被直接拒绝。

坑2:ProxyJump 连接卡住不动#

症状:ssh -J bastion compute-01 卡住,没有任何错误信息。

原因多半是跳板机上没装 netcat 或 ProxyJump 的转发被中间某层防火墙 block 了。解决方法:

Terminal window
# ~/.ssh/config 用 ProxyCommand 替代 ProxyJump(更兼容)
Host compute-01
HostName 10.0.1.10
User bioinfo
ProxyCommand ssh -W %h:%p bastion

-W %h:%p 是 SSH 的内置转发模式,不需要 netcat,兼容性更好。

坑3:端口转发时端口已被占用#

Terminal window
ssh -L 8888:localhost:8888 user@server
# bind [127.0.0.1]:8888: Address already in use
# 查谁在用
lsof -i :8888
# 或者杀掉占用的进程
# 或者换个本地端口
ssh -L 9999:localhost:8888 user@server

坑4:sshfs 断连后目录卡死#

症状:网络断开后,挂载目录 ls 直接卡死,Ctrl+C 都退不出来。

Terminal window
# 强制卸载
fusermount -uz ~/remote_data
# 如果还不行
sudo umount -l ~/remote_data

-u 是 unmount,-z 是 lazy(延迟卸载),-l 更暴力。sshfs 对网络稳定性要求高,长时操作建议 rsync 代替挂载。

坑5:ServerAliveInterval 设太短被服务器踢#

症状:ServerAliveInterval 60 设了,但服务器那边 ClientAliveCountMax 配合 ClientAliveInterval 算出来的超时时间更短,还是被踢。

其实 ServerAliveInterval 是客户端心跳,服务器端也有自己的超时策略。最佳实践是客户端和服务器都配置:

Terminal window
# 客户端 ~/.ssh/config
ServerAliveInterval 60
ServerAliveCountMax 5 # 连续5次没响应才断开 = 5分钟容忍
# 服务器 /etc/ssh/sshd_config
ClientAliveInterval 120
ClientAliveCountMax 3

坑6:把私钥发到了群聊里#

这个不算技术坑,但我觉得必须说——。私钥绝对不能分享,就像银行卡密码一样。 公钥(.pub 结尾)可以随便发,那是用来贴到 authorized_keys 里的。

如果不小心泄露了私钥,立刻在服务器上删掉对应的公钥行,生成新密钥对。

8. 小结#

需求命令/配置秘诀
免密登录ssh-keygen + ssh-copy-id权限必须 600
多主机管理~/.ssh/config 配 Host 别名告别记 IP
跳板穿透ProxyJump bastion一行配置,多层穿透
本地转发ssh -L 8888:localhost:8888映射远程服务到本地
远程转发ssh -R 9000:localhost:3000暴露本地服务到远程
SOCKS代理ssh -D 1080走服务器上网
远程挂载sshfs user@server:/data ~/mnt当本地盘用
断线保护tmux/screenSSH断了任务继续跑

SSH 是每天接触最多的工具之一,把这些用熟了,每天至少省 15 分钟。下一期写 Linux 进程管理——htop/ps/kill/nice 把服务器管明白


本文于 2025-06-18 在 Debian 12 上实测完成。OpenSSH 9.6,tmux 3.4。所有配置可直接使用。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

SSH远程连接进阶:免密登录、跳板机、端口转发
https://fg.ink/posts/ssh-advanced-bioinfo/
作者
风观
发布于
2024-10-15
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
风观
风有来路,观有所思
分类
标签
站点统计
文章
50
分类
1
标签
29
总字数
61,837
运行时长
0
最后活动
0 天前

文章目录