家里的内网有多个应用,现在 nginx 部署在一台单独的服务器上 192.168.2.180 现在想改造一下访问方式变成访问:
https://192.168.2.180:9444/chat 可以访问到部署的 chatgpt: http://192.168.2.4:50021
https://192.168.2.180:9444/pve 可以访问到 PVE 虚拟机 https://192.168.2.2:8006/
https://192.168.2.180:9444/adguard/ 可以访问到 adguard 的应用 http://192.168.2.200/
但是按照下面的配置,访问到的页面不全,页面各种缺失。 是不是这样的方法不适用??
worker_processes auto;
events {
worker_connections 1024;
}
http {
server {
listen 9444 ssl;
server_name 192.168.2.180;
ssl_certificate /etc/nginx/ssl.crt;
ssl_certificate_key /etc/nginx/ssl.key;
location /chat/ {
proxy_pass http://192.168.2.4:50021/;
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;
}
location /pve/ {
proxy_pass https://192.168.2.2:8006/;
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 Accept-Encoding "";
sub_filter_types *;
}
location /adguard/ {
proxy_pass http://192.168.2.200/;
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 Accept-Encoding "";
sub_filter_types *;
}
}
}
1
busier 2023-05-30 22:45:09 +08:00
不要随便转换路径!
本来是 / ,你非要转换成 /chat/ 、 /pve/ 、 /adguard/ 页面 html 以及 javascript 对资源的引用又不会自动转换! |
2
shiyuu OP @busier
去掉了 /也是一样的不行 比如 /chat 这个目录,加载这些页面的元素就 会变成 https://192.168.2.4:9444/assets/index-44aaddda.js 而不是 https://192.168.2.4:9444/chat/assets/index-44aaddda.js |
3
SKYNE 2023-05-30 23:14:21 +08:00 4
|
4
exiaohao 2023-05-30 23:19:45 +08:00 2
`location` 不能这样写,3 楼大佬正解
一句话解释 1) 楼主要理解 `^/some-path$` 和 `^/some-path/*` 的区别 2) 另外就是访问到比如 /chat 后,对真实的后段怎么把 /chat 去掉 |
5
icaolei 2023-05-31 01:05:11 +08:00
得看部署的项目本身是否支持动态路径,如果不支持的话只能考虑重写了。
|
6
chenluo0429 2023-05-31 01:35:40 +08:00 via Android 1
应该说是绝大部分前端项目都不支持动态路径,资源往往是以基于根目录的绝对路径引用的。
匹配未知目录 rewrite 到特定目录也只能处理一个目录下的服务,期望多个二级目录来切分服务,除非你愿意 fork 代码去修改,否则是无法实现你的目的。 二级域名可能更合适一点 |
7
blankmiss 2023-05-31 08:50:57 +08:00 1
坑定不适用 为什么不搞个二级域名
|
8
laoyutang 2023-05-31 09:14:37 +08:00 via Android
不行的,你这玩法我之前就试过了,项目前端的 publicpath 你根本控制不了,除非你找源码来改。考虑下用 server_name 分流
|
9
qwertty01 2023-05-31 09:23:50 +08:00
可以参考我得配置,用域名,https 也能搞定
``` server { listen 443 ssl; # listen [::]:443; server_name test.test.com; ssl_certificate /etc/nginx/certs/test.com.pem; ssl_certificate_key /etc/nginx/certs/test.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; access_log /var/log/nginx/https.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } upstream registry { server 192.168.31.123:5000; } upstream image { server 192.168.31.222:8080; } upstream esxi { server 192.168.31.77:443; } upstream rmi { server 192.168.31.88:443; } server { listen 443 ssl; # listen [::]:443; server_name registry.test.com; ssl_certificate /etc/nginx/certs/test.com.pem; ssl_certificate_key /etc/nginx/certs/test.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; access_log /var/log/nginx/https.access.log main; location / { proxy_pass http://registry; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } server { listen 443 ssl; # listen [::]:443; server_name image.test.com; ssl_certificate /etc/nginx/certs/test.com.pem; ssl_certificate_key /etc/nginx/certs/test.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; access_log /var/log/nginx/https.access.log main; location / { proxy_pass http://image; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } server { listen 443 ssl; # listen [::]:443; server_name esxi.test.com; ssl_certificate /etc/nginx/certs/test.com.pem; ssl_certificate_key /etc/nginx/certs/test.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; access_log /var/log/nginx/host.access.log main; location / { proxy_pass https://esxi; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } error_page 404 /404.html; } server { listen 443 ssl; # listen [::]:443; server_name rmi.test.com; ssl_certificate /etc/nginx/certs/test.com.pem; ssl_certificate_key /etc/nginx/certs/test.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; access_log /var/log/nginx/host.access.log main; location / { proxy_pass https://rmi; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } error_page 404 /404.html; } ``` |
10
awinds 2023-05-31 09:40:07 +08:00
用不同端口转发不同应用吧
|
11
JayZXu 2023-05-31 09:55:39 +08:00
用子路径的形式,目前大多数前端都不支持
js 和静态资源的调用路径在打包之前就得定义好。 建议使用不同端口号对应不同服务, 或者用 server_name 绑定不同域名,本地改 hosts 来实现基于 server_name 的转发 |
12
yujizmq 2023-05-31 10:06:36 +08:00
@shiyuu 虽然这个方法有点脏,但应该可以解决,参考:
sub_filter_once off; sub_filter_types text/html text/css application/javascript; sub_filter ' href="/' ' href="/chat/'; sub_filter ' src="/' ' src="/chat/'; sub_filter ' action="/' ' action="/chat/'; sub_filter '"assets/' '"chat/assets/'; sub_filter '"assets/' '"chat/assets/'; sub_filter '"/assets/' '"/chat/assets/'; # #sub_filter 'baseURL:"/api"' 'baseURL:"/chat/api"'; sub_filter 'url:"/' 'url:"/chat/'; sub_filter '/sw.js' '/chat/sw.js'; |
13
jifengg 2023-05-31 10:22:54 +08:00
楼主,建议你别用这种二级目录的方式,因为你转发的都基本上不是自己编译打包的项目,太难通用了。
建议通过域名来转发。 如果自己拥有一个域名,可以把不同的二级域名解析到 192.168.2.180 ,nginx“分别配置 server”,写好 server_name ,进行转发; 如果没有,在机器本地 hosts 随便配置个域名指向 192.168.2.180 也是 ok 的。 |
14
clf 2023-05-31 10:39:22 +08:00
你没法保证三个服务客户端( web 网页)请求的 url 都能正常分流。
比如第一个应用如果前端路由打包的时候 base 就是 / ,那么请求的 js 资源可能都是 /assist/xxx.js ,如果 3 个项目都是 /assist 的前缀,你根本没法分流。更别提调用的后端接口了。 |
15
adoal 2023-05-31 10:45:38 +08:00
现在流行的前后端分离项目,最终部署出来的前端静态资源都是“编译”过的,项目内引用路径是写死的,放到反代子路径下,如果你不能自己重新 build 的话,那除了用 sub_filter 来做 dirty hack 之外真没啥好办法。
其实在 good old CGI 时代,前后端不分离的系统,写得体贴的系统会根据 web server 或者反代传过来的 SCRIPT_NAME + PATH_INFO 来自适应地“意识到自己运行在子路径下”从而调整页面内路径引用的生成规则。缺点时静态资源的路径每次都要计算,性能有影响,当然对大部分系统来说没必要担心这个性能。 |
16
adoal 2023-05-31 10:50:01 +08:00
|
17
adoal 2023-05-31 10:54:37 +08:00
再比如 Flask 框架官方文档的解决办法 https://flask.palletsprojects.com/en/2.0.x/deploying/fastcgi/
|
18
Macv1994 2023-05-31 12:48:30 +08:00
二级域名不就行了吗?
|
19
huajia2005 2023-05-31 13:12:32 +08:00
只是本地访问的话,改 host 配二级域名,然后用 server_name 进行转发,大部分项目而且不是自己的项目的话,静态资源都会有路径问题
|
20
IvanLi127 2023-05-31 13:15:47 +08:00
这操作不是完全通用,很多项目不一定支持子目录部署,因为没做适配。你想搞这个的话,就三种情况:
- 项目使用相对路径,直接反向代理配置就好了 - 项目支持在编译时通过环境变量配置 BASE 路径,拉源码配一下重新构建前端项目 - 项目直接硬编码路径了,那就得拉源码一个个改了,改完提 PR❤️ 我也想把我部署的服务都弄成子目录形式,这样 frp 比较方便,现在用的 frp 便宜是便宜,就是一个通道只能绑三个域名 QAQ |
21
lovelylain 2023-05-31 14:23:37 +08:00
子目录访问要求被反代的应用要么使用相对路径,要么本身有做支持,否则建议换域名或者端口。
我也有追求所有应用都通过 homeassistant 以子目录访问: adguardhome: 相对路径 nodered: 相对路径 zigbee2mqtt: 相对路径 frigate: 本身有做适配,传 X-Ingress-Path 头 openwrt 里的 netdata: 相对路径 openwrt 里的 ttyd: 相对路径 openwrt: 最开始换了域名反代,后来用 sub_filter 等解决了 虽然大部分都实现了,但还是建议对于非相对路径的直接换域名不折腾。 |
22
yxisenx 2023-05-31 15:01:43 +08:00
懒得麻烦就用二级域名
|
23
luhuisicnu 2023-05-31 15:32:11 +08:00
我们有这样的使用案例,统一一个域名做入口,根据 path 来区分业务,转发到内网的其他域名下,大概像这样:
server { listen 80; server_name api.test.com; location /server1/ { rewrite /server1/(.*) /$1 break; proxy_pass http://1.1.1.1:80; } location /server2/ { rewrite /server2/(.*) /$1 break; proxy_set_header Host server2.local.test.com; proxy_pass http://2.2.2.2:80; } location /server3/ { proxy_set_header Host server3.local.test.com; proxy_pass http://3.3.3.3:80/; } } server1 是不带域名的,server2 带域名转发,所以要设置内部域名的 header ,server3 是 server2 的另一种写法。转发后的 path ,是不带 server1, server2 ,server3 的。可以试试。 |
24
luhuisicnu 2023-05-31 15:34:46 +08:00
重新排版试试
我们有这样的使用案例,统一一个域名做入口,根据 path 来区分业务,转发到内网的其他域名下,大概像这样: ``` server { listen 80; server_name api.test.com; location /server1/ { rewrite /server1/(.*) /$1 break; proxy_pass http://1.1.1.1:80; } location /server2/ { rewrite /server2/(.*) /$1 break; proxy_set_header Host server2.local.test.com; proxy_pass http://2.2.2.2:80; } location /server3/ { proxy_set_header Host server3.local.test.com; proxy_pass http://3.3.3.3:80/; } } ``` server1 是不带域名的,server2 带域名转发,所以要设置内部域名的 header ,server3 是 server2 的另一种写法。转发后的 path ,是不带 server1, server2 ,server3 的。可以试试。 |
25
shiyuu OP @qwertty01 你的抄了一下可以用。看来只能用域名来搞了,这样可以在路由器少映射很多端口。阿里的免费证书不支持泛域名,得每个域名都申请一个证书,很麻烦,兄弟怎么解决?
|
26
vivisidea 2023-05-31 16:39:07 +08:00
@shiyuu 内网如果有 dns 的话,可以自己加个 dns 解析,或者设备不多的话,手动每个设备加个 hosts
我用 ikuai 软路由,内部搞了个 .lan 域名,比如 nas.lan 就是群辉,router.lan 就是路由器 |
27
qwertty01 2023-05-31 17:09:07 +08:00
|
28
shiyuu OP @qwertty01 不过我现在还遇到个问题,抄你的这么写了 4 个域名对应的系统。
pve.xx.com nas.xx.com adguard.xx.com route.xx.com 用对应域名都能正常访问到对应的系统了。 但是有个情况,另外还有一些域名比如 alist.xx.com ,我 nginx 上都还没配置,直接访问的话会居然能访问到 pve 的系统上,我没设置 error_page ,是不是也要配置一个 error_page 。 upstream pve { server 192.168.2.2:8006; } upstream nas { server 192.168.2.4:5000; } upstream adguard { server 192.168.2.200; } upstream route { server 192.168.2.1; } |
30
shiyuu OP @qwertty01 知道怎么弄了, “添加一个新的 server 块,用于处理所有未知域名。我们使用 default_server 参数将其指定为默认监听器,并将 server_name 设置为 _。在 location 规则中,我们返回一个 404 错误,告诉客户端该域名未配置。如果需要,您可以将此规则更改为一个自定义的重定向或其他行为。”
|
31
mk0114 2023-06-01 08:56:34 +08:00
泛域名证书用 certbot 吧,就是三个月要申请一次,或者你的域名解析商能提供 api 的话,可以做自动化更新证书。
|
32
bingfengfeifei 2023-06-01 14:34:04 +08:00
优雅的方法就是域名,12 楼的方法也可以解决问题。
我是使用了 12 楼的这种方法,但是不一定每一个页面都能成功。这个方法是修改 WEB 返回内容,将返回的资源绝对路径加上你的转发前缀。 有些页面他的请求 URL 是写到 JS 里面的,掺杂在代码里面,非常难以替换。 而且有些页面会有跳转重定向,在 location 字段里面跳转,也需要特殊处理。没有通用的方法 |