[GH-ISSUE #4405] FRP with SSL/HTTPS failed to connect #3482

Closed
opened 2026-05-05 14:14:16 -06:00 by gitea-mirror · 9 comments
Owner

Originally created by @mdennyh on GitHub (Aug 25, 2024).
Original GitHub issue: https://github.com/fatedier/frp/issues/4405

Bug Description

I have a web service that runs behind NAT. It runs on regular http port 4000 (local) so that I can access it locally in my LAN with http://<local.ip.address>:4000/

I want to expose this service to the internet so I can access it with https://<mydomain.ddns.net>:4000/. I already able to run it with regular http without SSL

I rent a public Ubuntu server and run frps there.

I also use no-IP to provide the domain that I need (this case: mydomain.ddns.net

I already have SSL certificate from Let's Encrypt. It consists of 2 files: fullchain.pem and privkey.pem. I generate both using certbot from the local server.

Using the configurations below, I unable to access the service at all although both frpc and frps confirm handshake.

frpc Version

0.60.0

frps Version

0.60.0

System Architecture

linux/amd64

Configurations

frps.ini

[common]
bind_port = 4100
vhost_https_port = 4000

tls_enable = true
tls_cert_file = ./path/to/fullchain.pem
tls_key_file = ./path/to/privkey.pem

log_level = debug

frpc.ini

[common]
server_addr = <my public server IP address>
server_port = 4100
log_level = debug

[https]
type = https
# local server runs at port 4000 also
local_port = 4000
custom_domains = mydomain.ddns.net

Logs

whenever I try to access http://mydomain.ddns.net:4000/ from the web browser the frps server prints this:

FPS log:

2024-08-25 06:58:37.718 [I] [frps/root.go:105] frps uses config file: /path/to/frps.ini
2024-08-25 06:58:37.748 [I] [server/service.go:237] frps tcp listen on 0.0.0.0:4100
2024-08-25 06:58:37.748 [I] [server/service.go:319] https service listen on 0.0.0.0:4000
2024-08-25 06:58:37.749 [I] [frps/root.go:114] frps started successfully
2024-08-25 06:58:49.787 [I] [server/service.go:576] [bec077128920b93f] client login info: ip [125.166.9.28:18051] version [0.60.0] hostname [] os [linux] arch [amd64]
2024-08-25 06:58:49.819 [I] [proxy/https.go:67] [bec077128920b93f] [https] https proxy listen for host [mydomain.ddns.net]
2024-08-25 06:58:49.820 [I] [server/control.go:399] [bec077128920b93f] new proxy [https] type [https] success
2024-08-25 06:58:49.820 [D] [server/control.go:243] [bec077128920b93f] new work connection registered
2024-08-25 06:58:54.804 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser []
2024-08-25 06:58:54.804 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:44120]
2024-08-25 06:58:54.804 [D] [server/control.go:272] [bec077128920b93f] get work connection from pool
2024-08-25 06:58:54.805 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051]
2024-08-25 06:58:54.805 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:44120])
2024-08-25 06:58:54.805 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser []
2024-08-25 06:58:54.805 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:44119]
2024-08-25 06:58:54.835 [D] [server/control.go:243] [bec077128920b93f] new work connection registered
2024-08-25 06:58:54.835 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051]
2024-08-25 06:58:54.835 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:44119])
2024-08-25 06:58:54.836 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed
2024-08-25 06:58:54.836 [D] [server/control.go:243] [bec077128920b93f] new work connection registered
2024-08-25 06:58:54.865 [D] [server/control.go:243] [bec077128920b93f] new work connection registered
2024-08-25 06:58:54.868 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed
2024-08-25 06:58:54.897 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser []
2024-08-25 06:58:54.897 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:44122]
2024-08-25 06:58:54.897 [D] [server/control.go:272] [bec077128920b93f] get work connection from pool
2024-08-25 06:58:54.897 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051]
2024-08-25 06:58:54.898 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:44122])
2024-08-25 06:58:54.928 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed
2024-08-25 06:58:54.928 [D] [server/control.go:243] [bec077128920b93f] new work connection registered
2024-08-25 06:58:54.929 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser []
2024-08-25 06:58:54.929 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:29208]
2024-08-25 06:58:54.929 [D] [server/control.go:272] [bec077128920b93f] get work connection from pool
2024-08-25 06:58:54.930 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051]
2024-08-25 06:58:54.930 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:29208])
2024-08-25 06:58:54.960 [D] [server/control.go:243] [bec077128920b93f] new work connection registered
2024-08-25 06:58:54.961 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed

