Internal-only Reverse Proxy for HTTPS

I have internal services (NextCloud, RocketChat, etc), currently serving them on HTTP that I want to create an HTTPS proxy for all. All internal, not exposing anything online (sites, caddy, CA, DNS, etc). I’ve started with just 1 site and the browser indicates that a cert is not served with the site but it is being reverse proxy’d thru caddy.

1. The problem I’m having:

When accessing internal sites via HTTPS, browsers give an “unsecured” error. Caddy is reversed proxy’ing for site on the same server.

$ curl -v https://192.168.1.42
*   Trying 192.168.1.42:443...
* Connected to 192.168.1.42 (192.168.1.42) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Unknown (21):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:0A000438:SSL routines::tlsv1 alert internal error
* Closing connection 0
curl: (35) error:0A000438:SSL routines::tlsv1 alert internal error

2. Error messages and/or full log output:

{"level":"info","ts":1709302025.5292373,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1709302025.533614,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1709302025.536512,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1709302025.5373704,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000421900"}
{"level":"info","ts":1709302025.5389552,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
{"level":"info","ts":1709302025.5391924,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"debug","ts":1709302025.5394068,"logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{"subjects":["192.168.1.42"]},{}]}},"http":{"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"192.168.1.42:8010"}]}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{}}}}}
{"level":"warn","ts":1709302025.5957437,"logger":"pki.ca.local","msg":"installing root certificate (you might be prompted for password)","path":"storage:pki/authorities/local/root.crt"}
{"level":"info","ts":1709302025.596777,"msg":"warning: \"certutil\" is not available, install \"certutil\" with \"apt install libnss3-tools\" or \"yum install nss-tools\" and try again"}
{"level":"info","ts":1709302025.5974088,"msg":"define JAVA_HOME environment variable to use the Java trust"}
{"level":"info","ts":1709302025.7444022,"msg":"certificate installed properly in linux trusts"}
{"level":"info","ts":1709302025.7449577,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1709302025.7452,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
{"level":"debug","ts":1709302025.74586,"logger":"http","msg":"starting server loop","address":"[::]:443","tls":true,"http3":true}
{"level":"info","ts":1709302025.7459059,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"debug","ts":1709302025.746005,"logger":"http","msg":"starting server loop","address":"[::]:80","tls":false,"http3":false}
{"level":"info","ts":1709302025.7460155,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1709302025.7460225,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["192.168.1.42"]}
{"level":"warn","ts":1709302025.7518303,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [192.168.1.42]: no OCSP server specified in certificate","identifiers":["192.168.1.42"]}
{"level":"debug","ts":1709302025.75189,"logger":"tls.cache","msg":"added certificate to cache","subjects":["192.168.1.42"],"expiration":1709322111,"managed":true,"issuer_key":"local","hash":"cf143085f423cdccdf138856c8d46d2a2bdf35c46c81f45b895bfff39ec16a53","cache_size":1,"cache_capacity":10000}
{"level":"debug","ts":1709302025.7519205,"logger":"events","msg":"event","name":"cached_managed_cert","id":"3311e3bb-2e5e-40f6-8560-ec103b216049","origin":"tls","data":{"sans":["192.168.1.42"]}}
{"level":"info","ts":1709302025.7539043,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1709302025.7540946,"msg":"serving initial configuration"}
{"level":"warn","ts":1709302025.7574959,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"c24f5be4-e2df-43ba-b80c-d935981c9732","try_again":1709388425.7574909,"try_again_in":86399.999998323}
{"level":"info","ts":1709302025.757803,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"debug","ts":1709302032.2533705,"logger":"events","msg":"event","name":"tls_get_certificate","id":"835c36df-29aa-4e2d-8a87-cfdc9034e9ba","origin":"tls","data":{"client_hello":{"CipherSuites":[4866,4867,4865,49196,49200,159,52393,52392,52394,49195,49199,158,49188,49192,107,49187,49191,103,49162,49172,57,49161,49171,51,157,156,61,60,53,47,255],"ServerName":"","SupportedCurves":[29,23,30,25,24,256,257,258,259,260],"SupportedPoints":"AAEC","SignatureSchemes":[1027,1283,1539,2055,2056,2057,2058,2059,2052,2053,2054,1025,1281,1537,771,769,770,1026,1282,1538],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771],"RemoteAddr":{"IP":"192.168.1.42","Port":58620,"Zone":""},"LocalAddr":{"IP":"172.28.0.4","Port":443,"Zone":""}}}}
{"level":"debug","ts":1709302032.2538145,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"172.28.0.4"}
{"level":"debug","ts":1709302032.2538793,"logger":"tls.handshake","msg":"no certificate matching TLS ClientHello","remote_ip":"192.168.1.42","remote_port":"58620","server_name":"","remote":"192.168.1.42:58620","identifier":"172.28.0.4","cipher_suites":[4866,4867,4865,49196,49200,159,52393,52392,52394,49195,49199,158,49188,49192,107,49187,49191,103,49162,49172,57,49161,49171,51,157,156,61,60,53,47,255],"cert_cache_fill":0.0001,"load_or_obtain_if_necessary":true,"on_demand":false}
{"level":"debug","ts":1709302032.2541714,"logger":"http.stdlib","msg":"http: TLS handshake error from 192.168.1.42:58620: no certificate available for '172.28.0.4'"}

Not sure where this IP is coming from in the logs either:

"identifier":"172.28.0.4"

3. Caddy version:

v2.7.6

4. How I installed and ran Caddy:

Docker compose

a. System environment:

Linux Mint 21 Vanessa, Docker: 24.0.7, build afdd53b

b. Command:

sudo docker-compose -f ~/Desktop/_selfhosted/docker/caddy2.yml --env-file ~/Desktop/_selfhosted/docker/.env up

.env

SELFHOSTED_DIR=/home/usr123/Desktop/_selfhosted

c. Service/unit/compose file:

caddy2.yml:

version: "3.7"

services:
  caddy_ssl:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "8083:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - $SELFHOSTED_DIR/caddy2/caddy_data:/data
      - $SELFHOSTED_DIR/caddy2/Caddyfile:/etc/caddy/Caddyfile

volumes:
  caddy_data:
    external: true
  caddy_config:

d. My complete Caddy config:

{
    debug
}

192.168.1.42 {
	tls internal
	reverse_proxy http://192.168.1.42:8010
}

You need to install Caddy’s root CA cert on the machines that will be connecting to Caddy. See the docs, which explain how to grab the root CA cert when running Caddy in Docker:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.