本文档旨在记录如何通过一台拥有公网IP的服务器,安全、稳定地访问一台位于内网(多层防火墙后)的服务器。
1. 目标与场景
- 公网服务器 (Relay Server): 一台拥有固定公网IP或域名的服务器,可以被外网直接访问。
- 内网服务器 (Target Server): 一台位于内网,可以访问外网,但无法被外网直接访问的服务器。
- 最终目标: 在任何网络环境下,通过访问公网服务器的特定端口,建立一个到内网服务器的SSH连接。
2. 环境与角色说明
角色 | 主机名 (示例) | IP/域名 (示例) | 关键用户 (示例) | 操作系统 |
---|---|---|---|---|
公网服务器 | relay-server |
your-relay-server.com |
tunnel_user (隧道专用) |
Debian/Ubuntu/CentOS |
内网服务器 | internal-server |
(内网IP) | your_user (登录用户) |
Debian/Ubuntu/CentOS |
运维终端 | 您的电脑 | (任意公网IP) | - | - |
端口规划
端口号 | 所在服务器 | 用途 | 防火墙策略 |
---|---|---|---|
2222 | 公网服务器 | SSH服务端口。用于内网服务器连接公网服务器建立隧道。 | 必须放行 |
8022 | 公网服务器 | 隧道转发端口。用于运维终端连接,流量会转发到内网服务器。 | 必须放行 |
22 | 内网服务器 | SSH服务端口。隧道的最终目标端口。 | (无需公网策略) |
3. 配置步骤
第一步:配置公网服务器 (your-relay-server.com
)
目标:创建专用用户,配置SSH服务,并放行防火墙。
- 创建隧道专用用户 为安全起见,创建一个无特权的专用用户(如
tunnel_user
)来处理隧道连接。sudo adduser tunnel_user
根据提示为新用户设置密码。
- 配置SSH服务以允许公网转发 编辑SSH配置文件,允许隧道端口绑定到公网地址。
sudo nano /etc/ssh/sshd_config
找到
GatewayPorts
选项,取消注释并修改为yes
。#... GatewayPorts yes #...
保存文件后,重启SSH服务使配置生效。
sudo systemctl restart sshd
- 配置防火墙 放行SSH服务端口和隧道转发端口。
- 如果使用
ufw
(Debian/Ubuntu):sudo ufw allow 2222/tcp sudo ufw allow 8022/tcp sudo ufw reload
- 如果使用
firewalld
(CentOS/RHEL):sudo firewall-cmd --permanent --add-port=2222/tcp sudo firewall-cmd --permanent --add-port=8022/tcp sudo firewall-cmd --reload
- 如果使用
第二步:配置内网服务器 (internal-server
)
目标:生成SSH密钥,配置免密登录,并使用systemd
和autossh
建立持久化隧道。
- 安装
autossh
autossh
可以监控SSH会话,并在断开时自动重连。sudo apt-get update sudo apt-get install autossh
- 生成SSH密钥对 为内网服务器生成一个密钥对,用于免密登录公网服务器上的
tunnel_user
用户。ssh-keygen -t ed25519 -C "internal_to_relay_tunnel"
一路回车,不要设置密码(passphrase),以确保自动化脚本可以顺利执行。
- 将公钥部署到公网服务器 使用
ssh-copy-id
将内网服务器的公钥添加到公网服务器的tunnel_user
用户的授权列表中。# 注意替换为公网服务器的域名和端口 ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub [email protected]
系统会提示输入公网服务器上
tunnel_user
用户的密码,这是最后一次需要输入密码。 - (可选)安全加固:限制密钥权限 登录到公网服务器,编辑
tunnel_user
用户的授权文件,限制此密钥只能用于建立隧道。# 在公网服务器上执行 sudo -u tunnel_user nano /home/tunnel_user/.ssh/authorized_keys
在公钥字符串的最前面,添加以下限制内容(注意末尾有一个空格):
command="/bin/false",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
最终该行看起来像:
command="..." ssh-ed25519 AAA... internal_to_relay_tunnel
- 创建
systemd
服务实现开机自启和守护进程 在内网服务器上创建systemd
服务文件。sudo nano /etc/systemd/system/reverse-ssh-tunnel.service
将以下内容粘贴进去,请确保
ExecStart
中的域名、端口和用户名正确无误。[Unit] Description=AutoSSH Reverse Tunnel to Relay Server Wants=network-online.target After=network-online.target [Service] # 建议使用一个非root用户来运行此服务 User=your_user Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -M 0 -N -p 2222 -o "ServerAliveInterval=60" -o "ServerAliveCountMax=3" -o "ExitOnForwardFailure=yes" -R your-relay-server.com:8022:localhost:22 [email protected] RestartSec=5 Restart=always [Install] WantedBy=multi-user.target
第三步:启动并验证隧道
- 在内网服务器上启动服务
sudo systemctl daemon-reload sudo systemctl enable reverse-ssh-tunnel.service sudo systemctl start reverse-ssh-tunnel.service
- 在内网服务器上检查服务状态
sudo systemctl status reverse-ssh-tunnel.service
确保状态为
active (running)
。 - 在公网服务器上验证端口监听
sudo ss -tlpn | grep 8022
正确的输出应该显示
sshd
进程正在监听0.0.0.0:8022
或*:8022
。
4. 最终连接
一切就绪后,您可以从任何运维终端上,通过以下命令连接到内网服务器:
# -p 8022: 连接公网服务器上为隧道开设的公网端口
# your_user@... : your_user是内网服务器上的用户名, @后面是公网服务器的域名
ssh -p 8022 [email protected]
输入内网服务器上your_user
用户的密码后,即可成功登录。
5. 常见故障排查
Connection refused
:- 检查公网服务器的防火墙是否已放行隧道端口(
8022
)。 - 检查公网服务器上
sshd_config
的GatewayPorts
是否为yes
。 - 检查连接的端口号是否正确。
- 检查公网服务器的防火墙是否已放行隧道端口(
Permission denied (publickey)
:- 检查内网服务器的公钥是否已正确添加到公网服务器上
tunnel_user
用户的~/.ssh/authorized_keys
文件中。 - 检查公网服务器上
~/.ssh
目录权限是否为700
,authorized_keys
文件权限是否为600
。
- 检查内网服务器的公钥是否已正确添加到公网服务器上
- 隧道只监听在
localhost
或127.0.0.1
:- 这是
GatewayPorts
设置不正确导致的。请返回第一步,确认公网服务器的sshd_config
中GatewayPorts
为yes
并已重启sshd
服务。
- 这是