FRPC log:

2024-08-25 13:58:49.724 [I] [sub/root.go:142] start frpc service for config file [/usr/local/frpc/frpc.ini]
2024-08-25 13:58:49.724 [I] [client/service.go:295] try to connect to server...
2024-08-25 13:58:49.821 [I] [client/service.go:287] [bec077128920b93f] login to server success, get run id [bec077128920b93f]
2024-08-25 13:58:49.822 [I] [proxy/proxy_manager.go:173] [bec077128920b93f] proxy added: [https]
2024-08-25 13:58:49.853 [I] [client/control.go:168] [bec077128920b93f] [https] start proxy success
2024-08-25 13:58:54.838 [D] [proxy/proxy_wrapper.go:260] [bec077128920b93f] [https] start a new work connection, localAddr: 192.168.88.245:47504 remoteAddr: <public IP>:4100
2024-08-25 13:58:54.839 [D] [proxy/proxy.go:210] [bec077128920b93f] [https] join connections, localConn(l[127.0.0.1:38418] r[127.0.0.1:4000]) workConn(l[192.168.88.245:47504] r[<public IP>:4100])
2024-08-25 13:58:54.840 [D] [proxy/proxy.go:222] [bec077128920b93f] [https] join connections closed

I want to highlight the error line here :
[vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser []

that line indicates a configuration error, but I still can't find any reference or clue as to what my error is. I don't use NGINX. I already check the firewall status of both 4000 and 4100 port

Steps to reproduce

...

Affected area

  • Docs
  • Installation
  • Performance and Scalability
  • Security
  • User Experience
  • Test and Release
  • Developer Infrastructure
  • Client Plugin
  • Server Plugin
  • Extensions
  • Others
Originally created by @mdennyh on GitHub (Aug 25, 2024). Original GitHub issue: https://github.com/fatedier/frp/issues/4405 ### Bug Description I have a web service that runs behind NAT. It runs on regular http port 4000 (local) so that I can access it locally in my LAN with `http://<local.ip.address>:4000/` I want to expose this service to the internet so I can access it with `https://<mydomain.ddns.net>:4000/`. I already able to run it with regular http without SSL I rent a public Ubuntu server and run `frps` there. I also use no-IP to provide the domain that I need (this case: `mydomain.ddns.net` I already have SSL certificate from Let's Encrypt. It consists of 2 files: `fullchain.pem` and `privkey.pem`. I generate both using `certbot` from the local server. Using the configurations below, I unable to access the service at all although both `frpc` and `frps` confirm handshake. ### frpc Version 0.60.0 ### frps Version 0.60.0 ### System Architecture linux/amd64 ### Configurations # frps.ini ``` [common] bind_port = 4100 vhost_https_port = 4000 tls_enable = true tls_cert_file = ./path/to/fullchain.pem tls_key_file = ./path/to/privkey.pem log_level = debug ``` # frpc.ini ``` [common] server_addr = <my public server IP address> server_port = 4100 log_level = debug [https] type = https # local server runs at port 4000 also local_port = 4000 custom_domains = mydomain.ddns.net ``` ### Logs whenever I try to access `http://mydomain.ddns.net:4000/` from the web browser the `frps` server prints this: # FPS log: ``` 2024-08-25 06:58:37.718 [I] [frps/root.go:105] frps uses config file: /path/to/frps.ini 2024-08-25 06:58:37.748 [I] [server/service.go:237] frps tcp listen on 0.0.0.0:4100 2024-08-25 06:58:37.748 [I] [server/service.go:319] https service listen on 0.0.0.0:4000 2024-08-25 06:58:37.749 [I] [frps/root.go:114] frps started successfully 2024-08-25 06:58:49.787 [I] [server/service.go:576] [bec077128920b93f] client login info: ip [125.166.9.28:18051] version [0.60.0] hostname [] os [linux] arch [amd64] 2024-08-25 06:58:49.819 [I] [proxy/https.go:67] [bec077128920b93f] [https] https proxy listen for host [mydomain.ddns.net] 2024-08-25 06:58:49.820 [I] [server/control.go:399] [bec077128920b93f] new proxy [https] type [https] success 2024-08-25 06:58:49.820 [D] [server/control.go:243] [bec077128920b93f] new work connection registered 2024-08-25 06:58:54.804 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser [] 2024-08-25 06:58:54.804 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:44120] 2024-08-25 06:58:54.804 [D] [server/control.go:272] [bec077128920b93f] get work connection from pool 2024-08-25 06:58:54.805 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051] 2024-08-25 06:58:54.805 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:44120]) 2024-08-25 06:58:54.805 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser [] 2024-08-25 06:58:54.805 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:44119] 2024-08-25 06:58:54.835 [D] [server/control.go:243] [bec077128920b93f] new work connection registered 2024-08-25 06:58:54.835 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051] 2024-08-25 06:58:54.835 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:44119]) 2024-08-25 06:58:54.836 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed 2024-08-25 06:58:54.836 [D] [server/control.go:243] [bec077128920b93f] new work connection registered 2024-08-25 06:58:54.865 [D] [server/control.go:243] [bec077128920b93f] new work connection registered 2024-08-25 06:58:54.868 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed 2024-08-25 06:58:54.897 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser [] 2024-08-25 06:58:54.897 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:44122] 2024-08-25 06:58:54.897 [D] [server/control.go:272] [bec077128920b93f] get work connection from pool 2024-08-25 06:58:54.897 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051] 2024-08-25 06:58:54.898 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:44122]) 2024-08-25 06:58:54.928 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed 2024-08-25 06:58:54.928 [D] [server/control.go:243] [bec077128920b93f] new work connection registered 2024-08-25 06:58:54.929 [D] [vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser [] 2024-08-25 06:58:54.929 [I] [proxy/proxy.go:204] [bec077128920b93f] [https] get a user connection [114.10.46.173:29208] 2024-08-25 06:58:54.929 [D] [server/control.go:272] [bec077128920b93f] get work connection from pool 2024-08-25 06:58:54.930 [D] [proxy/proxy.go:131] [bec077128920b93f] [https] get a new work connection: [125.166.9.28:18051] 2024-08-25 06:58:54.930 [D] [proxy/proxy.go:261] [bec077128920b93f] [https] join connections, workConn(l[<public IP>:4100] r[125.166.9.28:18051]) userConn(l[<public IP>:4000] r[114.10.46.173:29208]) 2024-08-25 06:58:54.960 [D] [server/control.go:243] [bec077128920b93f] new work connection registered 2024-08-25 06:58:54.961 [D] [proxy/proxy.go:271] [bec077128920b93f] [https] join connections closed ``` # FRPC log: ``` 2024-08-25 13:58:49.724 [I] [sub/root.go:142] start frpc service for config file [/usr/local/frpc/frpc.ini] 2024-08-25 13:58:49.724 [I] [client/service.go:295] try to connect to server... 2024-08-25 13:58:49.821 [I] [client/service.go:287] [bec077128920b93f] login to server success, get run id [bec077128920b93f] 2024-08-25 13:58:49.822 [I] [proxy/proxy_manager.go:173] [bec077128920b93f] proxy added: [https] 2024-08-25 13:58:49.853 [I] [client/control.go:168] [bec077128920b93f] [https] start proxy success 2024-08-25 13:58:54.838 [D] [proxy/proxy_wrapper.go:260] [bec077128920b93f] [https] start a new work connection, localAddr: 192.168.88.245:47504 remoteAddr: <public IP>:4100 2024-08-25 13:58:54.839 [D] [proxy/proxy.go:210] [bec077128920b93f] [https] join connections, localConn(l[127.0.0.1:38418] r[127.0.0.1:4000]) workConn(l[192.168.88.245:47504] r[<public IP>:4100]) 2024-08-25 13:58:54.840 [D] [proxy/proxy.go:222] [bec077128920b93f] [https] join connections closed ``` I want to highlight the error line here : `[vhost/vhost.go:249] [bec077128920b93f] [https] new request host [mydomain.ddns.net] path [] httpUser []` that line indicates a configuration error, but I still can't find any reference or clue as to what my error is. I don't use NGINX. I already check the firewall status of both 4000 and 4100 port ### Steps to reproduce 1. 2. 3. ... ### Affected area - [ ] Docs - [X] Installation - [ ] Performance and Scalability - [ ] Security - [ ] User Experience - [ ] Test and Release - [ ] Developer Infrastructure - [X] Client Plugin - [X] Server Plugin - [ ] Extensions - [ ] Others
Author
Owner

@fatedier commented on GitHub (Aug 26, 2024):

I am not familiar with the use of Let's Encrypt certificates; perhaps you can try searching Google to see if there is relevant information.

<!-- gh-comment-id:2309191510 --> @fatedier commented on GitHub (Aug 26, 2024): I am not familiar with the use of Let's Encrypt certificates; perhaps you can try searching Google to see if there is relevant information.
Author
Owner

@mdennyh commented on GitHub (Aug 26, 2024):

so @fatedier If not Let's Encrypt, then what service do you usually use for SSL?

<!-- gh-comment-id:2309511699 --> @mdennyh commented on GitHub (Aug 26, 2024): so @fatedier If not Let's Encrypt, then what service do you usually use for SSL?
Author
Owner

@mdennyh commented on GitHub (Aug 26, 2024):

This is what I did to obtain the Let's Encrypt certificate:

Install certbot

sudo apt update
sudo apt install certbot

Generate the SSL Certificate

sudo certbot certonly --standalone -d yourdomain.com

the command above gives me 2 files:

/etc/letsencrypt/live/yourdomain.com/privkey.pem    # private key
/etc/letsencrypt/live/yourdomain.com/fullchain.pem  # certificate

(Optional) To renew the certificate automatically

sudo crontab -e
0 0 * * * /usr/bin/certbot renew --quiet

This is how I use Let's Encrypt for other project too

<!-- gh-comment-id:2309522718 --> @mdennyh commented on GitHub (Aug 26, 2024): This is what I did to obtain the Let's Encrypt certificate: ### Install certbot ``` sudo apt update sudo apt install certbot ``` ### Generate the SSL Certificate ``` sudo certbot certonly --standalone -d yourdomain.com ``` the command above gives me 2 files: ``` /etc/letsencrypt/live/yourdomain.com/privkey.pem # private key /etc/letsencrypt/live/yourdomain.com/fullchain.pem # certificate ``` ### (Optional) To renew the certificate automatically ``` sudo crontab -e 0 0 * * * /usr/bin/certbot renew --quiet ``` This is how I use Let's Encrypt for other project too
Author
Owner

@fatedier commented on GitHub (Aug 26, 2024):

https://github.com/fatedier/frp?tab=readme-ov-file#tls

<!-- gh-comment-id:2309532563 --> @fatedier commented on GitHub (Aug 26, 2024): https://github.com/fatedier/frp?tab=readme-ov-file#tls
Author
Owner

@mdennyh commented on GitHub (Aug 26, 2024):

I see. So FRP is incompatible with PEM Chain certificate which Includes all the necessary certificates (such as intermediary CA certificates) in one file. FRP need a root CA cert which certbot simply cannot generate.

In development environment, I need to "act" as my own Certificate Authority by self-signing the CA with openssl as your example in https://github.com/fatedier/frp?tab=readme-ov-file#tls

In production, I cannot use certbot and had to use another SSL provider that can give me separate files: individual root, intermediate, and end-entity certificate files.

FRP need certificate.crt and ca.crt that I get from SSL provider, also the certificate.key that I get from the server (while generating the CSR)

<!-- gh-comment-id:2309649761 --> @mdennyh commented on GitHub (Aug 26, 2024): I see. So FRP is incompatible with PEM Chain certificate which Includes all the necessary certificates (such as intermediary CA certificates) in one file. FRP need **a root CA cert** which `certbot` simply cannot generate. In development environment, I need to "act" as my own Certificate Authority by self-signing the CA with `openssl` as your example in https://github.com/fatedier/frp?tab=readme-ov-file#tls In production, I cannot use `certbot` and had to use another SSL provider that can give me separate files: individual root, intermediate, and end-entity certificate files. FRP need `certificate.crt` and `ca.crt` that I get from SSL provider, also the `certificate.key` that I get from the server (while generating the CSR)
Author
Owner

@fatedier commented on GitHub (Aug 26, 2024):

If I understand correctly, ca.crt is not required.

<!-- gh-comment-id:2309653994 --> @fatedier commented on GitHub (Aug 26, 2024): If I understand correctly, `ca.crt` is not required.
Author
Owner

@mdennyh commented on GitHub (Aug 26, 2024):

Do you mean that this line: transport.tls.trustedCaFile = "ca.crt" not required ?

<!-- gh-comment-id:2309658788 --> @mdennyh commented on GitHub (Aug 26, 2024): Do you mean that this line: `transport.tls.trustedCaFile = "ca.crt"` not required ?
Author
Owner

@mdennyh commented on GitHub (Aug 26, 2024):

Finally it works!

I use the bundled SSL certificate provided by NoIP service but any providers would do.

I also had to update configuration file to TOML

frps.toml

bindPort = 4100
vhostHTTPSPort = 4000

transport.tls.force = true
transport.tls.certFile = "/path/to/my_server.crt"
transport.tls.keyFile = "/path/to/my_server.key"

yes the transport.tls.trustedCaFile = "ca.crt" is not needed here

frpc.toml

# frpc.toml
serverAddr = "<my public server IP address>"
serverPort = 4100

[[proxies]]
name = "plugin_https2http"
type = "https"
customDomains = ["mydomain.ddns.net"]
[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:4000"
crtPath = "/usr/local/frpc/my_server.crt"
keyPath = "/usr/local/frpc/my_server.key"
hostHeaderRewrite = "127.0.0.1"
requestHeaders.set.x-from-where = "frp"

Thank you

<!-- gh-comment-id:2310339834 --> @mdennyh commented on GitHub (Aug 26, 2024): Finally it works! I use the bundled SSL certificate provided by NoIP service but any providers would do. I also had to update configuration file to TOML # frps.toml ``` bindPort = 4100 vhostHTTPSPort = 4000 transport.tls.force = true transport.tls.certFile = "/path/to/my_server.crt" transport.tls.keyFile = "/path/to/my_server.key" ``` yes the `transport.tls.trustedCaFile = "ca.crt" ` is not needed here # frpc.toml ``` # frpc.toml serverAddr = "<my public server IP address>" serverPort = 4100 [[proxies]] name = "plugin_https2http" type = "https" customDomains = ["mydomain.ddns.net"] [proxies.plugin] type = "https2http" localAddr = "127.0.0.1:4000" crtPath = "/usr/local/frpc/my_server.crt" keyPath = "/usr/local/frpc/my_server.key" hostHeaderRewrite = "127.0.0.1" requestHeaders.set.x-from-where = "frp" ``` Thank you
Author
Owner

@lumen-novum commented on GitHub (Jun 4, 2025):

For anyone else who has this issue in the future, I would like to mention that the Let's Encrypt certificates from Certbot do work with frp. Using @mdennyh 's setup, all I had to do was set certFile to cert.pem and keyFile to privkey.pem.

Works great with my setup.

<!-- gh-comment-id:2940682570 --> @lumen-novum commented on GitHub (Jun 4, 2025): For anyone else who has this issue in the future, I would like to mention that the Let's Encrypt certificates from Certbot do work with frp. Using @mdennyh 's setup, all I had to do was set `certFile` to cert.pem and `keyFile` to privkey.pem. Works great with my setup.
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#3482
No description provided.