I have a code-server program listening to http://localhost:8080 requests.
I’m trying to run a non-root reverse proxy on custom http(s) ports as shown in the Caddyfile to relay requests to this server through https. The problem is http/8081 works, but https/8082 doesn’t, even though it is not a root port.
Non-root caddy’s certificate is already trusted. Https works as desired when I run the following command instead. I have to insert a https://localhost though for it to work.
$ caddy start
2021/05/26 14:29:19.470 INFO using adjacent Caddyfile
2021/05/26 14:29:19.472 INFO admin admin endpoint started {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["localhost:2019", "[::1]:2019", "127.0.0.1:2019"]}
2021/05/26 14:29:19.472 INFO http server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server {"server_name": "srv0", "http_port": 8081}
2021/05/26 14:29:19.472 INFO http server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv1", "https_port": 8082}
2021/05/26 14:29:19.472 INFO http enabling automatic HTTP->HTTPS redirects {"server_name": "srv1"}
2021/05/26 14:29:19.472 WARN http user server is listening on same interface as automatic HTTP->HTTPS redirects; user-configured routes might override these redirects {"server_name": "srv0", "interface": "tcp/:8081"}
2021/05/26 14:29:19.472 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc00035f2d0"}
2021/05/26 14:29:19.472 INFO tls cleaned up storage units
2021/05/26 14:29:19.472 INFO autosaved config {"file": "/home/user/.local/share/caddy/autosave.json"}
2021/05/26 14:29:19.472 INFO serving initial configuration
Successfully started Caddy (pid=76436) - Caddy is running in the background
5. What I already tried:
Running it as superuser with command line options works (as shown above), but that is far from what I need.
I’ve followed the following resources, no fruit.
You didn’t tell Caddy to manage any certificates, so the TLS handshake cannot be completed.
When you ran it with localhost, Caddy issued a certificate with the name localhost, using its internal CA, which is automatically enabled if Caddy sees the domain to look like something that can’t be publicly trusted. Read the docs here:
Caddy can issue certificates on demand for connections without a domain (i.e. an IP address), but you need to enable the on_demand option.
You’d be better off running Caddy as a systemd service, which will run as the caddy user typically (non-root) but with the CAP_NET_BIND_SERVICE capability enabled (which allows binding to low ports for non-root users). If you installed Caddy using pacman then you should have the systemd service already wired up:
I added the interval and the burst directives because of this output (too many "obtaining new certificate" messages). I’m not sure why this is happening.
You’re right. It’s four attempts per request, twice a second on average.
It’s not the only output though.
Here’s the complete log after one curl request (I put the on_demand_tls directive to avoid duplicate certificate requests).
2021/05/27 05:31:10.477 INFO using adjacent Caddyfile
2021/05/27 05:31:10.479 INFO admin admin endpoint started {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["localhost:2019", "[::1]:2019", "127.0.0.1:2019"]}
2021/05/27 05:31:10.479 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc0003bca10"}
2021/05/27 05:31:10.486 INFO http server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server {"server_name": "srv0", "http_port": 8081}
2021/05/27 05:31:10.486 INFO http server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv1", "https_port": 8082}
2021/05/27 05:31:10.486 INFO http enabling automatic HTTP->HTTPS redirects "server_name": "srv1"}
2021/05/27 05:31:10.486 WARN http user server is listening on same interface as automatic HTTP->HTTPS redirects; user-configured routes might override these redirects "server_name": "srv0", "interface": "tcp/:8081"}
2021/05/27 05:31:10.486 INFO tls cleaned up storage units
2021/05/27 05:31:10.486 INFO autosaved config {"file": "/home/user/.local/share/caddy/autosave.json"}
2021/05/27 05:31:10.486 INFO serving initial configuration
2021/05/27 06:18:46.591 INFO tls.on_demand obtaining new certificate {"server_name": "192.168.1.42"}
And here’s the curl output.
$ curl -v "http://192.168.1.42:8081"
* Trying 192.168.1.42:8081...
* Connected to 192.168.1.42 (192.168.1.42) port 8081 (#0)
> GET / HTTP/1.1
> Host: 192.168.1.42:8081
> User-Agent: curl/7.76.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Content-Length: 29
< Content-Type: text/plain; charset=utf-8
< Date: Wed, 26 May 2021 20:37:36 GMT
< Location: ./login
< Server: Caddy
< Vary: Accept, Accept-Encoding
<
* Connection #0 to host 192.168.1.42 left intact
Found. Redirecting to ./login
~
$ curl -v "http://192.168.1.42:8082"
* Trying 192.168.1.42:8082...
* Connected to 192.168.1.42 (192.168.1.42) port 8082 (#0)
> GET / HTTP/1.1
> Host: 192.168.1.42:8082
> User-Agent: curl/7.76.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 400 Bad Request
<
Client sent an HTTP request to an HTTPS server.
* Closing connection 0
$ curl -v "https://192.168.1.42:8082"
* Trying 192.168.1.42:8082...
* Connected to 192.168.1.42 (192.168.1.42) port 8082 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
Also, I need 8081 to stay on http and 8082 to upgrade to https (if the request is http). Does this config do that?
Update -
Apparently for the user instance, the data folder ~/.local/share/caddy was owned by root. Must have been when I ran caddy with superuser privileges without changing XDG_DATA_HOME. So instead of taking /var/lib/caddy, it took ~/.local/share/caddy and so the certificates could not be accessed.
I’ve since changed the owner back to the non-root user. Here is the Caddyfile I’m using.
$ curl -v "http://localhost:8081"
* Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
> GET / HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.76.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Content-Length: 29
< Content-Type: text/plain; charset=utf-8
< Date: Thu, 27 May 2021 16:39:31 GMT
< Location: ./login
< Server: Caddy
< Vary: Accept, Accept-Encoding
<
* Connection #0 to host localhost left intact
Found. Redirecting to ./login
$ curl -v "https://localhost:8081"
* Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* error:1408F10B:SSL routines:ssl3_get_record:wrong version number
* Closing connection 0
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number
And caddy’s log -
$ caddy run
2021/05/27 16:39:16.828 INFO using adjacent Caddyfile
2021/05/27 16:39:16.830 INFO admin admin endpoint started {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["127.0.0.1:2019", "localhost:2019", "[::1]:2019"]}
2021/05/27 16:39:16.830 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc000352e70"}
2021/05/27 16:39:16.831 INFO autosaved config {"file": "/home/user/.local/share/caddy/autosave.json"}
2021/05/27 16:39:16.831 INFO serving initial configuration
2021/05/27 16:39:16.831 INFO tls cleaned up storage units
Isn’t on-demand tls supposed to redirect http to https here?
Yes, if a request comes on the HTTP port, it will respond with a redirect to the HTTPS port. An HTTP request to the HTTPS port is a bad request (wrong type of data on the wire).
A redirect is an HTTP response which contains the Location: header telling the client to try again with a different URL.
An HTTPS server cannot respond to HTTP requests.
This is all simplified if you use ports 80 and 443 because the browser assumes those port numbers automatically when you type http:// and https:// in the browser.
Like I said, if you run Caddy as a service, you can run Caddy as a non-root user, with permission to bind to ports 80 and 443.
I do run it as a service for the actual server,I’m just seeing what all can be done as a non-root user.
So one last thing.
With on-demand tls, when a https request is sent, I’m getting an error in the log.
2021/05/27 18:26:57.599 INFO using adjacent Caddyfile
2021/05/27 18:26:57.601 INFO admin admin endpoint started {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["[::1]:2019", "127.0.0.1:2019", "localhost:2019"]}
2021/05/27 18:26:57.601 INFO http server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 8082}
2021/05/27 18:26:57.601 INFO http enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2021/05/27 18:26:57.601 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc00034f3b0"}
2021/05/27 18:26:57.601 INFO http enabling automatic TLS certificate management {"domains": ["localhost"]}
2021/05/27 18:26:57.601 INFO autosaved config {"file": "/home/user/.local/share/caddy/autosave.json"}
2021/05/27 18:26:57.601 INFO serving initial configuration
2021/05/27 18:26:57.602 INFO tls cleaned up storage units
2021/05/27 18:26:57.608 INFO tls.on_demand obtaining new certificate {"server_name": "localhost"}
2021/05/27 18:26:57.608 INFO tls.obtain acquiring lock {"identifier": "localhost"}
2021/05/27 18:26:57.609 INFO tls.obtain lock acquired {"identifier": "localhost"}
2021/05/27 18:26:57.616 ERROR tls.obtain will retry {"error": "[localhost] Obtain: subject does not qualify for a public certificate: localhost", "attempt": 1, "retrying_in": 60, "elapsed": 0.007231348, "max_duration": 2592000}
Yeah, but to start/enable the service you have to be root eh?
Can you look at the above question too (edited reply)?
Error says localhost doesn’t qualify for a public certificate. So isn’t it supposed to get a local CA signed one instead? I’ve already made the system trust the root certificate, so I thought it was supposed to work.
If you’re using systemd, then yes, systemd runs as root. But I don’t see the concern here.
You need to also enable the internal issuer by specifying tls internal, otherwise it will always try to use the public issuers (Let’s Encrypt/ZeroSSL).