Padlock not appearing (not secure) for reverse proxy to another machine

1. Caddy version (caddy version):

v2.2.1 h1:Q62GWHMtztnvyRU+KPOpw6fNfeCD3SkwH7SfT1Tgt2c=

2. How I run Caddy:

Custom built docker image with following Dockerfile:

FROM caddy:builder AS builder

RUN xcaddy build \
    --with github.com/caddy-dns/cloudflare

FROM caddy:latest

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

a. System environment:

Raspberry Pi 3 with Docker.

b. Command:

docker-compose -f caddycloudflare/docker-compose.yml up -d

c. Service/unit/compose file:

version: "3.8"
services:
  caddy:
    image: caddy_cloudflare:1.0
    container_name: caddy_cloudflare
    hostname: caddy_cloudflare
    env_file: 
      - ../.env
      - ./secret.env
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./data:/data
      - ./config:/config

networks:
  default:
    external:
      name: $NETWORK

d. My complete Caddyfile or JSON config:

# External
portainer.{$DOMAIN} {
    reverse_proxy {$IP_PORTAINER}:9000
}

home.{$DOMAIN} {
    reverse_proxy {$IP_HOMEASSISTANT}:8123
}


# Internal
*.lan.{$DOMAIN} {
    tls MyEMAIL@gmail.com { 
        dns cloudflare {$CLOUDFLARE_API_TOKEN}
    }

	@unifi host unifi.lan.{$DOMAIN}
	handle @unifi {
        reverse_proxy {$IP_UNIFI}:8443
    }

	@home host home.lan.{$DOMAIN}
	handle @home {
        reverse_proxy {$IP_HOMEASSISTANT}:8123
	}

	@portainer host portainer.lan.{$DOMAIN}
	handle @portainer {
        reverse_proxy {$IP_PORTAINER}:9000
	}

	# For anything else, falls through to this:
	handle {
        respond "404 bruh." 404 {
            close
        }
	}
}

3. The problem I’m having:

SSL works great for home. and portainer. services and I see the padlock and the *.lan.mydomain.com cert when i click the padlock to inspect it, Both of those services actually run on the exact same machine as the docker container running caddy which is 192.168.1.100 so the reverse proxy is effectively routing to itself. I’m not sure if this matters or not considering the other services are running in docker containers that wouldn’t have the certificates installed into them (unless docker does this automatically by migrating the certs out of the caddy container?).

For unifi.lan.mydomain.com, the reverse proxy sends it to IP_UNIFI which is 192.168.1.1 and gives it the port for the service for the Unifi controller on my Unifi Dream Machine router/gateway.

When i navigate to unifi.lan.mydomain.com caddy successfully proxies me over to the correct IP address and i see the router login page, but I am noticing that it has no padlock and. says “Not Secure”.

I have noticed something a little odd. When i navigate to home.lan.mydomain.com in my browser the URL stays as that and i see the cert for *.lan.mydomain.com. You can see an image here:

Notice the URL has not changed, aside from having stuff tacked onto it by Home Assistant it stays as home.lan.mydomain.com.

But when i navigate to unifi.lan.mydomain.com the URL changes to the IP that caddy is sending it to (`192.168.1.1). See image here:

I am wondering if the self-signed certificate on the Unifi Dream Machine device is causing a conflict, but I don’t quite understand why this wouldn’t be the case with HomeAssistant or Portainer which are both in their own isolated docker containers.

4. Error messages and/or full log output:

None, per se.

5. What I already tried:

I tried adding a transport block to the reverse proxy directive

        reverse_proxy https://{$IP_UNIFI}:8443{
            transport http {
                tls
            }
        }

and adding https:// in from of {$IP_UNIFI} but the same thing results.

6. Links to relevant resources:

But when i navigate to unifi.lan.mydomain.com the URL changes to the IP that caddy is sending it to (`192.168.1.1).

It’s probably being redirected by the backend, i.e. the unifi app. Apparently it only wants to be accessed at that IP address. You’ll have to either reconfigure the backend to be less picky, or configure Caddy to trick the app into being served at that IP address.

Gotcha,

When i open up the developer tools and watch the network tab when i navigate to unifi.lan.mydomain.com i see

Status Code: 301 Moved Permanently
Remote Address: 192.168.1.1:80

