目录


SSH 隧道基础概念

什么是 SSH 隧道?

SSH 隧道(SSH Tunnel)是一种通过 SSH 协议建立的安全网络连接通道。它允许你通过一个安全的 SSH 连接来传输其他协议的数据,就像建立了一条”地下通道”。

1
2
你的电脑 ←→ [SSH 隧道] ←→ 目标服务器
安全加密连接 各种服务(数据库、Web等)

为什么需要 SSH 隧道?

  1. 安全性:所有数据都通过 SSH 加密传输
  2. 访问受限资源:绕过防火墙或网络限制
  3. 跳板机访问:通过中间服务器访问最终目标
  4. 本地化远程服务:让远程服务看起来像本地服务

工作原理

1
2
3
应用程序 → 本地端口 → SSH 隧道 → 远程端口 → 目标服务
↓ ↓ ↓ ↓ ↓
数据库客户端 → 3306 → SSH加密传输 → 22 → 远程数据库:3306

SSH 隧道类型详解

1. 本地端口转发(Local Port Forwarding)

概念:将本地端口的流量转发到远程服务器的指定端口。

流量走法:本地–>远程(端口本地监听,流量起点是本地服务器,流量终点是远程服务器。就和访问远程服务器一样,区别就是套了一层SSH加密,可以理解为本地转发就是把流量送出去。)

语法:

1
2
# [本地IP:]可以不填,默认就是localhost
ssh -L [本地IP:]本地端口:目标主机:目标端口 -p 端口 -i 密钥 SSH服务器

示例:

1
2
3
4
5
6
7
8
# 将本地 3306 端口转发到远程服务器的 MySQL
ssh -L 3306:localhost:3306 user@remote-server

# 绑定到所有网卡(允许其他机器访问)
ssh -L 0.0.0.0:3306:localhost:3306 user@remote-server

# 通过跳板机访问第三方服务器,通过访问本地8080达到访问192.168.1.100:80的目的
ssh -L 8080:192.168.1.100:80 user@jumpserver

使用场景:

  • 访问远程数据库
  • 访问内网 Web 服务
  • 绕过防火墙限制

2. 远程端口转发(Remote Port Forwarding)

概念:将远程服务器的端口转发到本地机器的指定端口。

流量走法: **远程–>本地(**远程端口监听,流量起点是远程服务器,流量终点是本地服务器。,可以理解为找了个通往本地服务器的门。)

语法:

1
ssh -R [远程IP:]远程端口:本地主机:本地端口 -p 端口 -i 密钥 SSH服务器

示例:

1
2
3
4
5
# 让远程服务器的 8080 端口转发到本地的 80 端口
ssh -R 8080:localhost:80 user@remote-server

# 让远程服务器可以访问本地的数据库
ssh -R 3306:localhost:3306 user@remote-server

使用场景:

  • 让远程服务器访问本地服务
  • 内网穿透
  • 开发环境共享

3. 动态端口转发(Dynamic Port Forwarding)

概念:创建一个 SOCKS 代理,可以代理多种协议的流量。

语法:

1
ssh -D [本地IP:]本地端口 SSH服务器

示例:

1
2
3
4
5
# 创建 SOCKS 代理
ssh -D 1080 user@remote-server

# 绑定到所有网卡
ssh -D 0.0.0.0:1080 user@remote-server

使用场景:

  • 翻墙上网
  • 代理多种服务
  • 网络调试

实战案例

案例1:通过跳板机连接数据库

场景:需要通过跳板机 192.168.25.88 连接到目标服务器 18.140.243.143 上的 MySQL 数据库。

1
2
3
4
5
6
7
8
# 方法1:一步建立隧道
ssh -L 3306:18.140.243.143:3306 ubuntu@192.168.25.88 -N

# 方法2:使用已配置的 SSH alias
ssh -L 3306:localhost:3306 testsgame-via-jump -N

# 方法3:指定不同的本地端口避免冲突
ssh -L 13306:localhost:3306 testsgame-via-jump -N

连接数据库:

1
2
3
4
5
# 使用命令行客户端
mysql -h 127.0.0.1 -P 3306 -u username -p

# 或连接到不同端口
mysql -h 127.0.0.1 -P 13306 -u username -p

案例2:多端口转发

1
2
# 同时转发多个服务
ssh -L 3306:target:3306 -L 6379:target:6379 -L 5432:target:5432 user@jumpserver -N

案例3:Web 服务访问

1
2
3
4
# 访问内网 Web 服务
ssh -L 8080:internal-web:80 user@jumpserver -N

# 然后在浏览器访问:http://localhost:8080

常用命令和参数

基本命令格式

1
ssh [选项] [用户@]主机名

重要参数详解

