# 反代理
一般实现不同域名直连,也即表示你不带端口实现访问部署在不同端口的多服务,那么你需要腾出 80、443、81 端口,以便反代理工具接管这些端口数据流向;因此在使用 Nginx 反代理实现统一端口路由多服务时,必须为 Nginx 服务至少腾出 80、443 端口,然后让 Nginx 通过监听 80、443 端口,当外部统一通过 80 端口访问服务时,根据 URL 路径前缀转发到部署在不同端口的服务上。
# Nginx 的处理顺序
当请求到达时,Nginx 会:
- 匹配
server_name
完全相同的配置 - 如果没有完全匹配,匹配通配符配置
- 如果没有通配符匹配,使用
default_server
- 如果没有
default_server
,使用第一个定义的 server 块
查看 default_server
是否存在:
grep -r "default_server" /etc/nginx/ |
如若没有,在配置文件夹里(一般在 /etc/nginx/conf.d/
目录)编写 other.conf
,防止其它不匹配的 server_name
非法跳转访问:
server {
listen 80 default_server;
listen [::]:80 default_server;
return 444; # 关闭连接
}
# 主机安装使用
由于本人是在 Openmediavault 服务器中操作,因此它是默认安装了 Nginx 服务的,如果是其它 Linux 平台,并没有 Nginx 服务,可以如下 "安装运行" 开启 Nginx 服务,若不清楚是否存在 Nginx 服务,可用 nginx -v
命令查看。
# 安装运行
以 debian 平台为示例,更新安装 Nginx:
sudo apt update | |
sudo apt install nginx |
启动并启用 Nginx:
sudo systemctl start nginx # 启动服务 | |
sudo systemctl enable nginx # 设置开机自启 |
# 编写 Nginx 配置
创建该服务的配置文件:
vim /etc/nginx/conf.d/app1_service.conf |
在这里选择最通用 /etc/nginx/conf.d/
目录存放自定义配置,避免不同平台存在差异。
note:
/etc/nginx/conf.d/
- 这是放置自定义配置最推荐、最通用的目录。
- 你可以在里面创建任意名称的
.conf
文件(例如my-website.conf
,reverse-proxy.conf
),Nginx 会自动加载它们。 - 例如:
/etc/nginx/conf.d/reverse-proxy.conf
/etc/nginx/sites-available/
和/etc/nginx/sites-enabled/
(常见于 Debian / Ubuntu)sites-available/
:存放所有可用的服务器块(虚拟主机)配置文件。这是一个 “仓库”。sites-enabled/
:存放当前已启用的服务器块配置文件的符号链接(快捷方式)。- 这种设计允许你轻松启用 / 禁用站点。
- 管理命令:
sudo ln -s /etc/nginx/sites-available/my-site /etc/nginx/sites-enabled/
(启用)
假设给 app1.domain.com
域名访问绑定至 8081
端口,写入如下信息:
server {
listen 80;
listen [::]:80;
server_name app1.domain.com;
#access_log /var/log/nginx/app1.access.log;
# proxy the app1 scripts to Nginx listening on 127.0.0.1:8081
location / {
proxy_set_header Host $proxy_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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_buffering off;
proxy_pass http://localhost:8081;
}
}
使用下面的命令检查一下修改后的配置文件是否有错:
nginx -t |
使其生效:
nginx -s reload |
至此,一个简单的域名访问服务的操作就完成了,同理你可以配置更多不同的域名绑至不同的端口服务。
# Docker 部署使用
同样的,若是需要域名直连访问不同端口服务,需要预留监听 80、443 的端口给到 Nginx docker 服务。
# 安装运行
先临时启动一个 Nginx docker 提取主要配置文件,当然你也可以复制一份已有的配置映射到容器中。
执行以下命令,临时创建 Nginx docker 服务:
docker run --rm -d --name nginx -p 80:80 nginx |
提取里面的配置文件到主机中,以便编辑配置,你说为什么不直接在容器中操作?拜托,里面可是连个默认的文本编辑器都没有,只有最小系统及 Nginx 服务;而至于为啥不直接把里面的文件反映射到主机?是因为一旦映射后,容器里面的文件夹将根据主机内容变化,即主机上需映射的文件夹如果是空,一旦映射到容器里,容器上的文件夹跟着变空;因此需要先提取出来再映射:
mkdir -p /<path>/nginx/config/conf.d | |
docker cp nginx:/etc/nginx/conf.d/default.conf /<path>/nginx/config/conf.d | |
docker cp nginx:/etc/nginx/nginx.conf /<path>/nginx/config |
停止 Nginx docker 服务,此时由于 --rm
参数将自动删除该容器:
docker stop nginx |
正式启动 Nginx docker 容器:
docker run -d \ | |
--name=nginx \ | |
-e PUID=1000 \ | |
-e PGID=993 \ | |
-e TZ=Asia/Shanghai \ | |
-p 80:80 \ | |
-p 81:81 \ | |
-p 443:443 \ | |
-v /<path>/nginx/config/nginx.conf:/etc/nginx/nginx.conf \ # 主配置文件 | |
-v /<path>/nginx/config/conf.d:/etc/nginx/conf.d \ # 附加配置文件目录 | |
-v /<path>/nginx/data:/usr/share/nginx/html:ro \ # 默认网站根目录 | |
-v /<path>/SSL:/usr/share/ssl:ro \ # SSL 证书目录 | |
--health-cmd="curl -fs -S --max-time 3 http://localhost || exit 1" \ | |
--health-interval=30s \ | |
--health-timeout=10s \ | |
--health-retries=3 \ | |
--health-start-period=5s \ | |
--add-host host.docker.internal:host-gateway \ # 用于解析链接到宿主机中的服务 | |
--restart always \ | |
nginx:latest |
note:
--add-host host.docker.internal:host-gateway
该参数选项非常重要,后于后面配置 Nginx 配置时,使得在 docker 里面能访问到主机上的服务及其它 docker 容器服务(哪怕所有容器不在同一网络);而它的大概意思也就是容器内部访问这个域名 host.docker.internal
时,就会访问到对应的主机上的 host-gateway
地址。
# 编写 Nginx 配置
docker 上的配置文件编写跟上面主机编写的 Nginx 配置变化不大,唯一需要更改的是 proxy_pass
字段中的参数,由于当前 Nginx 是在容器中,因此需要把网络转发到宿主机上面,再通过宿主机的本机路由再转给相应的端口服务:
server {
listen 80;
listen [::]:80;
server_name app1.domain.com;
#access_log /var/log/nginx/app1.access.log;
# proxy the app1 scripts to Nginx listening on 127.0.0.1:8081
location / {
proxy_set_header Host $proxy_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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_buffering off;
proxy_pass http://host.docker.internal:8081;
}
}
# 安装 SSL
在以上配置中,如果你通过访问可以知道当前页面是 HTTP 页面,同时第一次访问配置好的服务,会提示当前非 HTTPS 页面的警告,那么为了安全及消除这样的警告,你需要为你的服务安装 SSL 认证,使其启用 HTTPS 访问。
根据 使用 acme.sh 签发 SSL 证书 文章中成功获取签发的证书后,即可为相应的域名绑定服务并安装 SSL 证书了:
# HTTP 重定向到 HTTPS
server {
listen 80;
listen [::]:80;
server_name app1.domain.com;
return 301 https://$server_name$request_uri;
}
# HTTPS 服务器
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name app1.domain.com;
# SSL 证书路径
#RSA
ssl_certificate /<path>/SSL/RSA/chain.crt;
ssl_certificate_key /<path>/SSL/RSA/private.key;
#ECC
ssl_certificate /<path>/SSL/ECC/chain.crt;
ssl_certificate_key /<path>/SSL/ECC/private.key;
# 基本 SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets on;
# 代理设置
location / {
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_buffering off;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
proxy_pass http://localhost:8081; # 如果是 docker 需要更换为 host.docker.internal
}
# 记录
access_log /var/log/nginx/app1.access.log;
error_log /var/log/nginx/app1.error.log;
}
测试:
curl -IL http://app1.domain.com |