fatedier / frp

A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.
Apache License 2.0
85.33k stars 13.24k forks source link

[Feature Request] 基于uri路径的http代理模式 #4403

Closed lqian closed 1 month ago

lqian commented 1 month ago

Describe the feature request

目前很多智能设备内置了HTTP服务用于管理设备,这些设备http服务的使用率并不高。如果用customDomain去做http代理,则需要为这些设备申请域名,如果用端口模式的http代理,则这些端口的利用率非常低。 比如有一系列的设备序列号a,b,c,d,,,,,,且假设有一个域名ops.xxx.top, 能否支持基于uri路径的http代理模式, http://ops.xxx.top/a 映射到设备a的http 80端口 http://ops.xxx.top/b 映射到设备b的http 80端口 ?

Describe alternatives you've considered

No response

Affected area

xJetRy commented 1 month ago

You can do this with OpenResty

server side:

frps.toml

vhostHTTPPort=8080

nginx server block

server {
    listen 80;
    server_name foo.bar;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name foo.bar;

    ssl_certificate /path/to/crt/foo.bar.crt;
    ssl_certificate_key /path/to/key/foo.bar.key;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

client side:

frpc.toml

[[proxies]]
type = "http"
localPort = 5000
localIP = "openresty"
customDomains = ["foo.bar"]

requestHeaders.set.frp-dest = "10.0.0.2:8080"
locations = ["/a"]
requestHeaders.set.frp-route-path = "/a"
name = "example"

open-resty server block

server {
    listen 5000;
    server_name localhost;
    error_log /opt/bitnami/openresty/nginx/logs/debug.log debug;
    set_by_lua_block $frp_dest {
        local frp_dest = ngx.var.http_frp_dest
        if frp_dest == nil or frp_dest == '' then
            ngx.status = 400
            ngx.say('Bad Request: Missing frp-dest header')
            ngx.exit(ngx.HTTP_BAD_REQUEST)
        end
        return frp_dest
    }

    set_by_lua_block $frp_route_path {
        return ngx.var.http_frp_route_path or ''
    }

    location / {
        access_by_lua_block {
            local frp_route_path = ngx.var.frp_route_path
            if frp_route_path and frp_route_path ~= '' then
                local new_uri, n, err = ngx.re.sub(ngx.var.uri, "^" .. frp_route_path .. "/(.*)", "/$1", "jo")
                if new_uri then
                    ngx.req.set_uri(new_uri, false)
                else
                    ngx.log(ngx.ERR, "error on rewrite: ", err)
                    return ngx.exit(500)
                end
            end
        }
        proxy_pass http://$frp_dest;
        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;
    }
}

docker-compose:

version: '3'

services:
  openresty:
    image: bitnami/openresty:latest
    container_name: openresty
    volumes:
      - ./openresty.conf:/opt/bitnami/openresty/nginx/conf/server_blocks/frpc.conf:ro

  frpc:
    image: snowdreamtech/frpc:latest
    container_name: frpc
    volumes:
      - ./frpc.toml:/frpc.toml:ro
    command: -c /frpc.toml
    depends_on:
      - openresty

visit: https://foo.bar/a/echo

lqian commented 1 month ago

great!