which i assume is a redirect. So you’re probably right. I don’t think changing the back-end is feasible (or desirable imo) since i’d be digging into the weeds of the controller software on the router; and i hardly know what i’m doing as it is.

configure Caddy to trick the app into being served at that IP address.

I’m not sure how i would do this, is there any caddy configuration that would do this? This seems beyond caddy’s sphere of control.

If it’s not possible that’s okay, I was just wondering if I was somehow doing something fundamentally wrong in my Caddyfile.

Set the Host header going upstream to that of the IP address.

Sorry, i’m not a web guy. Can you explain that a bit slower?

Are you saying in the Caddyfile i should add something like this?

request_header Host {$IP_UNIFI}

inside the. handler block for @unifi?

Sorry, you have to bare with me as I really don’t understand this stuff.

EDIT:

nevermind, i found this example
header_up Host {http.reverse_proxy.upstream.hostport} nicely given in the reverse_proxy directive docs. Let me fiddle with it for a sec. Btw the docs are very good.

Unfortunately

	handle @unifi {
        reverse_proxy {$IP_UNIFI}:8443 {
            header_up Host {$IP_UNIFI}
        }
    }

Doesn’t help, still same issue with it not being secure.

Okay, so i’m a big dumb-dumb. My DNS server was routing unifi.lan.mydomain.com straight to 192.168.1.1 (the router) instead of 192.168.1.100 (the caddy server).

I changed it and now it’s at least seemingly doing the right thing, but unfortunately I can’t route directly to the service port 8443 because i get a page that says:

Bad Request
This combination of host and port requires TLS.```

Which doesn’t seem right to be because i should have TLS through my *.lan wildcard cert.

I GOT IT!!!

I cobbled some pieces from the ubiquiti forums and put together this all works! It uses my *.lan widlcard cert and takes me to the right place!!!

I have no idea why this works, unfortunately lol.

	@unifi host unifi.lan.{$DOMAIN}
	handle @unifi {
        reverse_proxy {$IP_UNIFI}:8443 {
            header_up -Referer
            header_down -Referer
            transport http {
                tls_insecure_skip_verify
            }
        }
    }
1 Like

CADDY F***ING RULES!!!

2 Likes

Nice work. You’re pretty clever to have figured that out! We like you, stick around.

1 Like

Unfortunately, I just kinda just mashed stuff together I found on old ubiquiti and caddy threads!

If someone could explain exactly what this does, i’d sure appreciate it.

            header_up -Referer
            header_down -Referer
            transport http {
                tls_insecure_skip_verify
            }

From googling around it’s pretty obvious that the first two simply remove the Referer fields in the header and the referer simply tells the site how the user got there; I didn’t think these ought to have any real effect on the certificate resolution. I removed them and it had no negative effect (padlock still there with my *.lan cert).

What I don’t quite understand is tls_insecure_skip_verify. From reading the docs it seems like it’s used to “override verification of the backend TLS certificate, essentially disabling security features over HTTPS.”

So why is a padlock being shown if i’m basically telling the proxy “hey, don’t worry about tls”? Is it a “fake” padlock?

The “padlock” is basically just the browser saying it trusts Caddy, i.e. the thing it’s connecting to. It has no knowledge of the proxy, i.e. the connection from Caddy to Ubiquiti. That’s kinda the point of the proxy :stuck_out_tongue:

tls_insecure_skip_verify is because Ubiquiti is using a self-signed cert or something to that effect, i.e. a certificate that is not issued by a certificate authority that the environment Caddy is running in can trust. You could add Ubiquiti’s cert to the trust store of the machine Caddy’s running on, or use the tls_trusted_ca_certs option to have Caddy explicitly trust it, but it’s a bit tedious to do and possibly maintain, depending on how often the certificate from Ubiquiti is renewed.

I’m not sure what’s going on with Referer, but I figure Ubiquiti makes use of that header, which the browser fills in, to trigger the redirects, and omitting the header both ways might get around that problem… or something. :man_shrugging:

1 Like

I see, you’re right about Ubiquiti using a self signed cert; it’s stored on the router hosting the management application. I see, so with tls_insecure_skip_verify i’m telling caddy that this website (which has a self-signed cert) is okay to trust (or rather, telling it to ignore the concept of trust here). And my browser already trusts caddy because of the dns challenge wildcard cert.

Thanks so much for the explanation!

1 Like

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