如何设置 NGINX Docker 反向代理?
介绍
想象一下,你设置了本地服务器,并基于它创建了一个前端应用程序。要访问某个应用程序的 API,你需要输入 example.com:3000;而对于应用程序本身,你需要输入类似 example.com:4040 的内容。一个应用程序可能有多个端口用于访问不同的页面:主页、仪表盘、联系人、表格等等。现在想象一下,你需要记住多个应用程序的多个端口。
如果只像这样访问 API:example.com/api,访问应用:example.com/app,那就太不靠谱了。与其输入愚蠢的端口,不如为多个容器建立路由,这些路由的 URL 可以是任意的。使用 docker 的反向代理可以更轻松地实现这一点。
什么是代理?
让我试着用一个比喻来解释一下。假设你走进你最喜欢的餐厅。你饿了,想吃你最喜欢的菜。你给服务员点了菜。服务员拿到你的订单后,去了厨房。服务员让厨师按照你要求的做所有菜。厨师做好了菜。服务员把菜端上来。简单吧?
需要注意的关键事项:你要求服务员帮忙。服务员无需你去厨房就满足了你的要求。厨师不知道这道菜是给谁做的。
在这个例子中,服务员是代理,厨师是互联网。代理充当您和互联网之间的防火墙。代理提供安全性、隐私性和其他级别的功能。您可以在尼日利亚设置代理服务器。然后,您可以在互联网上发出 HTTP 请求,该请求将首先发送到尼日利亚,然后再发送到互联网(用简单的语言来说)。
代理的另一个例子是同一家公司或一栋楼里的多台电脑。公司内部所有电脑的 IP 地址都位于公司的最高 IP 地址之下。所有互联网请求都使用同一个 IP 地址,这使得追踪到具体哪台电脑变得更加困难。
代理的核心在于确保外部请求的安全。
什么是反向代理
如果我在这里不打个比方就太不公平了。这个比方很老套了。免责声明:别评判我,我是个技术控。假设你早上醒来,看到邮递员在你家门口。邮递员给你寄来多封信、发票、明信片和其他形式的信件。所有这些信件都从不同的地方寄出,但最终都会到达你正确的地方。
注意:寄件人无需直接与您联系。邮递员会代表您从多个来源检索信件。
在此示例中,邮递员是反向代理,源是客户端,而您正在应用。客户端发出 HTTP 请求与您的应用程序通信。客户端想要查看应用程序,因此客户端创建此请求:example.com。但在后台,反向代理会将此请求转换为 example.com:8080。如果客户端或用户想要查看 API,则客户端会创建此请求:example.com/api,但在后台,反向代理会将其转换为 example.com:3000。反向代理位于 Web 服务器的前端,并将客户端请求转发到服务器。实施反向代理通常是为了提高安全性、性能和可靠性。
反向代理让您可以发出安全的内部请求。
什么是 Docker?
Docker 是一款流行的企业级 PAAS(平台即服务),用于通过容器创建、运行和部署应用程序。容器允许开发人员将应用程序与必要的模块、库和依赖项打包在一起,并将其作为软件包进行部署。Docker 位于现有的主机操作系统上,允许开发人员在虚拟机上创建轻量级容器来运行其应用程序。因此,开发人员可以在一个主机操作系统上创建多个容器并运行多个应用程序。企业无需花费巨资购买多个操作系统来部署单个应用程序。
如何设置 NGINX Docker 反向代理
让我们创建一个使用 Docker 设置 NGINX 反向代理的用例。在 Docker 容器内部,除非将私有端口和 IP 地址绑定到主机,否则无法访问它们。我们可以使用反向代理通过单个 80 端口访问在多个容器上运行的多个 Web 应用程序。我们将设置一个 Nginx 容器,该容器将绑定到 Docker 主机的 80 端口,并将请求转发到在多个容器上运行的 Web 应用程序。
我们需要设置两个容器,用于存放 Web 服务或两个可以用任何语言编写的应用程序。本教程将使用一个简单的 index.html 页面来创建两个 Web 服务。
我们的 Web 服务 1 的结构:
webservice1
├── docker-compose.yml
└── index.html
cd ~
mkdir webservice1
cd webservice1
vi docker-compose.yml
然后将此 YAML 代码粘贴到文件中:
version: '2'
services:
app:
image: nginx:1.9
volumes:
- .:/usr/share/nginx/html/
expose:
- "80"
快速提示:确保所有 YAML 文件的缩进格式正确。您也可以使用 VS Code 来正确格式化它们。
现在,让我们为 webservice1 创建一个简单的 HTML 页面:
vi index.html
<!DOCTYPE html>
<html>
<head>
<title>Web service 1</title>
</head>
<body>
<h1>Welcome to website 1</h1>
</body>
</html>
现在,使用 docker-compose 命令构建 webservice1
docker-compose build
启动容器
docker-compose up -d
列出所有容器
docker ps -a
您应该会看到带有名称的容器:
site2_app_1
类似地,为webservice2创建第二个容器
cd ~
mkdir webservice2
cd webservice2
vi docker-compose.yml
YAML 文件的代码:
version: '2'
services:
app:
image: nginx:1.9
volumes:
- .:/usr/share/nginx/html/
expose:
- "80"
创建索引文件
vi index.html
创建一个简单的 HTML 响应
<!DOCTYPE html>
<html>
<head>
<title>Web service 2</title>
</head>
<body>
<h1>Welcome to website 2</h1>
</body>
</html>
使用docker-compose命令构建webservice2容器
docker-compose build
启动容器
docker-compose up -d
太棒了!现在我们有两个正在运行的 Docker 容器,我们想将它们绑定到代理。注意:这两个容器都应该在 80 端口上运行,所以我们需要设置一个代理来相应地转发请求。所以,让我们来设置代理。
这将是代理的文件结构:
proxy/
├── backend-not-found.html
├── default.conf
├── docker-compose.yml
├── Dockerfile
├── includes
│ ├── proxy.conf
│ └── ssl.conf
└── ssl
├── site1.crt
├── site1.key
├── site2.crt
└── site2.key
让我们首先创建所有必要的文件。
cd ~
mkdir proxy
cd proxy
touch Dockerfile
touch backend-not-found.html
touch default.conf
touch docker-compose.yml
mkdir includes
mkdir ssl
cd includes
touch proxy.conf
touch ssl.conf
创建 Dockerfile
vi Dockerfile
FROM nginx:1.9
COPY ./default.conf /etc/nginx/conf.d/default.conf
COPY ./backend-not-found.html /var/www/html/backend-not-found.html
COPY ./includes/ /etc/nginx/includes/
COPY ./ssl/ /etc/ssl/certs/nginx/
Dockerfile 用于创建 Docker 镜像。然后,Docker 镜像用于创建 Docker 容器。在此 Dockerfile 中,镜像将引用现有的 Nginx Docker 镜像来创建自定义 Docker 镜像。然后,通过将本地计算机上的现有文件复制到 Docker 镜像来构建镜像。我们主要添加一个配置文件、基本的错误 HTML、一些代理配置文件以及稍后将生成的证书。
创建 default.conf
vi default.conf
# web service1 config.
server {
listen 80;
listen 443 ssl http2;
server_name site1.test;
# Path for SSL config/key/certificate
ssl_certificate /etc/ssl/certs/nginx/site1.crt;
ssl_certificate_key /etc/ssl/certs/nginx/site1.key;
include /etc/nginx/includes/ssl.conf;
location / {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://site1_app_1;
}
access_log off;
error_log /var/log/nginx/error.log error;
}
# web service2 config.
server {
listen 80;
listen 443 ssl http2;
server_name site2.test;
# Path for SSL config/key/certificate
ssl_certificate /etc/ssl/certs/nginx/site2.crt;
ssl_certificate_key /etc/ssl/certs/nginx/site2.key;
include /etc/nginx/includes/ssl.conf;
location / {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://site2_app_1;
}
access_log off;
error_log /var/log/nginx/error.log error;
}
# Default
server {
listen 80 default_server;
server_name _;
root /var/www/html;
charset UTF-8;
error_page 404 /backend-not-found.html;
location = /backend-not-found.html {
allow all;
}
location / {
return 404;
}
access_log off;
log_not_found off;
error_log /var/log/nginx/error.log error;
}
在这个 Nginx 配置文件中,有两个主要的服务器组件分别用于这两个 Web 服务。这两个容器都将监听 Nginx 的 80 端口。要访问这两个容器,我们可以在它们定义的 server_name 上执行 curl 命令:HTTP://site1.test或HTTP://site2.test。这两个服务器组件将帮助 Nginx 将请求转发到相应的 Web 服务容器。此配置还允许 Nginx 抛出自定义的错误 HTML 页面,而不是默认的 Nginx 错误页面。这两个服务器组件都会指示 Nginx 从合适的位置选择 SSL 证书。
创建 docker-compose.yml
vi docker-compose.yml
version: '2'
services:
proxy:
build: ./
networks:
- site1
- site2
ports:
- 80:80
- 443:443
networks:
site1:
external:
name: site1_default
site2:
external:
name: site2_default
注意:将我的文件复制到终端时,请确保缩进正确。
这是我们实际实现代理的主要部分。(技术上,我们在 default.conf 中实现了它)docker-compose.yml 文件会将两个名为 site1 和 site2 的外部网络连接到代理。此代理的 80/443 端口绑定是在 Docker 主机的 80/443 端口上实现的。我们已经为 Web 服务创建了两个 Docker 容器,并创建了两个名为 site1_default 和 site2_default 的外部 Docker 网络。
创建证书和密钥
对于 Web 服务 1
cd ssl
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout site1.key -out site1.crt
对于 Web 服务 2
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout site2.key -out site2.crt
现在让我们为代理创建一个标准配置。
cd includes
vi proxy.conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_intercept_errors on;
创建标准 SSL 配置以解码 SSL 证书和密钥
vi ssl.conf
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-
ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-
SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-
GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-
AES128-SHAECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-
SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:
DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-
DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:
AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-
CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;
此配置有助于使用密文解码 SSL 证书和密钥。
让我们添加主机名和 IP 地址
cd ~
vi /etc/hosts
172.31.30.78 site1.test
172.31.30.78 site2.test
这些是 Docker 主机的私有 IP 地址。请求将到达 Docker 主机的 80 端口,但会被重定向到 Nginx 容器的 80 端口。
最后,我们来构建一个代理容器
docker-compose build
我们有一个容器,现在运行容器
docker-compose up -d
现在,您应该看到三个正在运行的 Docker 容器。两个用于 Web 服务,一个用于代理容器。
docker ps -a
让我们验证一下反向代理是否正常工作
curl site1.test
您应该会看到以下响应:
<!DOCTYPE html>
<html>
<head>
<title>Web service 1</title>
</head>
<body>
<h1>Welcome to website 1</h1>
</body>
</html>
干得好!✨
容器化应用程序的优势之一是您可以轻松添加和部署应用程序。您可以通过在 default.conf 中添加配置并在 docker-compose YAML 文件中添加外部网络来添加任意数量的 Web 服务容器。此示例说明了使用 docker 和 Nginx 设置反向代理是多么简单。想象一下,有多个应用程序在 docker 容器上运行,并且它们的所有请求都由 Nginx 容器重定向。您无需担心手动添加配置。您可以使用 Docker API 轻松自动化该过程,这是一个值得在另一篇博文中讨论的概念。
感谢您阅读该博客,我希望它能帮助您理解这个非常独特的概念。
如果您有任何问题或疑虑,请给我留言。
文章来源:https://dev.to/sukhbirsekhon/what-is-docker-reverse-proxy-45mm