Nginx:向外代理暴露Web服务
Module:
Categories:
Pigsty 的 Infra 模块默认会在节点上安装 Nginx,这是一个高性能的 Web 服务器。 Pigsty 使用 Nginx 作为所有本地 WebUI 服务的统一入口,并将其用作本地软件仓库,向内网其他节点提供服务。
当然,用户可以根据需求,调整配置,将 Nginx 用作标准的 Web 服务器,对外提供服务。 无论是作为反向代理,还是直接作为网站服务器,都可以通过适当的配置实现。 Pigsty 本身的文档站与仓库也是通过 Pigsty 自建的 Nginx 对外提供的。
配置概览
Nginx 服务器配置由 infra_portal
参数指定。
用户在这里声明所有需要通过 Nginx 代理的域名,以及对应的上游服务器端点(endpoint
)或本地目录路径(path
)。
例如,默认情况下,Pigsty 会这样配置 Nginx,下面的配置会使用 Nginx 对外暴露 Home,Grafana,Prometheus,Alertmanager 四项服务:
infra_portal: # domain names and upstream servers
home : { domain: h.pigsty }
grafana : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
prometheus : { domain: p.pigsty ,endpoint: "${admin_ip}:9090" }
alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9093" }
blackbox : { endpoint: "${admin_ip}:9115" }
loki : { endpoint: "${admin_ip}:3100" }
当安装 Pigsty 时,Pigsty 会自动根据以上配置生成 Nginx 的配置文件。
/etc/nginx/conf.d/haproxy/ # <--- 存放着 HAPROXY 管理界面的位置定义
/etc/nginx/conf.d/home.conf # <--- Pigsty 默认服务器定义(本地软件源,HAPROXY转发)
/etc/nginx/conf.d/grafana.conf # <--- 代理访问内网 Grafana 服务器
/etc/nginx/conf.d/prometheus.conf # <--- 代理访问内网 Prometheus 服务器
/etc/nginx/conf.d/alertmanager.conf # <--- 代理访问内网 Alertmanager 服务器
Nginx 默认服务于 80/443 端口,home
服务器是本地软件源,同时也是默认的 Nginx 服务器。
如果你想通过 Nginx 访问其他服务,只需要在 infra_portal
中添加相应的配置即可,任何带有 domain
参数的配置都会被 Nginx 自动代理。
配置剧本
当安装 Pigsty 时,这些配置会在默认的 install.yml
剧本,或者 infra.yml
剧本中自动生效。
但是用户也可以在 Pigsty 部署后使用 infra.yml
剧本中的 nginx
子任务重新初始化 Nginx 配置。
./infra.yml -t nginx # 重新配置 Nginx
./infra.yml -t nginx_config # 重新生成 Nginx 配置
./infra.yml -t nginx_launch # 重新启动 Nginx 服务
这意味着如果您想要调整 Nginx 服务器的配置,只需要修改 pigsty.yml
配置文件,并执行上面的 nginx
任务即可生效。
当然,你也可以选择先使用 nginx_config
子任务重新生成 Nginx 配置文件,人工检查后使用 nginx -s reload
重新在线加载配置。
配置详情
配置变量 infra_portal
通常定义在全局变量 all.vars
中,默认值如下所示:
all:
vars:
infra_portal: # domain names and upstream servers
home : { domain: h.pigsty }
grafana : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
prometheus : { domain: p.pigsty ,endpoint: "${admin_ip}:9090" }
alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9093" }
blackbox : { endpoint: "${admin_ip}:9115" }
loki : { endpoint: "${admin_ip}:3100" }
默认配置意味着,用户默认可以通过:
h.pigsty
访问home
服务器,这是默认服务器,对应 Pigsty 的文件系统首页与本地软件源,通常指向本机上的/www
目录。g.pigsty
访问grafana
服务器,这是默认的 Grafana 服务,通常指向管理节点(admin_ip
)上的3000
端口。p.pigsty
访问prometheus
服务器,这是默认的 Prometheus 服务,通常指向管理节点(admin_ip
)上的9090
端口。a.pigsty
访问alertmanager
服务器,这是默认的 Alertmanager 服务,通常指向管理节点(admin_ip
)上的9093
端口。
注意这里的 blackbox
和 loki
没有配置 domain
参数,因此不会被添加到 Nginx 的配置中,因为它们没有配置 domain
参数。
但是这并不意味着用户可以直接把这两项定义移除掉,因为内网中的其他服务可能会引用这里的配置(例如日志 Agent 会引用 Loki endpoint 地址发送日志)
用户可以通过丰富的配置参数,为不同的服务配置不同的配置,如下所示:
服务器参数
每一条服务器记录都有一个独一无二的 name
作为 key
,一个配置字典作为 value
。在配置字典中,目前有以下几个可用配置项:
-
domain
:可选,指定代理的域名,如果不填写,则 Nginx 不会对外暴露此服务。对于那些需要知道
endpoint
地址,但不想对外暴露的服务(例如 Loki, Blackbox Exporter),可以不填写此参数 -
endpoint
:可选,指定上游服务的地址,可以是IP:PORT
或者DOMAIN:PORT
。- 当此服务器为上游服务时,可以指定此参数,Pigsty 会生成一个标准的反向代理配置,并将请求转发给上游的
endpoint
地址。 - 此参数与
path
参数是互斥的,不能同时存在:如果一个服务器是反向代理服务器,那么它不能同时是本地网页服务器。 - 在此参数值中,可以使用
${admin_ip}
占位符,Pigsty会填入admin_ip
的值。 - 如果指定了此参数,则 Pigsty 默认会使用
endpoint.conf
配置模板,这是反向代理的标准模板 - 如果同时指定了
conf
参数,则conf
参数指定的模板有更高的优先级。 - 如果上游强制要求 HTTPS 访问,你可以额外设置
scheme: https
参数。
- 当此服务器为上游服务时,可以指定此参数,Pigsty 会生成一个标准的反向代理配置,并将请求转发给上游的
-
path
:可选,指定本地 Web 服务器的根目录,可以是绝对路径或者相对路径。- 当此服务器为本地 Web 服务器时,可以指定此参数,Pigsty 会生成一个标准的本地 Web 服务器配置,并将请求转发给本地的
path
目录。 - 此参数与
endpoint
参数是互斥的,不能同时存在,如果一个服务器是本地网页服务器,那么它不能同时是上游代理服务器。 - 如果指定了此参数,则 Pigsty 默认会使用
path.conf
配置模板,这是本地 Web 服务器的标准模板 - 如果同时指定了
conf
参数,则conf
参数指定的模板有更高的优先级。 - 如果你希望 Nginx 自动生成文件列表索引,可以设置
index: true
参数,默认是不打开的。
- 当此服务器为本地 Web 服务器时,可以指定此参数,Pigsty 会生成一个标准的本地 Web 服务器配置,并将请求转发给本地的
-
conf
: 可选,如果指定,则将会使用templates/nginx/
中定义的配置模板。- 当你想要任意定制 Nginx 配置时可以指定此参数,指定一个存在于
templates/nginx
目录中的模板文件名。 - 如果没有指定此参数,Pigsty 将根据服务器的类型(Home, Proxy, Path)自动应用相应的 默认模板:
home.conf
: 默认服务器的模板(用于 home)。endpoint.conf
: 上游服务代理的模板(例如:用于Grafana,Prometheus 等)path.conf
:本地 Web 服务器的模板(默认没有使用,但home
是特殊的本地服务器)
- 当你想要任意定制 Nginx 配置时可以指定此参数,指定一个存在于
-
certbot
: 可选,指定此服务器的certbot
证书名称,Pigsty 会自动使用certbot
生成的证书。- 如果您的证书是使用 certbot 生成的,你可以指定此参数为
certbot
生成的证书名称,Pigsty 会自动使用此证书。 - 您应当填入 certbot 生成证书的域名部分。例如
certbot: pigsty.cc
会自动使用- 证书:
/etc/letsencrypt/live/pigsty.cc/fullchain.pem
,但可以被显式指定的cert
参数(完整路径)覆盖。 - 私钥:
/etc/letsencrypt/live/pigsty.cc/privkey.pem
,但可以被显式指定的key
参数(完整路径)覆盖。
- 证书:
- certbot 证书名称通常与
domain
参数相同,例如g.pigsty
的证书名称为g.pigsty.cc
,但也有特例:当你同时申请多个证书时,certbot 会生成一个捆绑证书,名称为申请列表中的第一个域名。
- 如果您的证书是使用 certbot 生成的,你可以指定此参数为
-
cert
: 可选,指定此服务器的 SSL 证书文件名,需要给出完整路径。 -
key
: 可选,指定此服务器的 SSL 私钥文件名,需要给出完整路径。 -
domains
: 可选,除了默认的domain
域名,您还可以为此服务器指定多个额外的域名 -
scheme
: 可选,指定此服务器的协议(http
/https
),留空则默认使用 http,通常用于强制要求 HTTPS 访问的上游 Web 服务。 -
index
: 可选,如果设置为true
, Nginx 会为目录自动生成文件列表索引页面,方便浏览文件,对于软件仓库类通常可以打开,对于网站通常应当关闭。 -
log
: 可选,如果指定,则日志将打印到<value>.log
,而非默认的access.log
中。- 作为特例,上游代理服务器的日志总是会打印到
<name>.log
中。
- 作为特例,上游代理服务器的日志总是会打印到
复杂的配置样例
Pigsty 自带的配置模板 conf/demo.yml
有一个更详细的案例,给出了 Pigsty 文档站的配置样例。
是的,Pigsty 的文档站也是在一台普通云服务器上使用 Pigsty 本身建设的,其配置如下所示:
infra_portal:
home : { domain: home.pigsty.cc }
grafana : { domain: demo.pigsty.cc ,endpoint: "${admin_ip}:3000" ,websocket: true ,cert: /etc/cert/demo.pigsty.cc.crt ,key: /etc/cert/demo.pigsty.cc.key }
prometheus : { domain: p.pigsty.cc ,endpoint: "${admin_ip}:9090" }
alertmanager : { domain: a.pigsty.cc ,endpoint: "${admin_ip}:9093" }
cc : { domain: pigsty.cc ,path: "/www/pigsty.cc" ,cert: /etc/cert/pigsty.cc.crt ,key: /etc/cert/pigsty.cc.key }
blackbox : { endpoint: "${admin_ip}:9115" }
loki : { endpoint: "${admin_ip}:3100" }
minio : { domain: m.pigsty.cc ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
postgrest : { domain: api.pigsty.cc ,endpoint: "127.0.0.1:8884" }
pgadmin : { domain: adm.pigsty.cc ,endpoint: "127.0.0.1:8885" }
pgweb : { domain: cli.pigsty.cc ,endpoint: "127.0.0.1:8886" }
bytebase : { domain: ddl.pigsty.cc ,endpoint: "127.0.0.1:8887" }
jupyter : { domain: lab.pigsty.cc ,endpoint: "127.0.0.1:8888", websocket: true }
gitea : { domain: git.pigsty.cc ,endpoint: "127.0.0.1:8889" }
wiki : { domain: wiki.pigsty.cc ,endpoint: "127.0.0.1:9002" }
noco : { domain: noco.pigsty.cc ,endpoint: "127.0.0.1:9003" }
supa : { domain: supa.pigsty.cc ,endpoint: "10.10.10.10:8000" ,websocket: true }
dify : { domain: dify.pigsty.cc ,endpoint: "10.10.10.10:8001" ,websocket: true }
odoo : { domain: odoo.pigsty.cc ,endpoint: "127.0.0.1:8069" ,websocket: true }
mm : { domain: mm.pigsty.cc ,endpoint: "10.10.10.10:8065" ,websocket: true }
这个文档站的 Nginx 配置要比默认的配置复杂一些:
home
服务器使用了一个真实的公网域名home.pigsty.cc
grafana
服务器使用了一个真实的公网域名demo.pigsty.cc
,并配置了websocket: true
以支持 WebSocket 连接。cc
服务器是 Pigsty 的文档站,它使用了真实公网域名pigsty.cc
,并指向了本地的/www/pigsty.cc
目录。- 下面还定义了一系列 Docker App 服务器,将这些应用的 Web 界面通过域名对外暴露。
cc
与grafana
直接通过cert
与key
参数指定了 HTTPS 证书。
配置域名
您可以通过 IP:Port 直接访问特定服务,例如 IP:3000 访问 Grafana,IP:9090 访问 Prometheus。 但这样的行为通常并不可取,常规安全最佳实践要求您通过域名访问服务,而不是通过 IP:Port 直接访问。 通过域名访问意味着你只需要对外暴露一个 Nginx 服务,减小攻击面,并便于统一添加访问控制!
小知识:Nginx 是如何区分不同服务器的?
Nginx 通过浏览器设置的 HOST
首部中的域名,来区分不同的服务。
所以如果您有多种服务,尽管都使用同一个 IP 地址的 80/443 端口,但 Nginx 仍然可以区分它们。
但限制条件就是,您 必须 通过域名访问服务,而不是通过 IP:Port 直接访问。如果您直接用 IP 来访问 80/443 端口,那么您只能访问到默认的 home
服务器。
使用域名访问 Pigsty WebUI 时,您需要配置 DNS 解析,有以下几种方式:
- 使用真域名,通过云厂商/域名厂商的 DNS 解析服务,将公网域名指向你的服务器公网IP
- 使用内网域名,在内网 DNS 服务器上添加内网域名,并指向你服务器的内网IP地址
- 使用本机域名,在你浏览器所在主机的(
/etc/hosts
)添加一条静态解析记录
通过本机访问
如果你是唯一的用户,那么可以直接修改本地 /etc/hosts
文件(Linux/MacOS),
在 Windows 系统上,您需要修改 C:\Windows\System32\drivers\etc\hosts
文件。
无论是什么系统,修改此文件通常需要管理员权限。
你可以添加以下静态解析记录,将 Pigsty 的默认域名指向你的服务器IP地址:
<ip_address> h.pigsty a.pigsty p.pigsty g.pigsty
如果你会用到其他服务,也可以添加其他服务对应的域名解析记录:
10.10.10.10 h.pigsty a.pigsty p.pigsty g.pigsty
10.10.10.10 api.pigsty ddl.pigsty adm.pigsty cli.pigsty lab.pigsty
10.10.10.10 supa.pigsty noco.pigsty odoo.pigsty dify.pigsty
通过办公网访问
如果您的服务需要在办公网共享访问,例如让所有同事都可以通过域名访问,那么除了让同事都在自己的电脑上添加上面的静态解析记录之外,更正规的做法是使用内网DNS服务器。
您可以要求网络管理员在公司内部 DNS 服务器中添加相应的解析记录,将其指向 Nginx 服务器所在的 IP 地址。
当然还有另一种选项,Pigsty 默认安装也会在 53 端口提供一个 DNS 服务器,您可以通过配置 /etc/resolv.conf
文件或图形化界面配置 DNS 服务器,来使用内网域名访问部署在办公网中的服务。
通过互联网访问
如果您的服务需要直接暴露在互联网网上,通常您需要通过 DNS 服务商(Cloudflare,Aliyun DNS 等)解析互联网域名。 当然,你依然可以使用本地 DNS 服务器或本地静态解析记录来访问服务,但这样你的服务(除了默认的home服务器)就没法被互联网上的其他用户访问了。
您可以将所有需要暴露的域名都解析到 Nginx 服务器所在的 IP 地址。或者更简单的将 @
和 *
A 记录都解析到 Nginx 服务器所在的 IP 地址。
当你申请好新域名并将其指向你的服务器公网IP后,你还需要修改 Pigsty 的 infra_portal
,将域名填入各个服务器条目的 domain
字段中。
通过公网访问的域名,最佳实践是申请 HTTPS 证书,并始终使用 HTTPS 访问。我们将在下一节介绍这个主题。
配置HTTPS
HTTPS 是当代 Web 服务的主流配置,然而并非所有用户都熟悉 HTTPS 的配置方法。因此 Pigsty 默认为用户启用 HTTPS 支持。
如果你的 Nginx 只是对内网,办公网提供服务,那么 HTTPS 是一个 可选项; 如果你的 Nginx 需要对 互联网 提供服务,那么我们 强烈建议 您使用真实的域名与真正的 HTTPS 证书。 使用 HTTPS 不仅能够加密您的网络流量避免非法窥探篡改,而且能够避免访问 “未备案” 域名时恼人的体验。
本地域名与自签名证书
因为 Pigsty 默认使用的域名都是本地域名(x.pigsty
),无法申请真正的域名 HTTPS 证书,所以 Pigsty 默认使用自签名证书。
Pigsty 会使用自签名的 CA 为所有的 infra_portal
中的域名签发证书。当然此证书并非权威证书,在浏览器中会提示证书不可信。你可以选择:
- “我知道不安全,继续访问”
- 使用 Chrome 浏览器时,你也可以使用敲击键入
thisisunsafe
来绕过证书验证 - 将 Pigsty 自动生成的
pigsty-ca
CA 证书加入浏览器所在电脑的 信任的根 CA 列表。 - 回退到 HTTP 或者 IP:Port 访问,不使用 HTTPS (不推荐)
- 不使用本地域名与自签名证书,而是使用真正的域名与真正的 HTTPS 证书。
默认生成的自签名 CA 公钥和私钥位于 pigsty 本地目录的:files/pki/ca/ca.crt
和 files/pki/ca/ca.key
。
真实域名与真证书
HTTPS 证书通常是一项收费服务,但是您可以使用诸如 certbot
这类工具申请免费的 Let’s Encrypt 证书。
使用 Certbot 申请真正 HTTPS 证书的教程将在下一篇 Certbot教程:申请免费HTTPS证书 中详细介绍。