Automatic https with dynamic reverse_proxy

1. Caddy version (caddy version):

v2.4.5

2. How I run Caddy:

Caddy on a Digital Ocean instance.

a. System environment:

Linux caddy 4.15.0-156-generic #163-Ubuntu SMP Thu Aug 19 23:31:58 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

b. Command:

sudo systemctl start caddy

c. Service/unit/compose file:

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile or JSON config:

# The Caddyfile is an easy way to configure your Caddy web server.
#
# Unless the file starts with a global options block, the first
# uncommented line is always the address of your site.
#
# To use your own domain name (with automatic HTTPS), first make
# sure your domain's A/AAAA DNS records are properly pointed to
# this machine's public IP, then replace ":80" below with your
# domain name.

{
    on_demand_tls {
        ask      http://localhost:5555
        interval 2m
        burst    5
    }
}

https:// {
  tls {
    on_demand
  }

  reverse_proxy https://example.com {
    header_up Host {upstream_hostport}
    header_up X-Forwarded-Host {host}
  }
}

# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile

3. The problem I’m having:

I want to have a way to dynamically reverse proxy to a domain with a variable component. E.g.

https:// {
  tls {
    on_demand
  }

  reverse_proxy https://example.com/*username*
}

Where username is the variable component. Without needing to update the Caddyfile and restart the service for each user that points their domain to our app.

We want to allow users of our app to add custom domains to their publicly available app url. Currently they are only pointed to the main application. I am really not sure if this is even possible without explicitly updating the Caddyfile for each user. My initial thoughts are:

  • The ask server’s response can include data which is accessible in a variable in the Caddyfile, since this server needs to read db info anyway it can include some metadata that will allow to be appended to the reverse_proxy uri and make it dynamic.

  • We don’t want to require the users to have a specific URI structure when they point their domain to us.

4. Error messages and/or full log output:

Null

5. What I already tried:

I only set up the basic reverse proxy to the main app uri with automatic https, and deployed a small Nodejs server to handle the ask operation on an internal port. This functionality works as expected.

6. Links to relevant resources:

Since you’re passing this header through already, your backend should do that work during its routing step.

Set up some middleware that reads from the request headers, if X-Forwarded-Host is there then you can adjust the routing in your app.

The ask endpoint is only called when Caddy needs to know if it needs to issue a certificate, which is not on every request. It’s totally decoupled from request handling.

1 Like

Thanks for the assistance! This is a great suggestion that will require some architectural changes on our side, but yes this is the solution. Thank you!

1 Like

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