参数 说明 示例
-L 本地端口转发 -L 3306:target:3306
-R 远程端口转发 -R 8080:localhost:80
-D 动态端口转发 -D 1080
-N 不执行远程命令,只建立隧道 -N
-f 后台运行 -f
-C 启用压缩 -C
-v 详细输出(调试用) -v
-T 禁用伪终端分配 -T
-o 指定选项 -o ConnectTimeout=10

实用技巧

1. 后台运行隧道:

1
2
3
4
5
# 后台运行,不占用终端
ssh -L 3306:target:3306 user@server -N -f

# 使用 nohup 防止意外断开
nohup ssh -L 3306:target:3306 user@server -N &

2. 自动重连:

1
2
3
4
5
6
7
8
# 使用 autossh(需要安装)
autossh -M 0 -N -L 3306:target:3306 user@server

# 使用循环自动重连
while true; do
ssh -L 3306:target:3306 user@server -N
sleep 5
done

3. 查看和管理隧道:

1
2
3
4
5
6
7
8
9
# 查看所有 SSH 进程
ps aux | grep ssh

# 查看端口占用
lsof -i :3306
netstat -tulpn | grep 3306

# 终止隧道
kill $(lsof -t -i:3306)

SSH 配置文件

基本配置结构

SSH 配置文件位置:~/.ssh/config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 跳板机配置
Host jump-server
HostName 192.168.25.88
User ubuntu
Port 22
IdentitiesOnly yes

# 通过跳板机访问目标服务器
Host target-via-jump
HostName 18.140.243.143
User devx
Port 22
IdentityFile ~/.ssh/id_rsa_target
ProxyJump jump-server
IdentitiesOnly yes

端口转发配置

1
2
3
4
5
6
7
8
# 自动建立端口转发
Host db-tunnel
HostName 192.168.25.88
User ubuntu
LocalForward 3306 18.140.243.143:3306
LocalForward 5432 18.140.243.143:5432
LocalForward 6379 18.140.243.143:6379
ExitOnForwardFailure yes

使用方式:

1
2
# 连接时自动建立所有端口转发
ssh db-tunnel -N

高级配置选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Host *
# 连接超时
ConnectTimeout 10

# 保持连接活跃
ServerAliveInterval 60
ServerAliveCountMax 3

# 压缩传输
Compression yes

# 控制主连接
ControlMaster auto
ControlPath ~/.ssh/control-%r@%h:%p
ControlPersist 10m

故障排查

常见问题和解决方案

1. 端口已被占用

1
2
3
4
5
6
7
# 错误信息
bind: Address already in use

# 解决方案
lsof -i :3306 # 查看占用进程
kill $(lsof -t -i:3306) # 终止占用进程
ssh -L 13306:target:3306 ... # 使用不同端口

2. 连接超时

1
2
3
4
5
6
7
8
# 调试连接
ssh -v user@server

# 常见原因和解决方案
- 防火墙阻止:检查防火墙规则
- DNS 解析问题:使用 IP 地址
- SSH 服务未启动:检查目标服务器 SSH 服务
- 网络不通:使用 ping 和 telnet 测试

3. 认证失败

1
2
3
4
5
6
7
8
# 检查密钥权限
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 700 ~/.ssh

# 测试密钥
ssh-add -l # 查看已加载的密钥
ssh-add ~/.ssh/id_rsa # 手动添加密钥

4. 隧道建立但无法连接

1
2
3
4
5
6
7
8
# 检查隧道状态
netstat -tulpn | grep 端口号

# 检查目标服务是否运行
ssh user@server "netstat -tulpn | grep 3306"

# 检查防火墙
ssh user@server "sudo ufw status"

调试技巧

1. 启用详细输出:

1
2
3
4
ssh -v -L 3306:target:3306 user@server
# -v: 详细模式
# -vv: 更详细
# -vvv: 最详细

2. 测试连接:

1
2
3
4
5
6
# 测试 SSH 连接
ssh -T user@server

# 测试端口连通性
telnet target-server 3306
nc -zv target-server 3306

3. 检查日志:

1
2
3
4
5
# 客户端日志
journalctl -u ssh

# 服务器日志
sudo tail -f /var/log/auth.log

工具集成

配置方法:

  1. 创建连接 → 选择数据库类型

  2. 常规设置:

    1
    2
    3
    4
    5
    连接名:项目数据库
    主机:127.0.0.1
    端口:3306
    用户名:数据库用户名
    密码:数据库密码
  3. SSH 设置:

    1
    2
    3
    4
    5
    6
    ✅ 使用 SSH 隧道
    主机:192.168.25.88
    端口:22
    用户名:ubuntu
    验证方法:公钥
    私钥:选择密钥文件

VS Code SFTP 插件

