Automatic HTTPS with IP address

1. Caddy version (caddy version):

2.5.1

2. How I run Caddy:

docker-compose

a. System environment:

Ubuntu 20.04, Docker 20.10.15, Compose 1.25.0

b. Command:

docker-compose up -d

c. Service/unit/compose file:

version: "2.2"

services:
  caddy:
    container_name: caddy-cluster-proxy
    image: caddy:2.5.1-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - caddy_data:/data
      - ./:/etc/caddy/
    command: caddy run --config /etc/caddy/Caddyfile --watch

volumes:
  # Cached caddy data, e.g. certs
  caddy_data:

d. My complete Caddyfile or JSON config:

import "*.Caddyfile"

{
	debug
}

https://159.223.140.9 {
	header {
		Cache-Control "no-cache, no-store, must-revalidate"
	}
	encode gzip
	handle_path /107731/* {
		reverse_proxy http://159.223.140.9:8000 {
			flush_interval -1
		}
	}

}

3. The problem I’m having:

I want to enable HTTPS on just an IP address. When I use the above config I get HTTPS errors in my browser, and with curl:

curl https://159.223.140.9 -k -v
*   Trying 159.223.140.9:443...
* Connected to 159.223.140.9 (159.223.140.9) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* 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

4. Error messages and/or full log output:

{"level":"info","ts":1657528686.1966174,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":""}
{"level":"warn","ts":1657528686.19679,"msg":"No files matching import glob pattern","pattern":"*.Caddyfile"}
{"level":"warn","ts":1657528686.1981165,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":1}
{"level":"info","ts":1657528686.1991653,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1657528686.1993258,"logger":"http","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":1657528686.199342,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1657528686.1994512,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000217ab0"}
{"level":"info","ts":1657528686.200295,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
{"level":"info","ts":1657528686.2009776,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1657528686.2203028,"logger":"pki.ca.local","msg":"root certificate is already trusted by system","path":"storage:pki/authorities/local/root.crt"}
{"level":"debug","ts":1657528686.2206156,"logger":"http","msg":"starting server loop","address":"[::]:443","http3":false,"tls":true}
{"level":"debug","ts":1657528686.2206867,"logger":"http","msg":"starting server loop","address":"[::]:80","http3":false,"tls":false}
{"level":"info","ts":1657528686.2207088,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["159.223.140.9"]}
{"level":"warn","ts":1657528686.2211394,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [159.223.140.9]: no OCSP server specified in certificate","identifiers":["159.223.140.9"]}
{"level":"debug","ts":1657528686.2211623,"logger":"tls.cache","msg":"added certificate to cache","subjects":["159.223.140.9"],"expiration":1657569657,"managed":true,"issuer_key":"local","hash":"9d440d4d2bbab98eeaf1e2a3ed669bbec7c347598f7f6a30bbffbc73b5ebc191","cache_size":1,"cache_capacity":10000}
{"level":"info","ts":1657528686.221428,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1657528686.2214453,"msg":"serving initial configuration"}
{"level":"info","ts":1657528686.2215388,"logger":"watcher","msg":"watching config file for changes","config_file":"/etc/caddy/Caddyfile"}

5. What I already tried:

I believe HTTPS is technically possible with IP addresses: https - Is it possible to have SSL certificate for IP address, not domain name? - Stack Overflow

And I think Caddy uses ZeroSSL, which supports certs for IP addresses: https://help.zerossl.com/hc/en-us/articles/360060119973-Is-It-Possible-To-Generate-a-SSL-Certificate-for-an-IP-Address-

But I’ve only seen cert errors when I use this setup.

(Why am I doing this? We spin up/down servers every day on a schedule with terraform. Getting DNS to work with this system would be a pain. Currently we have a few small permanent servers that I run Caddy on it with a regular domain name that reverse proxies to our Terraform servers, but I’m trying to remove this server-for-the-sake-of-a-domain-name).

6. Links to relevant resources:

Hi :wave:

Caddy is able to use certs for IP addresses.
It just won’t be publically trusted, but instead self-signed when using the auto-https feature currently.
The docs/automatic-https#hostname-requirements (pretty far down though) state:

[…]
In addition, hostnames qualify for publicly-trusted certificates if they:

  • are not an IP address

I am pretty sure I read an issue or some mention to track it not long ago, but I can’t seem to find it right now :frowning:
Maybe someone else has some insights on that.

A quick workaround, at least for now, if you want publicly-trusted certificates, would be to use services like https://nip.io/ that resolve 159.223.140.9.nip.io as 159.223.140.9 without any additional setup.
That way you would have a “valid” domain name :woman_shrugging:

Though, you really shouldn’t be getting SSL routines::tlsv1 alert internal error when using the plain IP.
Both https://159.223.140.9 { and 159.223.140.9 { are valid and will serve that vhost via some self-signed certificate.

Are you absolutely sure that the Caddyfile and logs you shared are from the on the server publically accessible under 159.223.140.9 and not some other server?

2 Likes

Context:

ZeroSSL supposedly supports it but nobody has tried it out yet to confirm whether they actually do. And Certmagic will probably need some updates/fixes to allow it if it does work.

But yeah, for now, you need a domain name. Or use Caddy’s internal CA.

3 Likes

As others have said, Caddy will present a certificate for an IP address, but it won’t be trusted by default. It attempts to install trust into the local root store, but that requires a password and only works for some clients on the local machine. (That’s not a limitation of Caddy.) For a publicly-trusted IP certificate, you’ll need a CA that supports issuing that (preferably via ACME, since Caddy supports that already).

Thank you so much! nip.io provides exactly what I need. And it’s easy and free. Appreciate it!

1 Like

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