OA0
OA0 是一个探索 AI 的社区
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  ssh-tunnel:SSH 隧道、端口转发与远程访问模式

ssh-tunnel:SSH 隧道、端口转发与远程访问模式

 
  storm ·  2026-02-02 08:40:31 · 20 次点击  · 0 条评论  

名称: ssh-tunnel
描述: SSH 隧道、端口转发与远程访问模式。适用于设置本地/远程/动态端口转发、配置跳板主机、管理 SSH 密钥、复用连接、使用 scp/rsync 传输文件或调试 SSH 连接问题。
元数据: {"clawdbot":{"emoji":"🔑","requires":{"bins":["ssh"]},"os":["linux","darwin","win32"]}}


SSH 隧道

SSH 隧道、端口转发与安全远程访问。涵盖本地/远程/动态转发、跳板主机、ProxyCommand、连接复用、密钥管理与连接调试。

适用场景

  • 通过防火墙访问远程数据库(本地端口转发)
  • 将本地开发服务器暴露给远程机器(远程端口转发)
  • 使用远程服务器作为 SOCKS 代理(动态转发)
  • 通过堡垒机/跳板主机连接
  • 管理 SSH 密钥与代理转发
  • 安全传输文件(scp、rsync)
  • 调试 SSH 连接失败

端口转发

本地转发(在本地访问远程服务)

# 将本地端口 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 = 本地转发

远程转发(将本地服务暴露给远程)

# 使你的本地端口 3000 可在远程服务器的 8080 端口访问
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 代理)

# 在本地端口 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+)

# 通过堡垒机连接
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(旧系统兼容,更灵活)

# 等同于 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

# 首次连接创建 socket,后续连接复用
# 对同一主机的重复 ssh/scp/rsync 操作会快很多
# 创建 socket 目录
mkdir -p ~/.ssh/sockets

# 手动管理控制 socket
ssh -O check prod       # 检查连接是否存活
ssh -O stop prod        # 关闭主连接
ssh -O exit prod        # 立即关闭

密钥管理

生成密钥

# 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

部署密钥

# 复制公钥到远程服务器
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/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

SSH 代理

# 启动代理(通常自动启动)
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 → 使用你的本地密钥
# 安全提示:仅转发到受信任的主机

文件权限

# 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

# 复制文件到远程
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

# 同步目录(仅传输更改的文件)
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 2222" ./dist/ user@remote:/var/www/

# 恢复中断的传输
rsync -avz --partial --progress large-file.tar.gz user@remote:/path/

# 通过跳板主机
rsync -avz -e "ssh -J bastion" ./files/ user@internal:/path/

连接调试

详细输出

# 递增详细级别
ssh -v user@remote       # 基础调试
ssh -vv user@remote      # 更多细节
ssh -vvv user@remote     # 最大细节

# 详细输出中可见的常见问题:
# "Connection refused" → SSH 服务未运行或端口错误
# "Connection timed out" → 防火墙阻止或 IP 错误
# "Permission denied (publickey)" → 密钥未被接受
# "Host key verification failed" → 服务器指纹已更改

测试连通性

# 检查 SSH 端口是否开放
nc -zv remote-host 22
# 或
ssh -o ConnectTimeout=5 -o BatchMode=yes user@remote echo ok

# 检查服务器接受哪个密钥
ssh -o PreferredAuthentications=publickey -v user@remote 2>&1 | grep "Offering\|Accepted"

# 不连接测试配置
ssh -G remote-host   # 打印该主机的有效配置

常见修复

# "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED"
# 服务器已重装 / IP 已重新分配
ssh-keygen -R remote-host   # 移除旧指纹
ssh user@remote-host        # 接受新指纹

# "Too many authentication failures"
# SSH 代理提供了太多密钥
ssh -o IdentitiesOnly=yes -i ~/.ssh/specific_key user@remote

# "Connection closed by remote host"
# 常见原因:服务器上的 MaxSessions 或 MaxStartups 限制
# 或:fail2ban 封禁了你的 IP

# 隧道频繁断开
# 在配置或命令行中添加保活设置:
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=5 user@remote

# 密钥正确但权限被拒绝
# 检查远程日志:/var/log/auth.log 或 /var/log/secure
# 常见原因:~/.ssh 或 authorized_keys 权限错误

终止卡住的 SSH 会话

# 如果 SSH 会话挂起(终端冻结):
# 依次输入以下字符序列:
~.          # 断开连接
~?          # 显示转义命令
~#          # 列出转发的连接
~&          # 将 SSH 放入后台(等待隧道关闭时)
# ~ 必须是新行的第一个字符(先按 Enter)

实用技巧

  • 使用 ~/.ssh/config 管理一切。使用命名主机和存储设置,比输入长命令更快且不易出错。
  • 优先使用 Ed25519 密钥而非 RSA。它们更短、更快且同样安全。
  • 连接复用(ControlMaster)使重复连接瞬间完成。建议全局启用。
  • 对于单个文件以外的传输,rsync 几乎总是优于 scp。它能处理中断、仅传输更改并支持压缩。
  • 代理转发(-A)很方便,但在不受信任的服务器上存在安全风险。远程主机可以使用你的代理以你的身份进行认证。建议优先使用 ProxyJump
  • 在配置中添加 ServerAliveInterval 60 可防止大多数“管道破裂”导致的断开。
  • 使用注释保持 ~/.ssh/config 的组织性。未来的你会感谢现在的你。
  • ~. 转义序列是终止卡住的 SSH 会话而不关闭终端的唯一方法。
20 次点击  ∙  0 人收藏  
登录后收藏  
0 条回复
关于 ·  帮助 ·  PING ·  隐私 ·  条款   
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
耗时 21 ms
Developed with Cursor