Reverse Proxy for macvlan on Intranet

I have an internal network as follows:
Internet -> Gateway (VPN, public-facing IP) -> Server (192.168.2.1)

I also have a handful of Docker containers running on the server, each with their own macvlan IP address (ex: 192.168.2.9). I’m trying to understand how Caddy might be used as a reverse proxy to permit self-signed SSL for these containers without needing a domain name since this is all internal. So the goal is to enter an IP, and have the connection to the corresponding container be over HTTPS.

My current setup is as follows:

1. Caddy version (caddy version):

2.2.1

2. How I run Caddy:

Running in Docker on a Synology NAS (unix).
Caddy docker-compose

 version: '3'
services:
  caddy:
    image: caddy:latest
    volumes:
      - /volume1/docker/caddy/caddyfile:/etc/caddy/caddyfile
      - /volume1/docker/caddy/data:/data
      - /volume1/docker/caddy/config:/config
    ports:
      - 9999:9999

Caddyfile:

{
        default_sni 192.168.2.9
}

https://192.168.2.9:443  {
        reverse_proxy bitwarden:80
}

Docker container we want to secure (bitwarden):

    version: '3'
    
    services:
      bitwarden:
        image: bitwardenrs/server
        container_name: bitwarden
        restart: unless-stopped
        volumes:
          - /volume1/docker/bitwarden:/data
        environment:
          WEBSOCKET_ENABLED: 'true' # Required to use websockets
          SIGNUPS_ALLOWED: 'true'   # set to false to disable signups
        networks:
          macvlan_private:
            ipv4_address: 192.168.2.9
        hostname: bitwarden
    
    networks:
      macvlan_private:
        external: true

However it looks like Caddy isn’t receiving the requests. What is wrong with the above configuration?

I don’t know much about macvlan, but don’t you need to publish port 443 in your docker-compose config? Caddy won’t be reachable from outside, otherwise (in a typical bridge network scenario at least, I don’t know how macvlan may change that).

To use HTTPS, you’ll need to enable local certificate management:

For this you’ll want to turn on the local_certs global option

And your browser will complain about trust until you extract the root CA cert generated by Caddy’s local CA. You’ll find that in /volume1/docker/caddy/data/pki/authorities/local

This is the default for IP addresses and localhost addresses, so it’s already enabled automatically with the above config.

1 Like

From @matt, I didn’t see the need to explicitly define that.
@francislavoie, do you meant to specify the 443 port for Caddy, or for the other container (in this case Bitwarden) - or both?
My understanding is that it would be redundant as it should just be -p 443:443 since it has it’s own IP.

I don’t see anything here that would imply the Caddy container has its own IP. Are you sure you did that?

What are you seeing in your Caddy logs?

@francislavoie, I changed port 9999:9999 to be 9999:443 on Caddy.
There are no errors, but if I go to 192.168.2.9 (Bitwarden’s IP), it is over HTTP (not secure), and going to the host IP:9999 simply times out.

The log from Caddy is:

{"level":"info","ts":1610407001.6639998,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"info","ts":1610407001.6655533,"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":1610407001.665714,"logger":"http","msg":"server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server","server_name":"srv0","http_port":80}

Add the debug global option to your Caddyfile, it might reveal some more details.

I’ve updated my config as follows:

Pi-Hole local DNS record: bit.local pointing to 192.168.2.10

docker-compose:

version: '3'
services:
  caddy:
    image: caddy:latest
    volumes:
      - /volume1/docker/caddy/caddyfile:/etc/caddy/caddyfile
      - /volume1/docker/caddy/data:/data
      - /volume1/docker/caddy/config:/config
    ports:
      - "443:443"
      - "80:80"
    networks:
      macvlan_private:
        ipv4_address: 192.168.2.10
      
networks:
  macvlan_private:
    external: true

Caddyfile

bit.local {
	reverse_proxy 192.168.2.9:80
}

Entering bit.local in my browser, I get sent to the “Caddy Works” page, instead of the other docker container page.

Log:

2021-01-16T16:10:56.015173344Z {"level":"info","ts":1610813456.0149882,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
2021-01-16T16:10:56.016934666Z {"level":"info","ts":1610813456.0167713,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["127.0.0.1:2019","localhost:2019","[::1]:2019"]}
2021-01-16T16:10:56.017134264Z {"level":"info","ts":1610813456.0169802,"logger":"http","msg":"server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server","server_name":"srv0","http_port":80}
2021-01-16T16:10:56.017273699Z {"level":"info","ts":1610813456.0170085,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00036f960"}
2021-01-16T16:10:56.017500413Z {"level":"info","ts":1610813456.0174103,"logger":"tls","msg":"cleaned up storage units"}
2021-01-16T16:10:56.017556493Z {"level":"info","ts":1610813456.0174694,"msg":"autosaved config","file":"/config/caddy/autosave.json"}
2021-01-16T16:10:56.017600321Z {"level":"info","ts":1610813456.0174809,"msg":"serving initial configuration"}

Any ideas?

The Caddyfile has an uppercase C. Linux is a case sensitive filesystem.