ssh通过代理登录远程主机及穿越跳板机
Table of Contents
通过代理登录远程主机
ssh要使用代理登录远程主机,一般是因为远程主机是买的国外主机,然后ip被和谐了,所以要用通过代理来登录,代理一般都是ss啦。
用法一
ssh -o "ProxyCommand nc -X 5 -x 127.0.0.1:1086 %h %p" [email protected]
用法二
ssh -o ProxyCommand="nc -X 5 -x 127.0.0.1:1086 %h %p" [email protected]
用法三
不写-X
,则默认使用SOCKS5协议:
ssh -o ProxyCommand="nc -x 127.0.0.1:1086 %h %p" [email protected]
解释:
– -o
:option,表示选项的意思;
– ProxyCommand
:ssh的一个选项,man ssh
的-o
选项中可看到有ssh有哪些选项可使用,要进一步看选项具体含义,可用man ssh_config
查看;
– nc
:netcat,net就是网络,cat就是“concatenate”(连接),就是连接网络的意思,这是一个工具,可以用man nc
查看,windows下应该不存在这个命令,linux也需要安装,mac自带这个命令;
– -X
: (大写X)指定代理协议,有三种值:
4:SOCKS v4
5:SOCKS v5
connect:HTTPS
– -x
:(小写x)指定代理的主机地址和端口,我例子里写127.0.0.1:1086
,是因为我用的ss,它有它的本地ip和端口,当然主机地址也可以填域名;
– %h %p
:变量,用于替换ssh真正要连接的服务器的主机名(host)和端口(port);
– [email protected]
:真正要连接的主机。
注意:-X
和-x
都是nc
命令的选项(可用man nc
查看),而不是ProxyCommand
命令的选项。
用法四
把ProxyCommand
的配置写在配置文件中,这样就不需要全部选项明着写了。
编写配置文件~/.ssh/config
,注意,这个配置文件在客户端一般是不存在的,直接用vim新建保存即可。
vim ~/.ssh/config
配置文件内容:
Host *
ProxyCommand nc -X 5 -x 127.0.0.1:1086 %h %p
*
号表示所有ssh连接的主机都通过指定的代理连接,当然你也可写成指定域名,或通配符域名,例如*.test.com
使用了配置文件后,ssh直接像平时正常使用就可以,它会自动读取配置文件并使用代理去连接:
ssh [email protected]
注意:如果你是新建的~/.ssh/config
文件,一定要把它的权限设置为600
,否则会无法使用scp
等命令,一使用就会提示“Bad owner or permissions on ~/.ssh/config”。
Win下使用
我用总是报这个错误,网上查也没找到解决方法,如果真要在win下用,要不就直接用自带代理功能的客户端如Xshell,要不就直接用wsl(windows subsystem for Linux):
CreateProcessW failed error:2
posix_spawn: No such file or directory
穿越跳板机
什么是跳板机?
假设A为你的电脑,B、C为远程的服务器,为了安全,A无法直接登录C,A必须先登录B,然后在B上面再去登录C,在这里,B就是我们说的“跳板机”,一般不是直接提供服务的服务器(比如你们公司的网站不挂在这个服务器上),而C才是真正提供服务的服务器,同理还可以有D、E、F、……,这些机器都必须通过跳板机B来登录。
当然要注意,A未必就是你自己那台电脑,它也可以是远程的一台服务器,反正只要我们知道,A无法直接登录C,但A可以登录B,B也可以登录C,我们要做的,就是通过B,让A可以直接登录C,此时B就是“跳板机”。
ssh登录远程主机语法格式
最常见的登录格式:
ssh [email protected]
其中“23.45.67.78”是你要登录的远程服务器的ip地址(我们一般叫它“主机”或“主机地址”,它也可以写成域名,只要你的域名是指向这个ip的就行),而“zhangsan”则是“23.45.67.78”这台服务器中存在的一个用户,整句的意思,就是使用“zhangsan”这个用户去登录ip为“23.45.67.78”的服务器。
主机名用域名的形式:
ssh [email protected]
最简写法示例一:
ssh 23.94.74.45
最简写法示例二:
ssh server1.example.com
最简写法示例三:
ssh abcd
以上的三种最简写法,其实都是一个意思,就是不指定用户名,ssh后面只跟一个参数,那么这个参数会被识别为主机地址或叫主机名,主机地址即可以是ip“23.94.74.45”,也可以是域名“server1.example.com”,最后一个“abcd”是什么玩意儿?没错,它也是主机名,只不过没写成“xxx.xxx.com”这样的形式,但它也是主机名。
而其他没写的参数都会用默认参数,比如没写用户名,那就会用当前用户名,当前用户名是什么?就是你当前登录你电脑的用户名呀,如果你当前的电脑是Mac或Linux,那用whoami
命令就可以查看当前用户名,Windows的话,在控制面板→用户账号里可以看到,如果是Win10直接在左下角点开开始菜单,鼠标放到头像上就有用户名(不过如果名称有大写字母会被转成小写)。
命令方式穿越
现在我这有三台机:
– A: 10.37.129.5
– B: 10.37.129.6
– C: 10.37.129.7
其中A可以登录B,B可以登录C,但A不可以登录到C,我们现在要通过B实现从A直接登录到C。其中A就是我的Mac电脑(Linux系统也行,但Windows不行,因为Windows不支持这种写法,虽然有其他写法,但我目前没研究)。
穿越命令一:
ssh -o "ProxyJump [email protected]" [email protected]
如果你要指定跳板机端口(这里我们指定端口为22):
ssh -o "ProxyJump [email protected]:22" [email protected]
对应含义:
ssh -o "ProxyJump 跳板机用户名@跳板机ip(或域名):跳板机端口" 目标服务器用户名@目标服务器ip(或域名)
这是最简单的方式,但是openssh版本低的时候,会报错“command-line: line 0: Bad configuration option: proxyjump”,你去man ssh_config
里查,确实查不到“ProxyJump”选项,没关系,升级openssh就好了:
sudo yum -y update openssh
ProxyJump:Proxy是代理的意思,Jump就是跳的意思,ProxyJump就是代理跳板机的意思了,ProxyJump用于指定代理跳板机,至于怎么指定,当然是指定跳板机的用户名和ip(或域名)了,格式与ssh直接登录的时候格式是一样的,都是用户名@ip(或域名)。
穿越命令二:
ssh -o "ProxyCommand ssh [email protected] -W %h:%p" [email protected]
对应含义:
ssh -o "ProxyCommand ssh 跳板机用户名@跳板机ip或域名 -W %h:%p" 目标服务器用户名@目标服务器ip(或域名)
这种方式可用于低版本的openssh,当然高版本的也一样可以。
解释: -o
的o是option,选项的意思,使用man ssh
命令,搜索-o
可以看到它有很多选项:
-o option
Can be used to give options in the format used in the configuration file. This is useful for specifying options for which there is no separate command-line flag. For
full details of the options listed below, and their possible values, see ssh_config(5).
AddKeysToAgent
AddressFamily
BatchMode
BindAddress
CanonicalDomains
CanonicalizeFallbackLocal
CanonicalizeHostname
CanonicalizeMaxDots
CanonicalizePermittedCNAMEs
……
我这里只列出一小部分,其他的请自己使用“man ssh”命令查看。
但是这些选项都没有解释,不知道什么意思,怎么办?其实还有一个手册,使用man ssh_config
就可以查看到这些选项的含义了。
man ssh
中-W
的解释:
-W host:port
Requests that standard input and output on the client be forwarded
to host on port over the secure channel. Implies -N, -T,
ExitOnForwardFailure and ClearAllForwardings, though these can be
overridden in the configuration file or using -o command line
options.
大概意思:请求将客户端的标准输入输出通过安全通道转发到端口为“port”的主机“host”上。
“%h:%p”的解释:
h就是host(主机名,即ip或域名),p就是port端口,添加了%
表示它是一个变量,它们的值会被替换成实际要登录的主机和端口,由于本例中,实际要登录的目标主机ip是“10.37.129.7”,而端口由于未指定,则会使用默认端口“22”,所以以下两句是等效的:
ssh -o "ProxyCommand ssh [email protected] -W %h:%p" [email protected]
ssh -o "ProxyCommand ssh [email protected] -W 10.37.129.7:22" [email protected]
方式二还可以改成nc
方式:
ssh -o "ProxyCommand ssh [email protected] nc %h %p" [email protected]
即把-W
改成nc
,然后把%h:%p
改成%h %p
(即由原来的冒号分隔改成空格分隔)。
注意:这种方式要求“跳板机”上安装nc
命令,因为nc是一个工具,叫netcat
,从名字上可以看出,net是网络,cat就相当于Linux的命令cat
,是“concatenate”的缩写(是连接的意思),整个意思是网络连接。
配置文件方式穿越
其实就是把前面的“命令方式穿越”写在配置文件中,这样我们就不用每次写这么长一串了。
编辑ssh的配置文件(没有就新建):
vim ~/.ssh/config
把以下配置放进去,保存:
Host 10.37.129.7
ProxyJump [email protected]
试试穿越跳板机登录:
ssh [email protected]
根据前面说过的ssh登录格式,我们知道,“10.37.129.7”是要登录的服务器ip,也叫主机名(可以是ip也可以是域名),所以当回车执行该命令的时候,~/.ssh/config
中的配置起作用了,Host 10.37.129.7
中的ip刚好与我们要登录的服务器主机名匹配,所以ProxyJump [email protected]
生效,产生的效果与前边的命令方式的这句是一毛一样的,只不过一个是用-o
来指定选项,一个是用“配置文件”来指定选项而已:
ssh -o "ProxyJump [email protected]" [email protected]
同理,我们把前面命令穿越方式二改成配置文件写法:
Host 10.37.129.7
ProxyCommand ssh [email protected] -W %h:%p
或者使用nc方式:
Host 10.37.129.7
ProxyCommand ssh [email protected] nc %h %p
然后同样执行以下命令,通过“10.37.129.6”跳板机登录到“10.37.129.7”服务器:
ssh [email protected]
其中的%h
和%p
实际执行时,同样会被替换成实际要登录的目标服务器的的ip“10.37.129.7”和默认端口“22”,我们不写死,是因为写变量可以根据我们敲的命令自动匹配,否则你这个配置就只能登录一台机器了。
如果我们想要登录的目标服务器有很多台,它们都是同ip段的10.37.129.x
,我们用*
号来代替任意字符串(数字在这里也算是字符串)即可:
Host 10.37.129.*
ProxyCommand ssh [email protected] -W %h:%p
或用ProxyJump方式:
Host 10.37.129.*
ProxyJump [email protected]
这样,我们执行以下命令时,这个配置都会被匹配到:
ssh [email protected]
ssh [email protected]
ssh [email protected]
……
每次都要敲ip太麻烦,我们想通过简单的方式登录可不可以呢?答案是可以!
修改配置文件为:
Host server1
HostName 10.37.129.7
User xiebruce
ProxyCommand ssh [email protected] -W %h:%p
或用ProxyJump方式:
Host server1
HostName 10.37.129.7
User xiebruce
ProxyJump [email protected]
然后我们执行ssh server1
一样可以登录,由于不再是用ssh 用户名@主机名
的方式登录,按照前面ssh登录远程主机语法格式所说,用户名将会是当前电脑的用户名,而“server1”将会被识别为主机名,显然,用这样的用户名和主机名去登录肯定是不对的,所以我们要用HostName
来指定真正要登录的主机名(可以是ip或域名),用User
来指定真正要登录的用户名,而我怎么知道会有这两个属性呢?还是通过前面据说的man ssh
的-o
选项可以看到,通过man ssh_config
可以看到它们的详细解释。
实际上很多ssh的选项都可以在配置文件里指定,比如,如果你实际登录的目标主机端口不是默认端口22,而是被你修改成了2203,那么你可以用“Port”来指定:
Host server1
HostName 10.37.129.7
User xiebruce
Port 2203
ProxyJump [email protected]
同理假设你还有server2(10.37.129.8)和server3(10.37.129.9)也要通过代理服务器(10.37.129.6)来登录,继续添加配置即可:
Host server2
HostName 10.37.129.8
User xiebruce
Port 2203
ProxyJump [email protected]
Host server3
HostName 10.37.129.9
User xiebruce
Port 2203
ProxyJump [email protected]
当然也可以单独定义跳板机,然后再去引用它,这种方式的好处是你可以在后面多个Host里引用同一个jump,这样不用每次重复写:
Host jump
HostName 10.37.129.6
User xiebruce
Port 22
Host 10.37.129.7
ProxyJump jump
#ProxyCommand ssh jump nc %h %p
#ProxyCommand ssh jump -W %h:%p
免密码登录
前面的操作,正常情况下,会先让你输入跳板机密码,然后输入实际要登录的目标主机密码,即你得输两遍密码,还是很麻烦,要解决这个问题很简单,只要让A对B免密登录,A对C免密登录就可以了(B对C不需要免登录),免密登录设置方法请查看:Linux-使用ssh免密码登录。
不具有代理功能的软件使用代理
本站所在服务器是国外服务器,最近大规模和谐ip,本站ip也受牵连,ssh无法登录,于是通过本文的方法通过一个可以登录的ip做代理,解决了ssh无法登录的问题。
遇到的问题一:本站的代码之前是通过phpstorm的sftp直接上传的,但由于ip被和谐(ping不通,ssh登录不了),所以sftp无法上传了,我们都知道sftp实际上也是走ssh通道的,但是phpstorm的sftp功能不走系统的ssh配置文件~/.ssh/config
,所以我ssh能登录也帮不了phpstorm的sftp功能。
还是以前面用到的三台机为例:
– A:10.37.129.5(本地Mac电脑)
– B:10.37.129.6(远程centos服务器)
– C:10.37.129.7(远程centos服务器)
A可以登录B,B可以登录C,A无法直接登录C,现要通过B,让A能直接登录C。
解决方法:
使用以下语句开启ssh隧道(在本地Mac电脑上执行):
ssh -f -N -L localhost:2000:localhost:22 [email protected]
其中,[email protected]
是sftp要传送文件的目标服务器,但前面已经说过了,这个ip已经被和谐,但是我用前面的方法,已经在~/.ssh/config
里设置了跳板机,所以现在ssh [email protected]
是可以登录的。
-N
不开启终端窗口(只是开启通道)
-f
表示后台运行
-L
(Local)表示开启本地端口转发,localhost:2000
表示监听本地环回网卡的2000端口,localhost:22
是转发目标地址,localhost:2000:localhost:22
整句表示把本地的2000端口的数据转发到本地的22端口,而本地的22端口实际上是映射到跳板机的,这样就能把本地的2000端口的数据通过本地的22端口把数据通过跳板机发送到真实服务器“[email protected]”。
原Host为“10.37.129.7”,现Host为“localhost”,原端口为“22”,现端口为“2000”:
遇到的问题二:
sftp的问题解决了,mysql的问题又来了,我的mysql我没有设置任何可以远程登录的账号,只有127.0.0.1(或localhost)的账号,然后使用ssh通道来登录,使用的是挺好的,也安全:
但现在已经不行了,因为10.37.129.7
这个ip已经被和谐,而且mysql客户端的ssh是无法识别或使用~/.ssh/config
配置文件的,所以也不可能直接使用跳板机。
并且如果跟问题一一样的设置也是不行的:
ssh -f -N -L localhost:2000:localhost:3306 [email protected]
不行的原因是,localhost:3306
其实本质上是通过B机(10.37.129.6)来登录C机(10.37.129.7)的3306端口,而我前面说了,我的mysql是不能远程登录的,即使B能直接访问到C,但B也是无法登录C的mysql的,C的mysql只能在C机本地登录。
解决方法:我现在不在本地建立ssh隧道了,而是在B机(10.37.129.6)上来建立ssh隧道,隧道创建命令如下:
ssh -f -N -L 2000:localhost:3306 [email protected]
这表示把C机(10.37.129.7)的3306端口映射到B机(10.37.129.6),而我在A机(10.37.129.5)即我电脑上的mysql客户端还是使用ssh通道去连接,只不过这次ssh通道地址我填的是B机的ip、B机的ssh用户名和密码,因为B机上的2000端口已经相当于是C机(因为被映射下来了),所以这样就可以访问了(如下图所示)。
以上案例均为我现在正在真实使用的,并不是单纯为了做实验(当然ip数据被我改成了三个代替的ip),很简单,因为我BC两台机是服务器,都在墙外,起初都能直连,现在C被和谐了,B的443端口也被和谐但ssh却连的上,所以现在我是通过B去连C。
以上所使用的功能其实叫ssh端口转发(或ssh隧道),具体参见:SSH端口转发(SSH隧道)。
参考:
ssh端口转发:ssh隧道
玩转SSH端口转发
PhpStorm sftp deploy with SSH Proxy
总结的很好呀,收藏了,谢谢博主!
不客气,感谢你的肯定,感谢收藏!
bash
CreateProcessW failed error:2
posix_spawn: No such file or directory
Win 报这个错误是因为没有 nc ,要使用 connect 的话也要使用绝对路径,网上很多教程直接写的 connect 还是会报这个错误(也有可能他们把 connect 放在了已经存在于环境变量中的目录)。
哦哦,我有空再试试,你试成功过吗?
亲测写上绝对路径就可以了