WSS TLS handshake error

1. The problem I’m having:

WSS TLS Handshake problem for my subdomain.

The device trying to connect is using an OCPP protocol without any authentication, I get some connected but this one says TLS Handshake problem!

2. Error messages and/or full log output:

{"level":"debug","ts":1723118114.8205967,"logger":"http.stdlib","msg":"http: TLS handshake error from ip:54612: EOF"}

3. Caddy version:

v2.8.4

4. How I installed and ran Caddy:

directly in ubuntu

a. System environment:

Ubuntu 22.04

b. Command:

d. My complete Caddy config:

# The Caddyfile is an easy way to configure your Caddy web server.
#
# Unless the file starts with a global options block, the first
# uncommented line is always the address of your site.
#
# To use your own domain name (with automatic HTTPS), first make
# sure your domain's A/AAAA DNS records are properly pointed to
# this machine's public IP, then replace ":80" below with your
# domain name.
{
    email me@email.com
    key_type rsa2048
    debug
}
:80 {
	# Set this path to your site's directory.
	root * /usr/share/caddy

	# Enable the static file server.
	file_server

	# Another common task is to set up a reverse proxy:
	# reverse_proxy localhost:8080

	# Or serve a PHP site through php-fpm:
	# php_fastcgi localhost:9000
}

wss.myapp.com {
	@websockets {
	header Connection *Upgrade*
	header Connection *upgrade*
	header Upgrade websocket
	}
	reverse_proxy @websockets 127.0.0.1:8010
	log {
    		output file /var/log/caddy/app-access.log {
        	roll_size 10mb
        	roll_keep 20
        	roll_keep_for 720h
      		}
  }
}

Here is the entire log that I have:

