Reverse proxy to docker daemon api: "Client sent an HTTP request to an HTTPS server"

1. The problem I’m having:

trying to use caddy on a vm host server as a reverse proxy to an insecure docker daemon on a vm using url rewrite, but i’m getting “Client sent an HTTP request to an HTTPS server” when i run docker commands.

my host server is named heart and the vm is named aorta

the caddy site (heart.home.lan:2376) is configured to use internal tls and is configured to proxy traffic to the vm via the vm’s hostname and insecure daemon port (aorta:2375).

i’m using handle_path in my caddyfile because i want my requests to the daemon to be path’d so i can run multiple reverse proxies to multiple daemons. i.e. i plan to also launch a vm named vena-cava. so, my daemon urls would work like this:

  • heart.home.lan:2376/aorta/docker → aorta:2375
  • heart.home.lan:2376/vena-cava/docker → vena-cava:2375

note, i can successfully run docker commands against the vm, directly:

> .\docker.exe -H aorta:2375 info
Client:
 Version:    24.0.2
 Context:    default
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 24.0.5
 Storage Driver: windowsfilter
  Windows:
 Logging Driver: json-file
 Plugins:
  Volume: local
  Network: ics internal l2bridge l2tunnel nat null overlay private transparent
  Log: awslogs etwlogs fluentd gcplogs gelf json-file local logentries splunk syslog
 Swarm: inactive
 Default Isolation: process
 Kernel Version: 10.0 20348 (20348.859.amd64fre.fe_release_svc_prod2.220707-1832)
 Operating System: Microsoft Windows Server Version 21H2 (OS Build 20348.1850)
 OSType: windows
 Architecture: x86_64
 CPUs: 12
 Total Memory: 950.9MiB
 Name: aorta
 ID: d8a521ff-96c1-4746-b02f-3f20dc1b57c6
 Docker Root Dir: C:\ProgramData\Docker\data-root
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine

WARNING: API is accessible on http://172.16.0.253:2375 without encryption.
         Access to the remote API is equivalent to root access on the host. Refer
         to the 'Docker daemon attack surface' section in the documentation for
         more information: https://docs.docker.com/go/attack-surface/

2. Error messages and/or full log output:

> .\docker.exe -H heart.home.lan:2376/aorta/docker info
Client:
 Version:    24.0.2
 Context:    default
 Debug Mode: false

Server:
ERROR: Error response from daemon: Client sent an HTTP request to an HTTPS server.
errors pretty printing info

3. Caddy version:

> caddy.exe version
v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

4. How I installed and ran Caddy:

a. System environment:

windows server core 2022
direct install (not installed in a container or vm)

b. Command:

i run caddy as a windows service with this command:

"D:\Program Files\Caddy\caddy.exe" run --adapter caddyfile --config "D:\ProgramData\Caddy\Caddyfile"

c. Service/unit/compose file:

> sc.exe qc caddy
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: caddy
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : "D:\Program Files\Caddy\caddy.exe" run --adapter caddyfile --config "D:\ProgramData\Caddy\Caddyfile"
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : caddy
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem

d. My complete Caddy config:

{
    admin off
    log {
        format json {
            time_format iso8601
        }
        output file "D:\ProgramData\Caddy\caddy.log" {
            roll_uncompressed
        }
    }
    storage file_system "D:\ProgramData\Caddy"
}

heart.home.lan {
    log
    respond "Hello, world!"
    tls internal
}

heart.home.lan:2376 {
    log
    handle_path /aorta/docker {
        reverse_proxy http://aorta:2375
    }
    tls internal
}

5. Links to relevant resources:

You probably need to specify https:// ?

I don’t know anything about Docker’s -H flag, I’ve never used it.

I don’t know anything about the Docker API, but please read The "subfolder problem", OR, "why can't I reverse proxy my app into a subfolder?", you may have an easier time by using subdomains instead of subpaths for each, to avoid messing around with URLs.

Also you only used /aorta/docker as your path matcher, which will only match exactly that path and nothing else, so you might need to add a * as a suffix to match paths below that.

-H doesn’t accept https on the hostname, just a socket type (e.g. tcp:// or npipe://, etc.). however, your suggestion made me realize i need to explicitly tell docker to use tls via --tls --tlscacert ... like this:

.\docker.exe -H heart.home.lan:2376/aorta/docker --tls --tlscacert C:\Users\Administrator\heart.home.lan.crt info

where heart.home.lan.crt is the cert chain caddy generated for the site.

1 Like

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