Search code examples
sslcurlproxyreverse-proxycaddy

Caddy reverse proxy server alerted internal error on attempt to relay TLS client hello


I tried to let the Caddy reverse proxy server relay the TLS handshake between the client and the back server, but failed at very beginning when the proxy just received the TLS client hello. Caddy v2.6.2 and Curl v7.87.0 were under test below.

/etc/hosts:

127.0.0.1 localhost back-server.local proxy-server.local

Caddyfile-back-server:

{ http_port 2015 }
back-server.local:2016
respond "Hello, world!"

Caddyfile-proxy-server:

{ http_port 2017 }
proxy-server.local:2018 {
  reverse_proxy https://back-server.local:2016 {
    header_up Host {upstream_hostport}
  }
}

Initial tests were OK below.

$ caddy start --config Caddyfile-back-server
$ caddy start --config Caddyfile-proxy-server
$ curl https://back-server.local:2016
Hello, world!
$ curl https://proxy-server.local:2018
Hello, world!

The next test failed to relay the TLS client hello below.

$ curl --connect-to back-server.local:2016:proxy-server.local:2018 https://back-server.local:2016
curl: (35) ... internal error

According to the captured packets, sni: back-server.local was sent from the TLS client hello to proxy-server.local:2018, but the proxy returned TLS server alert: internal error, then closed the connection right away. No communication happened at all between proxy-server.local and back-server.local:2016.

What could be wrong and how to make it work?


Solution

  • Caddy server as reverse proxy doesn't use SNI from TLS client hello for the related TLS passthrough to the back server, it's the job of TLS forward proxy. There's Caddy L4 plugin existing for L4 routing including TLS SNI-based routing.

    Below was successful against this problem along with another reverse proxy FRP capable of acting as TLS forward proxy as well.

    /etc/hosts

    127.0.0.1 localhost back-server.local proxy-server.local
    

    Caddyfile-back-server

    { http_port 2015 }
    back-server.local:2016
    respond "Hello, world!"
    

    frps.ini

    [common]
    vhost_https_port = 2018
    

    frpc.ini

    [common]
    
    [TLS passthrough]
    type = https
    local_port = 2016
    custom_domains = back-server.local
    

    Then the test went through as expected. All the configuration files were put at PWD for simplicity.

    $ caddy start --config Caddyfile-back-server
    $ frps
    $ frpc
    $ curl --connect-to back-server.local:2016:proxy-server.local:2018 https://back-server.local:2016
    Hello, world!