在购买并备案域名,在云服务器提供商处完成绑定后,虽然用 域名:port
的方式可以访问到云服务器的特定端口,但是在跳转到相应页面后,服务器的ip和端口号会直接暴露。如何配置实现域名直接访问某服务,且不将ip和端口号暴露给访问者呢?今天的文章就介绍一下博主采用的 docker容器化部署 + nginx反向代理 的方案,记录一下在配置过程中碰到的坑:
初次尝试 iptable流量转发 (不推荐)
通过域名访问时,默认会调用域名绑定服务器的 80 端口(HTTP)。为了让访问域名的流量转发到特定服务(例如 WordPress 博客,端口为 6666),可以使用 iptables 命令将 80 端口的流量重定向:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 6666
这种方法虽然可以通过域名直接访问服务,但问题在于:端口号仍然会暴露,并不是理想的解决方案。因此,不推荐这种方法。
nginx 反向代理
为了解决端口暴露的问题,我选择用 Docker 来搭建 Nginx,并通过反向代理来隐藏目标服务的实际端口。
首先,搭建 Nginx 的过程不再赘述。接下来是关键的 Nginx 配置(修改 nginx.conf 文件):
本人第一次的配置是这样的:
upstream blog_server{
server 127.0.0.1:6666;
}
server {
listen 80;
server_name superbloom.cn;
location / {
proxy_pass http://blog_server;
}
}
也就是将来自域名 superbloom.cn 访问的 80 端口流量都代理转发到本机的6666端口,也就是docker容器对外的端口。
然而这样配置后转发并没有成功!!!
问题排查
在多次排查后,发现问题可能不出在对nginx的配置上,而是 Nginx容器 与 服务提供容器之间的通信问题,因为nginx搭载在docker容器中,所以nginx中配置的127.0.0.1
实际上指向的是这个容器本身的虚拟机,而不是宿主机。这意味着,这里的127.0.0.1:6666
访问的是本容器内部的6666端口,当然访问不到正确结果。
要解决问题,这里有两个解决方案:
1. 设置nginx的网络模式,使其可以与宿主机通信
在创建并启动容器时,将容器设置为host模式。
比如host模式下,容器和宿主机共享IP地址和端口空间,容器内的服务可以直接通过localhost访问宿主机的服务。我们可以将 nginx 设置为host模式,就可以直接通过localhost:6666 访问到目标服务了。
docker run --network host <image>
这种方案简单易行,但是每次代理都需要访问宿主机的端口,未充分利用 Docker 的隔离性。因此,尽管这种方法有效,但并不是最佳选择。
2. 将nginx和目标服务放在一个docker网络下,使其在网络内部通信
更优雅的解决方案是:将 Nginx 和目标服务容器置于同一个 Docker 网络中。这样,Nginx 就可以通过内部网络访问目标服务的内部端口,而不需要公开服务容器的对外端口。
因为目标服务容器的对外端口没有使用到,外界的访问都是通过nginx代理转发过来的,完全可以关闭该对外接口,让提供服务的容器只在docker内部网络提供服务,整个服务网络只对外开放nginx监听接口,完全实现服务的隔离,提高了整体服务的安全性!
具体步骤如下:
1 创建该服务的docker网络:
docker network create service_network
2 将 Nginx 容器和目标服务容器(或许还有服务数据库)都连接到这个网络:
docker run --network service_network --name service_nginx -d nginx
docker run --network service_network --name wordpress_blog -d my_blog_image
3 在 Nginx 的配置中,将 upstream 直接配置为目标服务容器的名称,而不是 127.0.0.1,端口也设置为容器网络内部接口:
upstream blog_server {
server wordpress_blog:80;
}
server {
listen 80;
server_name superbloom.cn;
location / {
proxy_pass http://blog_server;
}
}
4 记得重启nginx!
这样,Nginx 通过 Docker 网络内部的名称 my_blog 访问服务容器,而服务容器的端口对外是不可见的。访问者只能通过 Nginx 的 80 端口访问服务,避免了端口泄露,并且确保了 Docker 的隔离性和安全性。
挖坑:需要更新支持HTTPS访问的日志(๑•̀ㅁ•́ฅ)