配置文件:.vscode/sftp.json

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "production",
"host": "192.168.25.88",
"username": "ubuntu",
"agent": "$SSH_AUTH_SOCK",
"remotePath": "/home/devx/project",
"hop": {
"host": "18.140.243.143",
"username": "devx",
"privateKeyPath": "/home/ubuntu/.ssh/id_rsa_target"
}
}

DBeaver 配置

  1. 新建连接 → 选择数据库类型
  2. 主要设置:填写数据库信息
  3. SSH 设置:配置跳板机信息
  4. 测试连接

命令行工具别名

在 ~/.bashrc 或 ~/.zshrc 中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 快速建立常用隧道
alias mysql-tunnel='ssh -L 3306:target:3306 jumpserver -N'
alias redis-tunnel='ssh -L 6379:target:6379 jumpserver -N'
alias web-tunnel='ssh -L 8080:target:80 jumpserver -N'

# 查看隧道状态
alias tunnels='ps aux | grep "ssh.*-L" | grep -v grep'

# 关闭所有隧道
alias kill-tunnels='pkill -f "ssh.*-L"'

# 端口检查
portcheck() {
lsof -i :$1 && echo "Port $1 is in use" || echo "Port $1 is free"
}

安全最佳实践

1. 密钥管理

1
2
3
4
5
6
7
8
9
10
# 生成强密钥
ssh-keygen -t ed25519 -C "your_email@example.com"

# 设置正确权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/*.pub

# 使用密钥代理
ssh-add ~/.ssh/id_ed25519

2. SSH 配置安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ~/.ssh/config 安全配置
Host *
# 只使用指定的密钥
IdentitiesOnly yes

# 连接超时
ConnectTimeout 10

# 禁用某些认证方法
PasswordAuthentication no
ChallengeResponseAuthentication no

# 保持连接但有超时
ServerAliveInterval 60
ServerAliveCountMax 3

3. 服务器安全

1
2
3
4
5
6
7
8
# SSH 服务器配置 /etc/ssh/sshd_config
Port 22 # 考虑更改默认端口
PermitRootLogin no # 禁止 root 登录
PasswordAuthentication no # 禁用密码认证
PubkeyAuthentication yes # 启用公钥认证
MaxAuthTries 3 # 限制认证尝试次数
ClientAliveInterval 300 # 客户端保活间隔
ClientAliveCountMax 2 # 最大保活次数

4. 隧道安全

1
2
3
4
5
6
7
8
# 只绑定到本地回环接口
ssh -L 127.0.0.1:3306:target:3306 server

# 避免绑定到所有接口(除非必要)
# 避免:ssh -L 0.0.0.0:3306:target:3306 server

# 使用防火墙限制访问
sudo ufw allow from 192.168.1.0/24 to any port 3306

5. 监控和日志

1
2
3
4
5
6
7
8
# 定期检查连接
ss -tulpn | grep :22

# 监控日志
sudo tail -f /var/log/auth.log | grep ssh

# 检查失败的登录尝试
sudo grep "Failed password" /var/log/auth.log

总结

SSH 隧道是一个强大的网络工具,可以帮助你:

  • ✅ 安全地访问远程服务
  • ✅ 绕过网络限制和防火墙
  • ✅ 通过跳板机访问内网资源
  • ✅ 保护敏感数据传输

记住关键要点:

  1. -L 用于本地端口转发(最常用)
  2. -N 只建立隧道,不执行命令
  3. -f 后台运行
  4. 使用 SSH 配置文件简化操作
  5. 注意安全和权限设置

通过练习这些示例,你将能够熟练使用 SSH 隧道来解决各种网络访问问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# ssh_config 多站点配置
Host myserver
HostName 192.168.0.100
User dev
IdentityFile ~/.ssh/id_rsa_dev

Host githubdex.com
HostName github.com
User xxx@test.com
IdentityFile ~/.ssh/id_rsa_dex #即使使用openssh key agent 这里填写的也是 ssh-add xxx 时的名称

Host github.com
User username@aliyun.com
IdentityFile ~/.ssh/id_rsa

# WSL中配置一下,并执行下面的命令,宿主机可以连接 localhost:27018
ssh -L 0.0.0.0:27018:localhost:27017 testsgame-via-jump -N
#######################################
## 带跳转
### SSH 自动执行以下逻辑:
### ssh ubuntu@192.168.25.88 -W 18.140.243.143:22
# Jump host configuration
Host jump-server
HostName 192.168.25.88
User ubuntu
Port 22

# Target server via jump host
Host testsgame-via-jump
HostName 18.140.243.143
User devx
Port 22
IdentityFile ~/.ssh/id_rsa_18-140-243-143
ProxyJump jump-server
IdentitiesOnly yes
#######################################