[GH-ISSUE #3831] Unable to Access frp Service Behind Nginx Reverse Proxy #3043

Closed
opened 2026-05-05 13:58:09 -06:00 by gitea-mirror · 5 comments
Owner

Originally created by @FerrazArthur on GitHub (Dec 6, 2023).
Original GitHub issue: https://github.com/fatedier/frp/issues/3831

Bug Description

I'm facing an issue where I cannot access the frp service when it's behind an Nginx reverse proxy. I've reduced the problem to a curl command, and it seems to be related to communication issues with how to access the upstream frp server.

From within the frps container, i can access the service with customDomain:/URL. YET i want to know how to access it with a call to 0.0.0.0:port/URL. like a curl -H "Host: customDomain" 0.0.0.0:port/URL should work.

This is important so i can mannage tls certificates with nginx, then pass it as http to frpserver. them return the response from frpserver to the user as https.

frpc Version

v0.52.3

frps Version

v0.52.3

System Architecture

linux/amd64, frpc and frps container's are alpine

Configurations

FRP FILES

FRPS.toml

bindPort = 7000
# bindAddr = "0.0.0.0" tried with and without, no change.

vhostHTTPPort = 80
vhostHTTPSPort = 443

FRPC.toml

serverAddr = "frp-server"
serverPort = 7000

log_file = "./frps.log"
log_level = "trace"
log.maxDays = 3

[[proxies]]
name = "wagi-proxy"
type = "http"
localPort = 3000
localIp = "wagi-server"
customDomains = ["my-app.test"]
Exact setup of problem

nginx file:

events {
    worker_connections  1024;
}

http {
    upstream frps {
        server frp-server:7000;
    }
    server {
        listen 80;
        server_name _;

        # Redirect HTTP to HTTPS
        location / {
            return 301 https://$host$request_uri;
        }
    }

    server {
        listen 443 ssl;
        server_name _;

        include snippets/self-signed.conf;
        include snippets/ssl-params.conf;

        location / {

            proxy_connect_timeout       60s;
            proxy_send_timeout          60s;
            proxy_read_timeout          60s;
            proxy_set_header Host $host;

            proxy_pass http://frps;  # Assuming frp-server is on the comms-nginx network
        }

        # Add other SSL and server configurations if needed
    }
}

dnsmasq file:

listen-address=0.0.0.0
interface=eth0
user=root

server=8.8.8.8
server=8.8.4.4
address=/.test/127.0.0.1

no-resolv

domain-needed

bogus-priv

I's a local dns server so for this to work you'll need to pause systemd.resolved with sudo systemctl stop systemd-resolved because it'll already be listenning of port 53. Also you'll need to add 127.0.0.1 to your dns list, in priority and probably change /etc/resolv.conf from 127.0.0.53 to 127.0.0.1. when you restart systemd-resolved, all goes back to normal.

traefik file:

providers:
  docker:
    defaultRule: "Host(`{{ trimPrefix `/` .Name }}.test`)"
api:
  insecure: true

docker compose

version: '3.3'
services:

  # DNS server that resolves all *.test to nginx-server
  dnsmasq:
    image: andyshinn/dnsmasq
    cap_add:
      - NET_ADMIN
    restart: always
    ports:
      - "53:53/udp"
      - "53:53/tcp"
    volumes:
      - ./dns-dev/dnsmasq.conf:/etc/dnsmasq.conf
    command: --log-facility=-
    networks:
      - dns-proxy

  traefik:
    image: "traefik:v2.2"
    container_name: "traefik"
    restart: always
    command:
      - "--log.level=ERROR"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./dns-dev/traefik.yml:/etc/traefik/traefik.yml"
    networks:
      - dns-proxy
      - comms-nginx

  cert-script:
    build:
      dockerfile: Dockerfile-certbot
    labels:
    - "traefik.enable=false"
    container_name: cert-script
    volumes:
      - etc-ssl:/etc/ssl
      - etc-nginx:/etc/nginx

  frp-server:
    build:
      context: .
      dockerfile: Dockerfile-frps
    labels:
    - "traefik.enable=false"
    container_name: frp-server
    volumes:
      - ./frps.toml:/frp/frps.toml:ro
    ports:
      - "7000:7000"
      - "7500:7500"
      - "30000-30900:30000-30900"
    networks:
      - comms-nginx
      - comms-frp

  nginx-server:
    image: nginx:alpine
    labels:
      - traefik.http.routers.nginx-server.rule=Host(`my-app.test`)
      - "traefik.http.routers.myrouter.tls=true"
    container_name: nginx-server
    volumes:
      - etc-ssl:/etc/ssl
      - etc-nginx:/etc/nginx
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "443:443"
    networks:
      - comms-nginx
      - dns-proxy
    depends_on:
      cert-script:
        condition: service_completed_successfully
      frp-server:
        condition: service_started

  frp-client:
    image: test-frpc
    build:
      context: .
      dockerfile: Dockerfile
    labels:
    - "traefik.enable=false"
    command: ["-c", "./quant1-frpc"]
    volumes:
      - ./frpc.toml:/frp/frpc.toml:ro
    container_name: frp-client
    tty: true
    stdin_open: true
    networks:
      - comms-frp
      - comms-local
    depends_on:
      - frp-server

  # Server that provides some application via http
wagi-server:
    image: node:14
    container_name: wagi-server
    labels:
    - "traefik.enable=false"
    working_dir: /app
    command: bash -c "echo 'const http = require(\"http\"); const server = http.createServer((req, res) => { res.end(\"Hello, World!\"); }); server.listen(3000, \"0.0.0.0\");' > index.js && node index.js" 
    networks:
      - comms-local

networks:
  comms-frp:
    driver: bridge
  comms-local:
    driver: bridge
  comms-nginx:
    driver: bridge
  dns-proxy:
    driver: bridge

volumes:
  etc-ssl:
  etc-nginx:

by running this, you'll see that nginx-server logs are showing:

nginx-server  | 2023/12/06 18:03:58 [error] 22#22: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.29.0.1, server: _, request: "GET /quicksort?--help HTTP/1.1", upstream: "http://172.29.0.3:7000/quicksort?--help", host: "my-app.test"

everytime you try https://my-app.test/URL.

Logs

with nginx

"nginx-server  | 2023/12/06 18:03:58 [error] 22#22: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.29.0.1, server: _, request: "GET /quicksort?--help HTTP/1.1", upstream: "http://172.29.0.3:7000/quicksort?--help", host: "my-app.test"

with curl (that's inside the frp-server container)

$ docker compose exec -it frp-server sh
/frp $ curl -H "Host: my-app.test" 0.0.0.0:7000/quicksort?--help #this is the same thing the nginx upstream tries to do
curl: (52) Empty reply from server
/frp $ curl http://my-app.test/quicksort?--help
hello world

Steps to reproduce

You can either run the services and test with nginx, or you can run only the frps server and frpc client containers and try to access the service from the frps Ip:port, like curl -H "Host: service domain host" frpsip:frpsport/URL

Affected area

  • Docs
  • Installation
  • Performance and Scalability
  • Security
  • User Experience
  • Test and Release
  • Developer Infrastructure
  • Client Plugin
  • Server Plugin
  • Extensions
  • Others
Originally created by @FerrazArthur on GitHub (Dec 6, 2023). Original GitHub issue: https://github.com/fatedier/frp/issues/3831 ### Bug Description I'm facing an issue where I cannot access the frp service when it's behind an Nginx reverse proxy. I've reduced the problem to a curl command, and it seems to be related to communication issues with how to access the upstream frp server. From within the frps container, i can access the service with customDomain:/URL. YET i want to know how to access it with a call to 0.0.0.0:port/URL. like a curl -H "Host: customDomain" 0.0.0.0:port/URL should work. This is important so i can mannage tls certificates with nginx, then pass it as http to frpserver. them return the response from frpserver to the user as https. ### frpc Version v0.52.3 ### frps Version v0.52.3 ### System Architecture linux/amd64, frpc and frps container's are alpine ### Configurations ## FRP FILES ### FRPS.toml ```toml bindPort = 7000 # bindAddr = "0.0.0.0" tried with and without, no change. vhostHTTPPort = 80 vhostHTTPSPort = 443 ``` ### FRPC.toml ```toml serverAddr = "frp-server" serverPort = 7000 log_file = "./frps.log" log_level = "trace" log.maxDays = 3 [[proxies]] name = "wagi-proxy" type = "http" localPort = 3000 localIp = "wagi-server" customDomains = ["my-app.test"] ``` <details><summary>Exact setup of problem</summary> ## nginx file: ```conf events { worker_connections 1024; } http { upstream frps { server frp-server:7000; } server { listen 80; server_name _; # Redirect HTTP to HTTPS location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name _; include snippets/self-signed.conf; include snippets/ssl-params.conf; location / { proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_set_header Host $host; proxy_pass http://frps; # Assuming frp-server is on the comms-nginx network } # Add other SSL and server configurations if needed } } ``` ## dnsmasq file: ```conf listen-address=0.0.0.0 interface=eth0 user=root server=8.8.8.8 server=8.8.4.4 address=/.test/127.0.0.1 no-resolv domain-needed bogus-priv ``` I's a local dns server so for this to work you'll need to pause systemd.resolved with `sudo systemctl stop systemd-resolved` because it'll already be listenning of port 53. Also you'll need to add 127.0.0.1 to your dns list, in priority and probably change /etc/resolv.conf from 127.0.0.53 to 127.0.0.1. when you restart systemd-resolved, all goes back to normal. ## traefik file: ```traefik providers: docker: defaultRule: "Host(`{{ trimPrefix `/` .Name }}.test`)" api: insecure: true ``` ## docker compose ```docker-compose.yml version: '3.3' services: # DNS server that resolves all *.test to nginx-server dnsmasq: image: andyshinn/dnsmasq cap_add: - NET_ADMIN restart: always ports: - "53:53/udp" - "53:53/tcp" volumes: - ./dns-dev/dnsmasq.conf:/etc/dnsmasq.conf command: --log-facility=- networks: - dns-proxy traefik: image: "traefik:v2.2" container_name: "traefik" restart: always command: - "--log.level=ERROR" - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" ports: - "80:80" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./dns-dev/traefik.yml:/etc/traefik/traefik.yml" networks: - dns-proxy - comms-nginx cert-script: build: dockerfile: Dockerfile-certbot labels: - "traefik.enable=false" container_name: cert-script volumes: - etc-ssl:/etc/ssl - etc-nginx:/etc/nginx frp-server: build: context: . dockerfile: Dockerfile-frps labels: - "traefik.enable=false" container_name: frp-server volumes: - ./frps.toml:/frp/frps.toml:ro ports: - "7000:7000" - "7500:7500" - "30000-30900:30000-30900" networks: - comms-nginx - comms-frp nginx-server: image: nginx:alpine labels: - traefik.http.routers.nginx-server.rule=Host(`my-app.test`) - "traefik.http.routers.myrouter.tls=true" container_name: nginx-server volumes: - etc-ssl:/etc/ssl - etc-nginx:/etc/nginx - ./nginx.conf:/etc/nginx/nginx.conf:ro ports: - "443:443" networks: - comms-nginx - dns-proxy depends_on: cert-script: condition: service_completed_successfully frp-server: condition: service_started frp-client: image: test-frpc build: context: . dockerfile: Dockerfile labels: - "traefik.enable=false" command: ["-c", "./quant1-frpc"] volumes: - ./frpc.toml:/frp/frpc.toml:ro container_name: frp-client tty: true stdin_open: true networks: - comms-frp - comms-local depends_on: - frp-server # Server that provides some application via http wagi-server: image: node:14 container_name: wagi-server labels: - "traefik.enable=false" working_dir: /app command: bash -c "echo 'const http = require(\"http\"); const server = http.createServer((req, res) => { res.end(\"Hello, World!\"); }); server.listen(3000, \"0.0.0.0\");' > index.js && node index.js" networks: - comms-local networks: comms-frp: driver: bridge comms-local: driver: bridge comms-nginx: driver: bridge dns-proxy: driver: bridge volumes: etc-ssl: etc-nginx: ``` by running this, you'll see that nginx-server logs are showing: ```bash nginx-server | 2023/12/06 18:03:58 [error] 22#22: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.29.0.1, server: _, request: "GET /quicksort?--help HTTP/1.1", upstream: "http://172.29.0.3:7000/quicksort?--help", host: "my-app.test" ``` everytime you try https://my-app.test/URL. </details> ### Logs # with nginx ```bash "nginx-server | 2023/12/06 18:03:58 [error] 22#22: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.29.0.1, server: _, request: "GET /quicksort?--help HTTP/1.1", upstream: "http://172.29.0.3:7000/quicksort?--help", host: "my-app.test" ``` # with curl (that's inside the frp-server container) ```bash $ docker compose exec -it frp-server sh /frp $ curl -H "Host: my-app.test" 0.0.0.0:7000/quicksort?--help #this is the same thing the nginx upstream tries to do curl: (52) Empty reply from server /frp $ curl http://my-app.test/quicksort?--help hello world ``` ### Steps to reproduce You can either run the services and test with nginx, or you can run only the frps server and frpc client containers and try to access the service from the frps Ip:port, like `curl -H "Host: service domain host" frpsip:frpsport/URL` ### Affected area - [X] Docs - [ ] Installation - [X] Performance and Scalability - [ ] Security - [X] User Experience - [ ] Test and Release - [ ] Developer Infrastructure - [ ] Client Plugin - [ ] Server Plugin - [ ] Extensions - [X] Others
Author
Owner

@fatedier commented on GitHub (Dec 7, 2023):

Please first try to verify the configuration according to the document example.

<!-- gh-comment-id:1844126726 --> @fatedier commented on GitHub (Dec 7, 2023): Please first try to verify the configuration according to the [document](https://github.com/fatedier/frp?tab=readme-ov-file#accessing-internal-web-services-with-custom-domains-in-lan) example.
Author
Owner

@FerrazArthur commented on GitHub (Dec 7, 2023):

Please first try to verify the configuration according to the document example.

I read it multiple times already and made some changes as setting frps httpvhost to 8080 and also tried setting the client proxy for remotePort 8080, but had the same result. This time i took a picture
fatedier

I think would be great to add in the documentation how to communicate directly to the frp's server, via it's ip:port, and access a service. I think this should work, passing the customDomain of the proxy as Host, yet cant make it work.

I thought it listens for the customDomain's, but it has to go thought some ip or port and i couldnt figure out how to mimic this in order to curl -k -H "customDomain" frps-ip:port/ sucessfully.

frp toml's

#FRPS.toml
bindPort = 7000

vhostHTTPPort = 8080 #changed to 8080, as in the doc
vhostHTTPSPort = 443


#FRPC.toml
serverAddr = "frp-server"
serverPort = 7000

log_file = "./frps.log"
log_level = "trace"
log.maxDays = 3

[[proxies]]
name = "wagi-proxy"
type = "http"
localPort = 3000
localIp = "wagi-server"
remotePort = 6000  # Tried setting this remote in hope the proxy_pass to "frp-server:6000
# with host my-app.test  would work, but connection refused.
customDomains = ["my-app.test"]

nginx

events {
    worker_connections  1024;
}

http {
    upstream frps {
        server frp-server:6000; # I tried setting this port to 8080 and 6000, but the
# behaviour was the same: connection refused, as in the image.
    }
    server {
        listen 80;
        server_name _;

        # Redirect HTTP to HTTPS
        location / {
            return 301 https://$host$request_uri;
        }
    }

    server {
        listen 443 ssl;
        server_name _;

        include snippets/self-signed.conf;
        include snippets/ssl-params.conf;

        location / {

            # proxy_connect_timeout       60s; commented out this lines as they were tests
            # proxy_send_timeout          60s;
            # proxy_read_timeout          60s;
            # proxy_set_header Host $host;

            proxy_pass http://frps;  # frp-server is on the comms-nginx network
        }

    }
}

<!-- gh-comment-id:1845115831 --> @FerrazArthur commented on GitHub (Dec 7, 2023): > Please first try to verify the configuration according to the [document](https://github.com/fatedier/frp?tab=readme-ov-file#accessing-internal-web-services-with-custom-domains-in-lan) example. I read it multiple times already and made some changes as setting frps httpvhost to 8080 and also tried setting the client proxy for remotePort 8080, but had the same result. This time i took a picture ![fatedier](https://github.com/fatedier/frp/assets/36120442/41fa1980-570e-4498-85cd-c13c632b2a1d) I think would be great to add in the documentation how to communicate directly to the frp's server, via it's ip:port, and access a service. I think this should work, passing the customDomain of the proxy as Host, yet cant make it work. I thought it listens for the customDomain's, but it has to go thought some ip or port and i couldnt figure out how to mimic this in order to curl -k -H "customDomain" frps-ip:port/<URL> sucessfully. <details><summary>frp toml's</summary> ```toml #FRPS.toml bindPort = 7000 vhostHTTPPort = 8080 #changed to 8080, as in the doc vhostHTTPSPort = 443 ``` ```toml #FRPC.toml serverAddr = "frp-server" serverPort = 7000 log_file = "./frps.log" log_level = "trace" log.maxDays = 3 [[proxies]] name = "wagi-proxy" type = "http" localPort = 3000 localIp = "wagi-server" remotePort = 6000 # Tried setting this remote in hope the proxy_pass to "frp-server:6000 # with host my-app.test would work, but connection refused. customDomains = ["my-app.test"] ``` </details> <details><summary>nginx</summary> ```conf events { worker_connections 1024; } http { upstream frps { server frp-server:6000; # I tried setting this port to 8080 and 6000, but the # behaviour was the same: connection refused, as in the image. } server { listen 80; server_name _; # Redirect HTTP to HTTPS location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name _; include snippets/self-signed.conf; include snippets/ssl-params.conf; location / { # proxy_connect_timeout 60s; commented out this lines as they were tests # proxy_send_timeout 60s; # proxy_read_timeout 60s; # proxy_set_header Host $host; proxy_pass http://frps; # frp-server is on the comms-nginx network } } } ``` </details>
Author
Owner

@superzjg commented on GitHub (Dec 8, 2023):

If using type = "http", there is no need to set remotePort and it will automatically be set to vhostHTTPPort.
When using type = "tcp", a remotePort needs to be set.

<!-- gh-comment-id:1846569340 --> @superzjg commented on GitHub (Dec 8, 2023): If using `type = "http"`, there is no need to set `remotePort` and it will automatically be set to `vhostHTTPPort`. When using `type = "tcp"`, a `remotePort` needs to be set.
Author
Owner

@xqzr commented on GitHub (Dec 8, 2023):

curl -H "Host: service domain host" frpsip:80/URL

<!-- gh-comment-id:1847271148 --> @xqzr commented on GitHub (Dec 8, 2023): `curl -H "Host: service domain host" frpsip:80/URL`
Author
Owner

@FerrazArthur commented on GitHub (Dec 8, 2023):

It started working when i redirected to port 8080 and removed remotePort from client. Thanks for the help, really appreciate you all.

<!-- gh-comment-id:1847528080 --> @FerrazArthur commented on GitHub (Dec 8, 2023): It started working when i redirected to port 8080 and removed remotePort from client. Thanks for the help, really appreciate you all.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/frp#3043
No description provided.