ssh通过代理登录远程主机及穿越跳板机

ssh通过代理登录远程主机及穿越跳板机

通过代理登录远程主机

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”:
Xnip2019-06-06_05-52-39.jpg


遇到的问题二:
sftp的问题解决了,mysql的问题又来了,我的mysql我没有设置任何可以远程登录的账号,只有127.0.0.1(或localhost)的账号,然后使用ssh通道来登录,使用的是挺好的,也安全:
Xnip2019-06-11_14-24-46.jpg

但现在已经不行了,因为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机(因为被映射下来了),所以这样就可以访问了(如下图所示)。
Xnip2019-06-11_16-04-28.jpg


以上案例均为我现在正在真实使用的,并不是单纯为了做实验(当然ip数据被我改成了三个代替的ip),很简单,因为我BC两台机是服务器,都在墙外,起初都能直连,现在C被和谐了,B的443端口也被和谐但ssh却连的上,所以现在我是通过B去连C。

以上所使用的功能其实叫ssh端口转发(或ssh隧道),具体参见:SSH端口转发(SSH隧道)

参考:
ssh端口转发:ssh隧道
玩转SSH端口转发
PhpStorm sftp deploy with SSH Proxy

打赏

订阅评论
提醒
guest

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

5 评论
内联反馈
查看所有评论
Dingding
2 年 前

总结的很好呀,收藏了,谢谢博主!

HE-SB
3 年 前

bash
CreateProcessW failed error:2
posix_spawn: No such file or directory

Win 报这个错误是因为没有 nc ,要使用 connect 的话也要使用绝对路径,网上很多教程直接写的 connect 还是会报这个错误(也有可能他们把 connect 放在了已经存在于环境变量中的目录)。

HE-SB
3 年 前
回复给  xiebruce

亲测写上绝对路径就可以了

5
0
希望看到您的想法,请您发表评论x

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

ssh通过代理登录远程主机及穿越跳板机