# 反代理

一般实现不同域名直连,也即表示你不带端口实现访问部署在不同端口的多服务,那么你需要腾出 80、443、81 端口,以便反代理工具接管这些端口数据流向;因此在使用 Nginx 反代理实现统一端口路由多服务时,必须为 Nginx 服务至少腾出 80、443 端口,然后让 Nginx 通过监听 80、443 端口,当外部统一通过 80 端口访问服务时,根据 URL 路径前缀转发到部署在不同端口的服务上。

# Nginx 的处理顺序

当请求到达时,Nginx 会:

  1. 匹配 server_name 完全相同的配置
  2. 如果没有完全匹配,匹配通配符配置
  3. 如果没有通配符匹配,使用 default_server
  4. 如果没有 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
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

夏沫の浅雨 微信支付

微信支付

夏沫の浅雨 支付宝

支付宝