
家里的内网有多个应用,现在 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 exiaohao 2023-05-30 23:19:45 +08:00 `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 应该说是绝大部分前端项目都不支持动态路径,资源往往是以基于根目录的绝对路径引用的。 匹配未知目录 rewrite 到特定目录也只能处理一个目录下的服务,期望多个二级目录来切分服务,除非你愿意 fork 代码去修改,否则是无法实现你的目的。 二级域名可能更合适一点 |
7 blankmiss 2023-05-31 08:50:57 +08:00 坑定不适用 为什么不搞个二级域名 |
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;br /> 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="http://www.v2ex.com/' ' src="http://www.v2ex.com/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 子目录访问要求被反代的应用要么使用相对路径,要么本身有做支持,否则建议换域名或者端口。 我也有追求所有应用都通过 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 字段里面跳转,也需要特殊处理。没有通用的方法 |