Aug 09 07:02:50 systemd[1]: caddy.service: Deactivated successfully.
Aug 09 07:02:50 systemd[1]: Stopped Caddy.
Aug 09 07:02:50 systemd[1]: Starting Caddy...
Aug 09 07:02:50 caddy[3250641]: caddy.HomeDir=/var/lib/caddy
Aug 09 07:02:50 caddy[3250641]: caddy.AppDataDir=/var/lib/caddy/.local/share/caddy
Aug 09 07:02:50 caddy[3250641]: caddy.AppConfigDir=/var/lib/caddy/.config/caddy
Aug 09 07:02:50 caddy[3250641]: caddy.ConfigAutosavePath=/var/lib/caddy/.config/caddy/autosave.json
Aug 09 07:02:50 caddy[3250641]: caddy.Version=v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
Aug 09 07:02:50 caddy[3250641]: runtime.GOOS=linux
Aug 09 07:02:50 caddy[3250641]: runtime.GOARCH=amd64
Aug 09 07:02:50 caddy[3250641]: runtime.Compiler=gc
Aug 09 07:02:50 caddy[3250641]: runtime.NumCPU=3
Aug 09 07:02:50 caddy[3250641]: runtime.GOMAXPROCS=3
Aug 09 07:02:50 caddy[3250641]: runtime.Version=go1.22.3
Aug 09 07:02:50 caddy[3250641]: os.Getwd=/
Aug 09 07:02:50 caddy[3250641]: LANG=en_US.UTF-8
Aug 09 07:02:50 caddy[3250641]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Aug 09 07:02:50 caddy[3250641]: NOTIFY_SOCKET=/run/systemd/notify
Aug 09 07:02:50 caddy[3250641]: HOME=/var/lib/caddy
Aug 09 07:02:50 caddy[3250641]: LOGNAME=caddy
Aug 09 07:02:50 caddy[3250641]: USER=caddy
Aug 09 07:02:50 caddy[3250641]: INVOCATION_ID=e397a7d480964d90bfda9cadab60a4b5
Aug 09 07:02:50 caddy[3250641]: JOURNAL_STREAM=8:223540212
Aug 09 07:02:50 caddy[3250641]: SYSTEMD_EXEC_PID=3250641
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6278996,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6297174,"msg":"adapted config to JSON","adapter":"caddyfile"}
Aug 09 07:02:50 caddy[3250641]: {"level":"warn","ts":1723186970.6297307,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":11}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6307454,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//127.0.0.1:2019","//localhost:2019","//[::1]:2019"]}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.630907,"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}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6309319,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
Aug 09 07:02:50 caddy[3250641]: {"level":"warn","ts":1723186970.6309392,"logger":"http.auto_https","msg":"server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server","server_name":"srv1","http_port":80}
Aug 09 07:02:50 caddy[3250641]: {"level":"debug","ts":1723186970.6309674,"logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{"key_type":"rsa2048"}]}},"http":{"servers":{"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"127.0.0.1:8010"}]}],"match":[{"header":{"Connection":["*Upgrade*","*upgrade*"],"Upgrade":["websocket"]}}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{},"logs":{"logger_names":{"wss.myapp.com":["log0"]}}},"srv1":{"listen":[":80"],"routes":[{},{"handle":[{"handler":"vars","root":"/usr/share/caddy"},{"handler":"file_server","hide":["/etc/caddy/Caddyfile"]}]},{}],"automatic_https":{"disable":true}}}}}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6313033,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00061a580"}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6318195,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
Aug 09 07:02:50 caddy[3250641]: {"level":"debug","ts":1723186970.631938,"logger":"http","msg":"starting server loop","address":"[::]:443","tls":true,"http3":true}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6319509,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
Aug 09 07:02:50 caddy[3250641]: {"level":"debug","ts":1723186970.6320364,"logger":"http","msg":"starting server loop","address":"[::]:80","tls":false,"http3":false}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6320448,"logger":"http.log","msg":"server running","name":"srv1","protocols":["h1","h2","h3"]}
Aug 09 07:02:50 caddy[3250641]: {"level":"debug","ts":1723186970.632923,"logger":"tls","msg":"loading managed certificate","domain":"wss.myapp.com","expiration":1728203574,"issuer_key":"acme-v02.api.letsencrypt.org-directory","storage":"FileStorage:/var/lib/caddy/.local/share/caddy"}
Aug 09 07:02:50 caddy[3250641]: {"level":"debug","ts":1723186970.633204,"logger":"tls.cache","msg":"added certificate to cache","subjects":["wss.myapp.com"],"expiration":1728203574,"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"f1f5063293d8acd1e163352381b0ae06020464223ac4cd2647cde1993231a475","cache_size":2,"cache_capacity":10000}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.633219,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/var/lib/caddy/.local/share/caddy","instance":"be9691a3-4c38-4ce3-a330-2f1c8d0977e0","try_again":1723273370.6332178,"try_again_in":86399.99999968}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6332784,"logger":"tls","msg":"finished cleaning storage units"}
Aug 09 07:02:50 caddy[3250641]: {"level":"debug","ts":1723186970.6332283,"logger":"events","msg":"event","name":"cached_managed_cert","id":"19cae5d7-ea57-444d-aa62-0bca455e226e","origin":"tls","data":{"sans":["wss.myapp.cm"]}}
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6366217,"msg":"autosaved config (load with --resume flag)","file":"/var/lib/caddy/.config/caddy/autosave.json"}
Aug 09 07:02:50 systemd[1]: Started Caddy.
Aug 09 07:02:50 caddy[3250641]: {"level":"info","ts":1723186970.6383379,"msg":"serving initial configuration"}
Aug 09 07:03:17 caddy[3250641]: {"level":"debug","ts":1723186997.2410202,"logger":"http.stdlib","msg":"http: TLS handshake error from ip:55760: EOF"}

and also this:

