SSH远程连接进阶:免密登录、跳板机、端口转发
SSH 不仅仅是 ssh user@ip,进阶用法包括:密钥认证免密登录、~/.ssh/config 多主机管理、ProxyJump 跳板穿越、本地/远程/动态端口转发、SSHFS 远程挂载。本文覆盖这些技巧的完整配置和常见坑,附 6 个踩坑记录。
实测环境:Debian 12 客户端 + Ubuntu 22.04 服务器,OpenSSH 9.6。
1. 密钥认证——告别密码
1.1 生成密钥对
# 推荐 ed25519(比 RSA 更快更安全)ssh-keygen -t ed25519 -C "bioinfo@lab-server"
# 一路回车即可(或设个密码保护私钥)# 默认生成:~/.ssh/id_ed25519(私钥)和 ~/.ssh/id_ed25519.pub(公钥)如果你用的是旧系统只支持 RSA:
ssh-keygen -t rsa -b 4096 -C "bioinfo@lab-server"1.2 把公钥上传到服务器
# 方法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'上传完测试一下:
ssh user@192.168.1.100# 应该不用密码直接进去了1.3 安全加固
在服务器上编辑 /etc/ssh/sshd_config:
# 禁用密码登录(配好密钥后再做!)PasswordAuthentication no
# 禁用 root 直接登录PermitRootLogin no
# 改个非标准端口(减少暴力破解)Port 2222
# 重启 sshdsudo systemctl restart sshd⚠️ 在禁用密码登录前一定确认密钥能用,保留一个已登录的终端窗口以防万一。
2. ~/.ssh/config——多主机管理神器
经常要连多台服务器:集群登录节点、数据存储服务器、云上的 GPU 实例……每次都敲一长串 IP 和参数太累了。~/.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配好后登录就简单了:
# 之前ssh zhang@10.0.0.50 -p 2222 -i ~/.ssh/gpu_key
# 之后ssh gpu-serverServerAliveInterval 60 是防止连接因空闲被断开——每 60 秒发一个心跳包,对尤其重要(跑个 BWA 就要几小时,回来发现终端断了真的很崩溃)。
3. 跳板机——访问内网集群
很多学校/公司的计算集群只开放一个跳板机(bastion)对外,集群节点都在内网。你需要先 SSH 到跳板机,再从跳板机跳到计算节点。
3.1 传统做法(两次 SSH)
ssh user@bastion.example.com # 先到跳板机ssh compute-node-01 # 再从跳板机跳到计算节点每次传文件还得 scp 两次,烦。
3.2 ProxyJump——一步到位
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 也支持跳板
# 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 多层跳板
有的环境需要穿两层甚至三层:
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-nodeSSH 会按 ProxyJump 链条自动建立隧道,你只需要 ssh deep-node。
4. 端口转发——生信三大场景
4.1 本地端口转发(-L):把远程服务映射到本地
最常见的场景:你在服务器上起了 Jupyter Notebook 或 RStudio Server,想在本地浏览器打开。
# 在本地执行:把远程8888端口映射到本地8888ssh -L 8888:localhost:8888 user@server
# 然后在本地浏览器打开 http://localhost:8888# 就像 Jupyter 跑在本地一样!格式:-L 本地端口:目标主机:目标端口。这里的 localhost 是相对于服务器的(从服务器角度看的目标主机)。
生信实战:访问集群内网的数据库
# UCSC Genome Browser 在集群内网的一台机器上跑着# 映射到本地ssh -L 8080:internal-db:8080 user@bastion
# 本地浏览器访问 http://localhost:8080 即可4.2 远程端口转发(-R):让外面能访问你本地的服务
和内网穿透一个道理。比如你在笔记本上跑了一个数据可视化服务,想让服务器上的同事也能看:
# 在本地执行:把本地的3000端口暴露到服务器的9000端口ssh -R 9000:localhost:3000 user@server
# 同事在服务器上访问 http://localhost:9000 就能看到你的可视化生信场景: 你在本地分析数据用 RStudio,想让合作者在远程服务器上看到你的结果。或者反过来——帮远程同事调试环境。
4.3 动态端口转发(-D):SSH 当 SOCKS 代理
# 在本地起一个 SOCKS5 代理ssh -D 1080 user@server
# 浏览器或程序配置代理:SOCKS5, 127.0.0.1:1080# 之后所有流量都走服务器出去生信场景:服务器有学校订阅的期刊数据库访问权限,你在家办公时通过 -D 代理就能访问付费文献。
5. SSHFS——把远程目录挂载到本地
有时候你不想 scp 来 scp 去,而是想直接把远程目录当本地盘操作:
# 安装sudo apt install sshfs -y
# 挂载远程目录mkdir ~/remote_datasshfs 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。
# 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@servertmux attach -t pipeline # 恢复会话,看到任务已经跑完了ServerAliveInterval 能防止空闲断开,但防不了网络波动。tmux 才是真正的断线保护。
7. 踩坑记录
坑1:authorized_keys 权限错误导致密钥认证失败
症状:密钥明明配好了,SSH 还是要密码。
排查:
# 在服务器上检查权限ls -la ~/.ssh/# authorized_keys 应该是 600(-rw-------)# .ssh 目录应该是 700(drwx------)
# 修复chmod 700 ~/.sshchmod 600 ~/.ssh/authorized_keysSSH 对权限极其敏感。权限太宽松(如 644 或 777)会被直接拒绝。
坑2:ProxyJump 连接卡住不动
症状:ssh -J bastion compute-01 卡住,没有任何错误信息。
原因多半是跳板机上没装 netcat 或 ProxyJump 的转发被中间某层防火墙 block 了。解决方法:
# ~/.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:端口转发时端口已被占用
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 都退不出来。
# 强制卸载fusermount -uz ~/remote_data
# 如果还不行sudo umount -l ~/remote_data-u 是 unmount,-z 是 lazy(延迟卸载),-l 更暴力。sshfs 对网络稳定性要求高,长时操作建议 rsync 代替挂载。
坑5:ServerAliveInterval 设太短被服务器踢
症状:ServerAliveInterval 60 设了,但服务器那边 ClientAliveCountMax 配合 ClientAliveInterval 算出来的超时时间更短,还是被踢。
其实 ServerAliveInterval 是客户端心跳,服务器端也有自己的超时策略。最佳实践是客户端和服务器都配置:
# 客户端 ~/.ssh/configServerAliveInterval 60ServerAliveCountMax 5 # 连续5次没响应才断开 = 5分钟容忍
# 服务器 /etc/ssh/sshd_configClientAliveInterval 120ClientAliveCountMax 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/screen | SSH断了任务继续跑 |
SSH 是每天接触最多的工具之一,把这些用熟了,每天至少省 15 分钟。下一期写 Linux 进程管理——htop/ps/kill/nice 把服务器管明白。
本文于 2025-06-18 在 Debian 12 上实测完成。OpenSSH 9.6,tmux 3.4。所有配置可直接使用。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!