Linux服务器借用一下本地代理

最近在折腾docker,但国内网络环境对docker特别不友好,经常会遇到镜像拉不下来的情况,即使配置了registery-mirrors也不好使。因为index.docker.io这个索引域名无法访问的话,有再多镜像地址也是徒劳的,唯一的办法是用代理访问。

但我的服务器是在国内公有云上的,直接把自己电脑上的代理软件安装到服务器上可能会不太好。一是linux系统安装起来比windows要麻烦的多,二是连接到外国的地址可能会被防火墙拦截,三是多安装一个客户端会占用同时在线的客户端数量。

所以一个看起来比较好的办法是借用一下自己电脑上的代理,也就是代理是安装在自己的电脑上的,但Linux服务器能远程借过去用用。听着感觉不太现实的样子,但实际上实现起来很简单,在docker拉不了镜像的时候临时救急一下效果很好。

具体的原理是frp,或者说端口转发。理论上用任何frp软件都可以把本地的服务暴露给远程服务器(这个叫反向端口转发)。但我们今天不用任何三方软件,就用连接linux服务器的ssh软件。ssh除了能连接服务器敲命令以外,本身还支持端口转发的,无论是正向端口转发(本地端口转发),还是反向端口转发(远程端口转发)都是没问题的。

正向端口转发(本地端口转发)就是把位于远端的服务的端口暴露给本地,或者说客户端本机

反向端口转发(远程端口转发)就是把位于本地的服务的端口暴露给远端,或者说服务器

正向端口转发多用于访问服务器上的一些私有的服务,比如你在服务器上搭建了一些涩涩的网站,但是又不想让别人访问,这时候就可以用正向端口转发了,只有登录ssh才能访问这个网站,而其它人不登录的话是访问不了的,私密性挺好的。

反向端口转发多用于把自己电脑上的一些服务暴露给服务器,比如暴露代理服务,暴露smb服务或者远程桌面啥的,因为ssh自带加密功能会给你的数据再套一层锁,所以会非常安全。

命令行

首先说一下命令行ssh,使用纯命令行就可以完成端口转发,只不过易用性和GUI比还是差了点

正向端口转发格式为ssh -L 本地端口:目标主机:目标端口 user@host -N

  • -L参数为本地端口转发的意思
  • -L参数的值可以被分成两部分,第一部分是本地端口,第二部分是目标主机:目标端口
    • 其中第一部分是给本机的ssh看的,第二部分是给远程的ssh看的
  • 本地端口:在本机上监听的端口,这个端口上所有的连接都会被转发到目标主机的目标端口上去
  • 目标主机:当ssh服务端收到来自ssh客户端的请求后,发到哪个地址上去
  • 目标端口:当ssh服务端收到来自ssh客户端的请求后,发到哪儿端口上去

(你可能会好奇,为啥没有本地主机这个选项,那是因为一个程序你只能监听自己电脑上的端口,是绝对不可能监听别的电脑上的端口的,所以本地主机只能是127.0.0.1,绝对不可能是其它值,所以就不需你再手动输入了)

说了这么多,这些参数怎么用呢?假设我在服务器上搭建了一个绝对不能让别人看到的网站,这个网站开在端口1234上。同时我希望ssh连接上去之后,能在我电脑上的浏览器里用5678这个端口来访问这个网站。只需要如下设置即可:本地端口设置成5678,目标主机设置成127.0.0.1,目标端口设置成1234。接着ssh连上之后,在浏览器里敲http://127.0.0.1:5678就可以打开这个网站啦。

大概的原理如下,首先ssh登录成功后,本地的ssh客户端会开始监听5678端口。然后当你用浏览器开始访问127.0.0.1:5678这个端口的时候(这里的127.0.0.1只能是127.0.0.1因为自己电脑上的程序,是没有监听别的电脑上的端口的本事的),ssh会帮你把这个请求转发给远在天边的服务器上。

等到服务器上的ssh服务端收到这个ssh客户端发来的请求时,就会把这个请求转发到目标主机:目标端口上,也就是127.0.0.1:1234上,这样整个TCP连接就算建立成功了,浏览器就可以顺利打开网页了。

