通过主机名将 ssh 连接转发到 docker 容器

Zia*_*man 12 ssh reverse-proxy docker

我遇到了一个非常具体的情况,虽然还有其他方法可以做到这一点,但我有点着迷于此,并想找到一种完全像这样的方法:

背景

假设我有一台服务器运行多个服务,这些服务隐藏在隔离的 docker 容器中。由于大多数这些服务都是 http,我使用 nginx 代理向每个服务公开特定的子域。例如,节点服务器运行在 docker 容器上,其端口80绑定到127.0.0.1:8000主机上。我将在 nginx 中创建一个虚拟主机,将所有请求代理myapp.mydomain.comhttp://127.0.0.1:8000. 这样,docker 容器不能从外部访问,除了通过myapp.mydomain.com.

现在我想以指向 gogs容器的方式启动一个gogsgogs.mydomain.com docker 容器。所以我启动了这个 gogs 容器,端口8000绑定到127.0.0.1:8001主机上。和一个 nginx 站点代理请求gogs.mydomain.comhttp://127.0.0.1:8001并且它运行良好......

但是,gogs 是一个 git 容器,我也想像通过那样访问存储库,git@gogs.mydomain.com:org/repo但这不适用于当前设置。使这项工作的一种方法22是将容器的端口绑定到0.0.0.0:8022主机上的端口,然后 git ssh url 可以是类似git@gogs.mydomain.com:8022/repo.

(这似乎不工作;当我推到与URI这样的原点,混帐要求密码对gitgogs.mydomain.com-而不是gogs.mydomain.com:8022-但不过这可能是什么我做错了,超出范围的这个问题,我也很感激任何诊断)

问题

我主要担心的是,我希望<gogs container>:22代理ssh 端口,就像我使用 nginx 代理 http 端口一样;即任何gogs.mydomain.com要传递到容器端口的ssh 连接22。现在我无法将容器的 ssh 端口绑定到主机的 ssh 端口,因为主机上已经有一个 sshd 正在运行。此外,这意味着*.mydomain.com要传递到容器的 sshd 的任何连接。


我想要任何 ssh 连接:

  • mydomain.com host.mydomain.com 或 mydomain 的 IP 地址被接受并转发到主机上的 sshd
  • gogs.mydomain.com或被git.mydomain.com接受并传递到 gogs 容器上的 sshd
  • *.mydomain.com*除了上述可能性之外的任何其他地方)被拒绝

如果是 http,我可以通过 nginx 轻松完成这项工作。有没有办法为 ssh 做到这一点?


(也想出去问问:一般来说,有没有办法用任何tcp 服务来实现这一点?)

对我在这里尝试做的方式的任何见解,也欢迎。当我试图做的事情完全愚蠢时,我不介意被告知。


我脑子里已经有了:

也许我可以将主机上的 sshd 套接字与容器共享为一个ro卷?这意味着容器内的 sshd 可以获取到*.mydomain.com. 有没有办法让容器内的 sshd拒绝gogs.mydomain.comor之外的所有连接git.mydomain.com?但是,主机上的 sshd 将获取所有连接,*.mydomain.com包括gogs.mydomain.com; 所以会有冲突。我不知道,我还没有真正尝试过。我应该试试吗?

And*_*gge 3

“通过主机名”执行此操作根本不在 ssh 的范围内。ssh 协议本身不支持基于名称的虚拟主机(事实上 HTTP 是此处规则的例外)。

接收端的 SSHd 永远无法知道您要求客户端连接到的主机名,因为此信息不会在协议内部传递。

如果您只需要几个客户端来使用此功能,您可以将每个客户端配置为连接到您的服务器,然后跳转到 docker 容器,如下所示:

Host yourcontainer
        Hostname internal.ip.of.your.container
        ProxyCommand ssh your.docker.host nc %h %p
Run Code Online (Sandbox Code Playgroud)

这样,ssh 将调用代理命令,该命令将打开到您的主机的 ssh 会话并调用netcat以建立到您的容器的连接。这样你就不需要将容器的 ssh 端口暴露给外界。