SSH 隧道
SSH 隧道、端口转发和安全远程访问。涵盖本地/远程/动态转发、跳板主机、ProxyCommand、多路复用、密钥管理和连接调试。
使用场景
- - 通过防火墙访问远程数据库(本地端口转发)
- 将本地开发服务器暴露给远程机器(远程端口转发)
- 使用远程服务器作为 SOCKS 代理(动态转发)
- 通过堡垒/跳板主机连接
- 管理 SSH 密钥和代理转发
- 安全传输文件(scp、rsync)
- 调试 SSH 连接失败
端口转发
本地转发(在本地访问远程服务)
bash
将本地端口 5432 转发到远程的 localhost:5432
使用场景:像访问本地数据库一样访问远程 PostgreSQL 数据库
ssh -L 5432:localhost:5432 user@remote-server
然后本地连接:
psql -h localhost -p 5432 -U dbuser mydb
转发到远程可访问的其他主机
远程服务器可以访问 db.internal:5432,但你不行
ssh -L 5432:db.internal:5432 user@remote-server
转发多个端口
ssh -L 5432:db.internal:5432 -L 6379:redis.internal:6379 user@remote-server
后台运行(无 shell)
ssh -fNL 5432:db.internal:5432 user@remote-server
-f = 认证后在后台运行
-N = 不执行远程命令
-L = 本地转发
远程转发(在远程暴露本地服务)
bash
让远程服务器上的端口 8080 可以访问你本地的端口 3000
ssh -R 8080:localhost:3000 user@remote-server
在远程:curl http://localhost:8080 → 访问你的本地 :3000
暴露给远程的所有接口(不仅仅是 localhost)
需要在远程 sshd_config 中设置 GatewayPorts yes
ssh -R 0.0.0.0:8080:localhost:3000 user@remote-server
后台模式
ssh -fNR 8080:localhost:3000 user@remote-server
动态转发(SOCKS 代理)
bash
在本地端口 1080 创建 SOCKS5 代理
ssh -D 1080 user@remote-server
通过隧道路由浏览器流量
配置浏览器代理:SOCKS5,localhost:1080
与 curl 一起使用
curl --socks5-hostname localhost:1080 https://example.com
后台模式
ssh -fND 1080 user@remote-server
跳板主机 / 堡垒机
ProxyJump(最简单,OpenSSH 7.3+)
bash
通过堡垒主机连接
ssh -J bastion-user@bastion.example.com target-user@internal-server
链式多跳
ssh -J bastion1,bastion2 target-user@internal-server
通过堡垒机进行端口转发
ssh -J bastion-user@bastion -L 5432:db.internal:5432 target-user@app-server
ProxyCommand(旧系统,更灵活)
bash
等同于 ProxyJump,但适用于旧版 OpenSSH
ssh -o ProxyCommand=ssh -W %h:%p bastion-user@bastion target-user@internal-server
跳板主机的 SSH 配置
~/.ssh/config
堡垒主机
Host bastion
HostName bastion.example.com
User bastion-user
IdentityFile ~/.ssh/bastion_key
内部服务器(自动使用堡垒机)
Host app-server
HostName 10.0.1.50
User deploy
ProxyJump bastion
Host db-server
HostName 10.0.2.30
User admin
ProxyJump bastion
LocalForward 5432 localhost:5432
现在只需:ssh app-server
或者:ssh db-server(自动转发端口 5432)
SSH 配置模式
基本配置
~/.ssh/config
全局默认设置
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
IdentitiesOnly yes
命名主机
Host prod
HostName 203.0.113.50
User deploy
IdentityFile ~/.ssh/prod_ed25519
Port 2222
Host staging
HostName staging.example.com
User deploy
IdentityFile ~/.ssh/staging_ed25519
通配符模式
Host *.dev.example.com
User developer
IdentityFile ~/.ssh/dev_key
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
连接多路复用(复用连接)
~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
第一次连接创建套接字,后续连接复用
对重复的 ssh/scp/rsync 到同一主机更快
bash
创建套接字目录
mkdir -p ~/.ssh/sockets
手动管理控制套接字
ssh -O check prod # 检查连接是否存活
ssh -O stop prod # 关闭主连接
ssh -O exit prod # 立即关闭
密钥管理
生成密钥
bash
Ed25519(推荐——快速、安全、密钥短)
ssh-keygen -t ed25519 -C user@machine -f ~/.ssh/mykey_ed25519
RSA 4096(更广泛的兼容性)
ssh-keygen -t rsa -b 4096 -C user@machine -f ~/.ssh/mykey_rsa
生成无密码密钥(仅用于自动化)
ssh-keygen -t ed25519 -N -f ~/.ssh/deploy_key
部署密钥
bash
将公钥复制到远程服务器
ssh-copy-id -i ~/.ssh/mykey_ed25519.pub user@remote-server
手动方式(如果 ssh-copy-id 不可用)
cat ~/.ssh/mykey
ed25519.pub | ssh user@remote-server mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorizedkeys && chmod 600 ~/.ssh/authorized_keys
SSH 代理
bash
启动代理(通常自动启动)
eval $(ssh-agent -s)
添加密钥到代理
ssh-add ~/.ssh/mykey_ed25519
添加带过期时间的密钥(超时后移除密钥)
ssh-add -t 3600 ~/.ssh/mykey_ed25519
列出已加载的密钥
ssh-add -l
移除所有密钥
ssh-add -D
代理转发(在远程主机上使用本地密钥)
ssh -A user@remote-server
在远程:ssh git@github.com → 使用你的本地密钥
安全提示:只转发到受信任的主机
文件权限
bash
SSH 对权限要求严格。修复常见问题:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 # 私钥
chmod 644 ~/.ssh/id_ed25519.pub # 公钥
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/authorized_keys
文件传输
scp
bash
复制文件到远程
scp file.txt user@remote:/path/to/destination/
从远程复制文件
scp user@remote:/path/to/file.txt ./local/
递归复制目录
scp -r ./local-dir user@remote:/path/to/
通过跳板主机
scp -o ProxyJump=bastion file.txt user@internal:/path/
指定密钥和端口
scp -i ~/.ssh/mykey -P 2222 file.txt user@remote:/path/
通过 SSH 使用 rsync
bash
同步目录(仅更改的文件)
rsync -avz ./local-dir/ user@remote:/path/to/remote-dir/
预演(预览更改)
rsync -avzn ./local-dir/ user@remote:/path/to/remote-dir/
删除远程上本地不存在的文件
rsync -avz --delete ./local-dir/ user@remote:/path/to/remote-dir/
排除模式
rsync -avz --exclude=node_modules --exclude=.git ./project/ user@remote:/deploy/
指定 SSH 选项
rsync -avz -e ssh -i ~/.ssh/deploy_key -p