//not working
Jul 24 15:44:12 [1629176]: {"level":"error","ts":1721835852.9529366,"logger":"http.log.error.log0","msg":"dial tcp 127.0.0.1:8010: connect: connection refused","request":{"remote_ip":"ip","remote_port":"50033","client_ip":"ip","proto":"HTTP/1.1","method":"GET","host":"wss.myapp.com:443","uri":"/ocpp/1234/567/st01","headers":{"Upgrade":["websocket"],"Connection":["Upgrade"],"Sec-Websocket-Key":["h1Pt7GEL7jXXwcktQjoixQ=="],"Sec-Websocket-Protocol":["ocpp1.6"],"Sec-Websocket-Version":["13"]},"tls":{"resumed":false,"version":771,"cipher_suite":49199,"proto":"","server_name":"wss.myapp.com"}},"duration":0.000743485,"status":502,"err_id":"8r2y9q8ig","err_trace":"reverseproxy.statusError (reverseproxy.go:1269)"}
Jul 24 15:45:13 [1629176]: {"level":"error","ts":1721835913.2652106,"logger":"http.log.error.log0","msg":"dial tcp 127.0.0.1:8010: connect: connection refused","request":{"remote_ip":"ip","remote_port":"50034","client_ip":"ip","proto":"HTTP/1.1","method":"GET","host":"wss.myapp.com:443","uri":"/ocpp/1234/567/st01","headers":{"Sec-Websocket-Protocol":["ocpp1.6"],"Sec-Websocket-Version":["13"],"Upgrade":["websocket"],"Connection":["Upgrade"],"Sec-Websocket-Key":["5a6OBEw+CBWcr+h5bCvy7g=="]},"tls":{"resumed":false,"version":771,"cipher_suite":49199,"proto":"","server_name":"wss.myapp.com"}},"duration":0.000398294,"status":502,"err_id":"cvdw87ep5","err_trace":"reverseproxy.statusError (reverseproxy.go:1269)"}
Jul 24 15:46:13 [1629176]: {"level":"error","ts":1721835973.1385367,"logger":"http.log.error.log0","msg":"dial tcp 127.0.0.1:8010: connect: connection refused","request":{"remote_ip":"ip","remote_port":"50035","client_ip":"ip","proto":"HTTP/1.1","method":"GET","host":"wss.myapp.com:443","uri":"/ocpp/1234/567/st01","headers":{"Connection":["Upgrade"],"Sec-Websocket-Key":["05IE9e2Ry5dS7PbfJutGyg=="],"Sec-Websocket-Protocol":["ocpp1.6"],"Sec-Websocket-Version":["13"],"Upgrade":["websocket"]},"tls":{"resumed":false,"version":771,"cipher_suite":49199,"proto":"","server_name":"wss.myapp.com"}},"duration":0.000364427,"status":502,"err_id":"pir0twx9h","err_trace":"reverseproxy.statusError (reverseproxy.go:1269)"}


//working

Aug 09 07:06:51 [3250641]: {"level":"debug","ts":1723187211.7254717,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"127.0.0.1:8010","duration":0.001991361,"request":{"remote_ip":"ip","remote_port":"42565","client_ip":"ip","proto":"HTTP/1.1","method":"GET","host":"wss.myapp.com:443","uri":"/ocpp/1234/567","headers":{"Sec-Websocket-Key":["x3JJHMbDL1EzLkh9GBhXDw=="],"X-Forwarded-Proto":["https"],"Sec-Websocket-Version":["13"],"Connection":["Upgrade"],"Upgrade":["websocket"],"User-Agent":[""],"X-Forwarded-For":["ip"],"X-Forwarded-Host":["wss.myapp.com:443"],"Sec-Websocket-Protocol":["ocpp1.6"]},"tls":{"resumed":false,"version":771,"cipher_suite":49199,"proto":"","server_name":"wss.myapp.com"}},"headers":{"Upgrade":["websocket"],"Connection":["Upgrade"],"Sec-Websocket-Accept":["HSmrc0sMlYUkAGmm5OPpG2HaGWk="],"Sec-Websocket-Protocol":["ocpp1.6"],"Uwebsockets":["20"]},"status":101}
Aug 09 07:06:51 [3250641]: {"level":"debug","ts":1723187211.7255325,"logger":"http.handlers.reverse_proxy","msg":"upgrading connection","upstream":"127.0.0.1:8010","duration":0.001991361,"request":{"remote_ip":"ip","remote_port":"42565","client_ip":"ip","proto":"HTTP/1.1","method":"GET","host":"wss.myapp.com:443","uri":"/ocpp/1234/567","headers":{"Sec-Websocket-Key":["x3JJHMbDL1EzLkh9GBhXDw=="],"X-Forwarded-Proto":["https"],"Sec-Websocket-Version":["13"],"Connection":["Upgrade"],"Upgrade":["websocket"],"User-Agent":[""],"X-Forwarded-For":["ip"],"X-Forwarded-Host":["wss.myapp.com:443"],"Sec-Websocket-Protocol":["ocpp1.6"]},"tls":{"resumed":false,"version":771,"cipher_suite":49199,"proto":"","server_name":"wss.myapp.com"}}}