细心的朋友可能会发现,如果目标主机填的不是127.0.0.1会发生肾么?如果不填127.0.0.1而是填一个局域网ip比如192.168.1.1,那么ssh服务端是真的会把这个请求发送到这个192.168.1.1上的,也就可以访问服务器的局域网里的设备,可以说很厉害了。如果192.168.1.1是路由器的管理地址的话,此时就可以远程管理路由器啦,是不是很方便呢?但是这个地址大多数情况下都是127.0.0.1也就是本机

借助ssh的安全性,即使在正向端口转发上走各种不安全协议,比如http,sftp也是完全没问题的,因为ssh本身自带一层加密,可以说肥肠安全了。

接下来说一下正向端口转发的兄弟,反向端口转发。

反向顾名思义就是方向反过来嘛,可以让服务器去访问你电脑上的服务啥的。

反向端口转发格式为ssh -R 远程端口:目标主机:目标端口 user@host -N

  • 其实反向端口转发的参数和正向转发是差不多的
  • -R参数为远程端口转发的意思
  • 远程端口:ssh服务端监听哪个端口?
  • 目标主机:请求由ssh客户端转发到哪个地址上
  • 目标端口:请求由ssh客户端转发到哪个地址上

当服务器上的某个app访问127.0.0.1:远程端口时,ssh服务端就会把此请求转发到ssh客户端这边,ssh客户端会把此请求转发到目标主机:目标端口上。和正向转发同理,反向转发的目标主机也可以设置为非127.0.0.1值。这样的话服务器就可以访问本地的局域网设备了。

最后是一个小知识,无论是正向转发还是反向转发,远程端口或者说本地端口是可以和目标端口相同的,因为他俩是处于不同的机器上的,所以完全不会有冲突啥的

图形化ssh客户端软件

用命令行操作ssh终究还是没有图形化界面来的方便,图形化ssh客户端有很多的,比如热门的Termius,XShell,MobaXterm,Juice SSH,Putty等,还有冷门的Bitvise,我这里用的bitvise,虽然不同软件之间操作不太一样,但端口转发的设置总体上是大同小异的。

比如我需要把本机的代理服务暴露给服务器上的dockerd,那么我就知道这种场景下我应该要使用反向端口转发。

反向端口转发在bitvise里叫s2c。(正向的叫c2s)

我们只需要添加一行规则就好了,监听地址填0.0.0.0(0.0.0.0可以认为等价于127.0.0.1,具体区别后面会讲),监听端口填8888,目标主机填localhost或者127.0.0.1,目标端口填10809。

然后重新连接一下ssh,然后就可以在服务器上用curl http://127.0.0.1:8888来测试连通性了,没问题之后就可以配置给dockerd使用了。

image-20230620083319553

配置dockerd使用代理

跑题半天之后,终于想起来我要写的主题其实是dockerd配置代理了。。。

docker拉镜像时干活的其实是dockerd这个程序,所以我要给dockerd配置代理。

根据docker官方文档,配置代理有3种方法:

  1. 用环境变量 (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY)
  2. 用配置文件
  3. 用命令行参数(–http-proxy, –https-proxy, and –no-proxy)

我当然是选择配置文件了,不同的操作系统配置文件位置不一样,Linux上是在/etc/docker/daemon.json,我们打开这个文件(没有就创建一个)。然后添加这些内容,或者合并现有内容:

{
    "proxies": {
        "http-proxy": "http://127.0.0.1:10809",
        "https-proxy": "http://127.0.0.1:10809"
    }
}

http-proxy的意思是,对于dockerd发出的http请求,应该转发到哪里去?

https-proxy的意思是,对于dockerd发出的https请求,应该转发到哪里去?

一般情况下两者的代理地址都是一样的,实际情况中,dockerd发出的都是https请求,http请求我还没见到过,这样来说的话就可以不用配置http-proxy的。

配置完成后保存关闭,接着使用systemd重启docker服务systemctl restart docker,注意别嫌麻烦用reload,必须要restart,reload是不行的。

重启完成后可以使用docker info来查看docker的配置情况。如果看到HTTP Proxy: http://127.0.0.1:10809这样的字样就说明配置成功了,接着使用docker pull或者docker compose up都可以拉取镜像,而且拉取速度嘎嘎快。