目录
说明
格式
参数说明
实例
实例1
实例2
ssh个人配置
config配置含义
远程转发指的是在远程 SSH 服务器建立的转发规则。
它跟本地转发正好反过来。建立本地计算机到远程计算机的 SSH 隧道以后,本地转发是通过本地计算机访问远程计算机,而远程转发则是通过远程计算机访问本地计算机。比较常见的例子就是内网穿透。
它的命令格式如下:
$ ssh -R 远程主机端口:目标主机地址:目标主机端口 -N [远程主机用户名@]远程主机地址 [-p 远程主机SSH端口]
参数 | 含义 |
---|---|
-C | 允许压缩数据 |
-f | 后台执行ssh指令 |
-N | 不执行远程指令,用于转发端口 |
-g | 允许远端主机连接本地转发的端口 |
-p | 指定远程主机的端口,如果为默认端口,则可以省略 |
注意上面的参数除了-p需要跟参数外其他的可以组合使用,使用一个-
,但是主要组合时要放到转发类型参数的签名,并且不能和转发类型组合使用
ssh -g -L lport:remoteAddr:remotePort
等价于 ssh -L 0.0.0.0:lport:remoteAddr:remotePort
转发类型:
参数 | 含义 |
---|---|
-L | 正向代理,将本地机(客户机)的某个端口转发到远端指定机器的指定端口 |
-R | 反向代理,远程端口转发,将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口 |
-D | socks5代理(-D):相当于 ss/ssr |
其中 [远程主机用户名@] 中如果远程主机用户名跟当前操作的用户名一致可以省略,如都是ubuntu,则只需要写后面的远程主机地址就可以
远程转发主要针对内网的情况。下面举两个例子。
服务器 | 服务 | 说明 |
---|---|---|
服务器A(192.168.1.245)【隧道建立者】 | localhost:8800 | 内网,外网不可直接访问 |
服务器B(124.42.8.133)【提供对外访问地址】 | 124.42.8.133:8899 | 外网,外网可直接访问 |
主机C【访问者】 | - | 外网,想访问服务器A的服务 |
现在有一台内网服务器A(不可用访问互联网),在 8800
端口启动了一个web服务,现在想把这个服务通过公网映射出去,映射到具有公网 IP 地址的服务器B(124.42.8.133
)的 8899
端口,使得访问124.42.8.133:8899
这个地址,就可以访问到内网服务器A的8800
端口。
在服务器A
上执行以下命令,回车后会要求输入服务器B
(124.42.8.133
)的ubuntu
账号的密码:
# 以下命令在服务器A上执行 $ ssh -R 远程服务器B访问端口:目标服务器A地址:目标服务器A端口 -N 用户名@远程服务器C地址 -p 远程服务器Cssh端口 ssh -fN -R 8899:localhost:8800 [email protected] -p 22022
说明:
1、如果远程服务器跟本地服务器用户名相同都是ubuntu
,则ubuntu@
可以不写,即:
ssh -fN -R 8899:localhost:8800 124.42.8.133 -p 22022
2、-p参数后面跟的是124.42.8.133的ssh端口,如果是默认的22则-p和后面的参数可以不写,即:
ssh -fN -R 8899:localhost:8800 124.42.8.133
输入密码后就可以在124.42.8.133
上访问了
curl 127.0.0.1:8899
可以看到返回了我们服务器A上8800服务的内容。
上面命令是在内网服务器A上执行,建立从服务器A到124.42.8.133
的 SSH 隧道。运行以后,用户访问124.42.8.133:8899
,就会自动映射到localhost:8800
。
问题
到这还没有结束,假设有一台能访问服务器B的机器C,在机器C上测试一下这个服务,很可能会发现服务124.42.8.133:8899
并不能正常访问。
这又是为什么呢?服务器B上我们明确是可以访问到的。这是因为在SSH服务的配置文件/etc/ssh/sshd_config
中有这样一个配置,当然也可能没有,因为它的默认值是no
。
GatewayPorts no
GatewayPorts
是否允许远程主机连接本地的转发端口,默认值为 no
。注意:这个设置需要在端口转发的机器上修改,这里是远程服务器B,改服务器A是没有作用的。
GatewayPorts yes
将此项配置为yes
并重启SSH
服务后,再次执行命令
~$ sudo service ssh restart
这样再启动,服务器C就可以访问124.42.8.133:8899
了,其他能访问服务器B,并且没有被防火墙拦截的机器也都可以访问该服务。
服务器 | 服务 | 说明 |
---|---|---|
服务器A(124.42.8.133)【提供对外访问地址】 | 124.42.8.133:8899 | 外网,外网可直接访问 |
SSH 跳板机B(192.168.1.251)【隧道建立者】 | ssh隧道 | 内网,外网不可直接访问,可连通A、C服务器 |
目标服务器C(192.168.1.245)【提供对外访问地址】 | 192.168.1.245:8800 | 内网,外网不可直接访问,最终服务提供者 |
机器D【访问者】 | - | 外网,访问服务器A |
服务器A(124.42.8.133)
在外网,SSH 跳板机B(192.168.1.251)
和目标服务器C(192.168.1.245)
都在内网,必须通过 SSH 跳板机B才能访问目标服务器C(192.168.1.245)
。但是,服务器A无法访问内网之中的 SSH 跳板机B,但是 SSH 跳板机可以访问服务器A。
由于服务器A
无法访问内网 SSH 跳板机B
,就无法从外网发起 SSH 隧道,建立端口转发。必须反过来,从 SSH 跳板机B
发起隧道,建立端口转发,这时就形成了远程端口转发。跳板机执行下面的命令,绑定服务器A
的8899
端口,去访问192.168.1.245:8800
。
在跳板机B
上执行以下命令,回车后会要求输入服务器A
(124.42.8.133
)的ubuntu
账号的密码:
# 以下命令在跳板机B上执行 $ ssh -R 远程服务器A访问端口:目标服务器C地址:目标服务器C端口 -N 用户名@远程服务器A地址 -p 远程服务器Assh端口 $ ssh -R 8899:192.168.1.245:8800 -N [email protected] -p 22022
上面命令是在 SSH 跳板机B(192.168.1.251)
上执行的,建立跳板机B(192.168.1.251)
到服务器A(192.168.1.245)
的隧道,并且这条隧道的出口映射到目标服务器C``192.168.1.245:8800
。
显然,远程转发要求服务器A(124.42.8.133)
也安装了 SSH 服务器,这样才能接受 SSH 跳板机B(192.168.1.251)
的远程登录。
执行上面的命令以后,SSH 跳板机B(192.168.1.251)
到服务器A(124.42.8.133)
的隧道已经建立了。然后,就可以从服务器A(124.42.8.133)
访问目标服务器C(192.168.1.245)
了,在服务器A(124.42.8.133)
上执行下面的命令。
$ curl 124.42.8.133:8899
本机执行上面的命令以后,就会输出服务器目标服务器C(192.168.1.245)
的 8800
端口返回的内容。
如果经常执行远程端口转发,可以将设置写入 SSH
客户端的用户个人配置文件(~/.ssh/config
)。
Host 主机别名 HostName 远程服务器地址 Port 远程服务器ssh端口 User 远程服务器用户名 RemoteForward 远程服务器转发端口 目标主机地址:目标主机端口
Host 133 HostName 124.42.8.133 Port 22022 User ubuntu RemoteForward 8899 localhost:8800
Host 服务器别名,只要是合法的变量名称且不重复即可,可任意指定,ssh命令通过该名称来连接到指定服务器,比如上面的 ssh hostA
/ ssh hostB
。
Hostname 服务器地址,可以是域名,也可以是ip地址。
Port 端口号,默认为22,只有修改了ssh连接的默认端口才需要配置此参数
User ssh的登陆用户名
IdentityFile ssh 私钥文件的地址(不带.pub后缀的文件)
RemoteForward
远程转发配置
LocalForward
本地转发配置
DynamicForward
动态转发SOCKS配置
参考文件 How To Configure Custom Connection Options for your SSH Client | DigitalOcean
完成上面的设置后,执行下面的命令就会建立远程转发。
$ ssh -N 133(主机别名) #后台执行可以加上-f ssh -N remote-forward # 等同于 $ ssh -R 远程服务器转发端口:目标服务器地址:目标服务器端口 -N [email protected] -p 远程服务器ssh端口
这样就不用重复输入配置参数,减少出错。
当然除了ssh端口转发这种方法,我们还可以使用其他技术手段来实现转发端口,比如Nginx
。