I don’t know what OCPP is. Is it not HTTP? Caddy’s standard distribution only includes an HTTP server, it can’t handle arbitrary TCP traffic. For that you would need GitHub - mholt/caddy-l4: Layer 4 (TCP/UDP) app for Caddy

You only need the websockets matcher if you’re trying to split up traffic (i.e. send websocket traffic to one upstream and the rest to another). If you’re not doing that, you can simplify it to just this (dropping the matcher):

reverse_proxy 127.0.0.1:8010

You should remove this from your config. Having a :80 site will mess with HTTP->HTTPS redirects. That’s just there to give you a welcome page when you first install Caddy, you’re not meant to keep it there afterwards.

2 Likes

Could you please clarify that? It doesn’t seem to mess with the implicit redirects from auto_https if that is what you meant?

Below is what I used to verify, everything is bundled into a single compose.yaml file you can copy/paste, then just run the CLI commands shown at the end :slight_smile:

# For the separate container to reference by name:
networks:
  default:
    name: custom-network

services:
  reverse-proxy:
    image: caddy:2.8
    container_name: caddy
    # Normally this would be `volumes`, but `configs` embeds config for a simple copy/paste `compose.yaml` example
    configs:
      - source: caddy-config
        target: /etc/caddy/Caddyfile
    # Support for requests from the Docker host like: `https://example.localhost`
    ports:
      - "80:80"
      - "443:443"
    # Containers on this network will resolve these aliases to the IP of this container:
    networks:
      default:
        aliases:
          - example.test

configs:
  caddy-config:
    content: |
      {
        local_certs
        # Docker Compose ENV interpolation feature to toggle auto_https:
        ${AUTO_HTTPS:-}
      }

      :80 {
        respond "Hello from port 80"
      }

      # `auto_https disable_redirects` would need require this for HTTP + HTTPS access:
      #http://example.test, https://example.test {
      example.test, example.localhost {
        respond "Hello from {scheme}://{host}"
      }
$ docker compose up --force-recreate

# Run a separate container on the same network to curl from and leverage container DNS
$ docker run --rm -it --network custom-network fedora

# HTTP => HTTPS redirect works:
$ curl -L --insecure http://example.test
Hello from https://example.test

# Caddy container also reachable via container_name:
$ curl -L --insecure http://caddy
Hello from port 80
# Repeat but this time with implicit redirects disabled:
$ AUTO_HTTPS='auto_https disable_redirects' docker compose up --force-recreate
$ docker run --rm -it --network custom-network fedora

# HTTP => HTTPS redirect disabled as expected:
$ curl -L --insecure http://example.test
Hello from port 80

# HTTPS still available directly as expected:
$ curl --insecure https://example.test
Hello from https://example.test

It’s for when a request is made to a domain that doesn’t appear in the config (e.g. foo.test), then the redirect to HTTPS would be overridden with that site block.

But let’s not get off topic here. That wasn’t the users question in this topic.

1 Like

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