V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
nellxzy
V2EX  ›  NGINX

Nginx 能否将本地的多个端口转发到同一端口的不同目录

  •  
  •   nellxzy · 2021-02-13 02:23:25 +08:00 · 5300 次点击
    这是一个创建于 1409 天前的主题,其中的信息可能已经有所发展或是发生改变。

    玩树莓派遇到的问题,自己查了很久资料没搞定,求求论坛的各位大神指点!

    背景

    设备是树莓派,用了花生壳的内网穿透,免费版只提供两个端口,SSH 用掉一个 22 端口,现在只剩一个端口了。

    我有如下服务:

    • Jupyter:http://localhost:8888
    • Aria2 的 RPC:http://localhost:6800/jsonrpc
    • 其他某服务:http://localhost:5299
    • Aria-NG:基于 Nginx,http://localhost/aria-ng

    受到 Aria-NG 的启发,所以我在想能不能用 Nginx 实现如下转发:

    • Jupyter:http://localhost/jupyter
    • Aria2 的 RPC:http://localhost/jsonrpc
    • 其他某服务:http://localhost/xxx
    • Aria-NG:http://localhost/aria-ng

    我查到 Nginx 的默认端口是 80,如果上面可以实现的话,或许就可以只用一个 80 端口来使用多个服务。(应该是可以的,我之前试了 80 端口,用 外网域名:外网端口 /aria-ng 可以访问 Aria-NG,但是因为 Aria2 的 RPC 在 6800,所以只有 Aria-NG 的界面,没法实际使用。)

    目前的失败尝试

    /etc/nginx/nginx.conf中,进行如下修改:

    html {
    	......
        
        server {
            listen 80;
            server_name localhost;
    
            # Jupyter Notebook
            location /jupyter {
                proxy_pass http://localhost:8888;
                ......
            }
    
            # Aria2 JSONRPC
            location /jsonrpc {
                proxy_pass http://localhost:6800/jsonrpc;
                ......
            }
            
            # XXX
            location /xxx {
            	proxy_pass http://localhost:5299;
                ......
        }
    }
    

    重启 nginx 服务后,在树莓派上访问localhost/jupyter,错误 404 。局域网访问或外网访问自然也失败了。

    查到的资料基本上都是一个端口或域名转发到另一个端口或域名的,基本没有我这里的多个端口转发到同一端口的不同目录。还有一些用到了 stream 模块,但也是局域网内的端口对端口。只有这个帖子比较像: https://www.imooc.com/wenda/detail/510191 ,但是没有详细答案。

    当然,这个问题不用花生壳就能解决了,但还是好奇,上面提的方案有没有实现的可能性?

    29 条回复    2021-02-14 22:09:06 +08:00
    cinhoo
        1
    cinhoo  
       2021-02-13 02:45:32 +08:00 via iPhone
    location 和 proxy_pass 最后都加上 /试试
    nellxzy
        2
    nellxzy  
    OP
       2021-02-13 02:51:31 +08:00 via iPhone
    @cinhoo 试了一下,两个都加 /,两个分别加#,都没成功
    ashong
        3
    ashong  
       2021-02-13 02:54:50 +08:00
    ```
    location /jupyter {
    proxy_pass http://localhost:8888/;
    ......
    }
    ```

    应该就可以了
    Kobayashi
        4
    Kobayashi  
       2021-02-13 02:55:00 +08:00 via Android
    我记得需要被代理的服务支持,需要通知被代理服务它正在工作在某个目录下。如果是子域名就没有这种限制。
    nellxzy
        5
    nellxzy  
    OP
       2021-02-13 03:06:19 +08:00
    @ashong 这边还是 404
    Qetesh
        6
    Qetesh  
       2021-02-13 03:14:09 +08:00 via iPhone   ❤️ 3
    这种转发会把路径带过去,需要写 rewrite 。最好用域名做到不通网站访问
    cz5424
        7
    cz5424  
       2021-02-13 08:13:04 +08:00 via iPhone
    是不是 docker 下,docker 下就不是 localhost
    crclz
        8
    crclz  
       2021-02-13 08:42:40 +08:00
    关键词 nginx rewrite
    cz5424
        9
    cz5424  
       2021-02-13 09:15:49 +08:00 via iPhone
    # Aria2 JSONRPC
    location /jsonrpc {
    proxy_pass http://localhost:6800;
    ......
    }
    kingfalse
        10
    kingfalse  
       2021-02-13 09:28:59 +08:00 via Android
    搜 Nginx 路径转发
    snip
        11
    snip  
       2021-02-13 09:34:58 +08:00
    如果是自己用,就用 ssh 隧道解决
    dier
        12
    dier  
       2021-02-13 09:46:52 +08:00 via iPhone
    server_name 填个域名,然后解析到花生壳的 cname 或 IP
    dier
        13
    dier  
       2021-02-13 09:47:46 +08:00 via iPhone
    你只有 localhost,那就只能通过 localhost 来访问
    dier
        14
    dier  
       2021-02-13 09:50:22 +08:00 via iPhone
    有些服务不支持路径的话,建议分成不同的 server{}块来区分,每一块都能监听 80 端口,修改成对应的 server_name 就可以了
    OhYee
        15
    OhYee  
       2021-02-13 10:43:27 +08:00 via Android
    参考下这个的例子?貌似问题就在反向代理路径上

    https://segmentfault.com/a/1190000022501310
    chinvo
        16
    chinvo  
       2021-02-13 10:46:09 +08:00 via iPhone
    @dier #13 瞎说,server name 不决定外部访问方式,只是按 server 排列顺序匹配,都匹配不上则展示最后一个或 default server
    Rysle
        17
    Rysle  
       2021-02-13 12:17:12 +08:00
    这个帖子回复需要各种验证?
    Rysle
        18
    Rysle  
       2021-02-13 12:21:11 +08:00
    带链接的不让回,自己搜索一下 ngx_http_sub_module 的例子
    SenLief
        19
    SenLief  
       2021-02-13 12:43:50 +08:00 via Android
    你应该是配置错了
    location /jsonrpc {
    proxy_pass http://localhost:6800;
    }
    不要在 proxy_pass 后跟目录,不加 /会自动替换请求链。可以试试
    ihipop
        20
    ihipop  
       2021-02-13 13:44:16 +08:00 via Android
    说了这么说没一个人贴文档的,文档里面说的很清
    http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass


    If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

    location /name/ { proxy_pass http://127.0.0.1/remote/; }

    假如你的 jupyter 工作在 8888 端口的 / ,不存在任何重定向,且木有绑定 host
    @ashong 的例子应该可以 work 的
    楼主也最好参阅一下 jupyter 的日志确定问题而不是乱试
    liuhan907
        21
    liuhan907  
       2021-02-13 14:26:42 +08:00 via Android
    此功能还是建议使用 traefik 。
    chairuosen
        22
    chairuosen  
       2021-02-13 14:48:19 +08:00
    用域名呗。。。。内网域名
    IvanLi127
        23
    IvanLi127  
       2021-02-13 15:47:13 +08:00 via Android
    把 server_name 这行去掉
    dorothyREN
        24
    dorothyREN  
       2021-02-13 19:00:28 +08:00
    答案是可以
    spolarbear
        25
    spolarbear  
       2021-02-13 19:49:56 +08:00
    server {
    listen 5000;
    server_name 192.168.0.173;

    location /geoserver {
    proxy_pass http://localhost:8080;
    #proxy_redirect http://localhost http://localhost:8080;
    proxy_set_header Host $host:5000;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    }

    自用这个可行,访问 192.168.0.173:5000/geoserver 的话,会转发到 8080 端口。
    Judoon
        26
    Judoon  
       2021-02-13 22:38:32 +08:00
    据我之前使用,jupyter 是不行的,前端加载的样式等静态资源链接的路径不会被改写(即无法修改为自定义的 context path )

    如果我哪里漏看了文档,或者楼主搞出来了可以教教我

    除了 jupyter,列举的其他几个目测都是可以用 nginx 实现的。当然,最好的方式是基于域名( server_name )分发
    nellxzy
        27
    nellxzy  
    OP
       2021-02-14 01:48:48 +08:00
    感谢大家的回复,现在有了一个初步的方案,能转发 jupyter,aria2-jsonrpc 和 aria-ng 。

    配置方法:
    首先, [/etc/nginx/nginx.conf] 作如下修改:
    ```
    http {
    ......

    server {
    listen 4000;
    server_name localhost;

    # Jupyter Notebook
    location /jupyter/ {
    proxy_pass http://localhost:8888;
    proxy_set_header Host $host:$server_port;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # websocket headers
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header X-Scheme $scheme;

    proxy_read_timeout 120s;
    proxy_next_upstream error;
    }

    # Aria2 JSONRPC
    location /jsonrpc {
    proxy_pass http://localhost:6800;
    }

    # Aria-NG
    location /aria-ng/ {
    proxy_pass http://localhost:80;
    }
    }
    }
    ```

    其次, [~/.jupyter/jupyter_notebook_config.py] 追加如下部分:
    ```
    # 将 Jupyter 的工作路径改成 localhost:8888/jupyter/
    # 参考 https://segmentfault.com/a/1190000016627630
    c.NotebookApp.base_url = '/jupyter/'

    # 允许任何源访问服务,修复用 nginx 反向代理访问时 kernel 与 terminal 无法加载的问题
    # 参考 https://juejin.cn/post/6844903877481857037
    c.NotebookApp.allow_origin = '*'
    ```

    一些记录:
    1. 端口之所以选 4000,是因为设置成 80 时有问题,所以就另找了一个空闲的端口。
    2. location 和 proxy_pass 的写法,主要参考了这一篇: https://xuexb.github.io/learn-nginx/example/proxy_pass.html
    3. jupyter 本来是工作在 [localhost:8888/] 下的,我想让它工作在 [localhost:4000/jupyter/] 下。尝试了 location 和 proxy_pass 的各种写法,以及 rewrite,没成功。某些配置下,有一种典型的现象是,访问[localhost:4000/jupyter/]时,地址跳转到[localhost:4000/tree?](对应本体的[localhost:8888/tree?]),而不是[localhost:4000/jupyter/tree?],但手动输入后者,也没法正常显示。所以退而求其次,让 jupyter 本体工作在[localhost:8888/jupyter/]下。
    4. 接下来又出现了一个问题,打开 jupyter 后,虽然文件管理界面没问题,但是 kernel 和 terminal 无法加载。所以又加入了允许所有源访问服务,解决了这个问题。

    概括一下:
    能够工作在端口下一个目录的服务,比如
    - localhost:8888/jupyter/
    - localhost:6800/jsonrpc
    - localhost:80/aria-ng/
    可以转发。但是直接工作在端口下的服务,比如
    - localhost:5299/
    没弄出来。树莓派能安装的 Nginx 版本只有 1.14.2,不知道跟版本有没有关系。
    nellxzy
        28
    nellxzy  
    OP
       2021-02-14 01:51:32 +08:00
    @Judoon jupyter 可以了
    rekulas
        29
    rekulas  
       2021-02-14 22:09:06 +08:00
    路径转发并不总是可行,因为被转发的程序也必须支持跟你定义的根路径一样才可以,我觉得更完美的方案是域名控制,即使一个端口也可以转发任意多个服务(没有用花生壳所以不太清楚能不能支持域名)
    我和我的朋友从不会有这些问题,因为是公网 IP,想开哪个端口开哪个。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5906 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 02:54 · PVG 10:54 · LAX 18:54 · JFK 21:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.