Simplify repetitive caddyfile

1. The problem I’m having:

I am using caddy on macos with tailscale and several self hosted apps. My setup is working fine but my caddyfile is very repetitive. I include full background below but it may not be relevant. My exact situation is complex but I am mostly looking for some documentation anyone can point me to on whether caddyfiles can define policies centrally and refer to them as needed.

I want each app to be available in 2 ways:

  1. Through my tailscale url and that app’s port number eg https://machinename.tailnetname.ts.net:1234
  2. Through an app-specific subdomain of my personal domain https://appname.example.com

I also want to use forward auth with Authentik for each app. I set up Authentik on ports 9001/9444 and reverse proxy with

# Authentik
machinename.tailnetname.ts.net:9001 {
    reverse_proxy :9000
}
machinename.tailnetname.ts.net:9444 {
    reverse_proxy :9443
}

I also want each app to have https. For the tailscale url (ending ts.net), caddy gets the certs from tailscale automatically but for my personal domain (example.com) I need to use a dns plugin as the tailscale 100.x IP address the domain points to is not publicly routable.

As tailscale is listening on port 443 I cannot bind to it and I configured tailscale to forward to 444 instead, which is where my caddy listens below.

For each app I have the following in my caddyfile (this particular app is natively on port 3000 of the machine and is named ‘app’ and so should be available at https://machinename.tailnetname.ts.net:3000 and https://app.example.com ):

machinename.tailnetname.ts.net:3000 {
    # always forward outpost path to actual outpost
    reverse_proxy /outpost.goauthentik.io/* https://machinename.tailnetname.ts.net:9001

    # forward authentication to outpost
    forward_auth https://machinename.tailnetname.ts.net:9001 {
        uri /outpost.goauthentik.io/auth/caddy

        # capitalization of the headers is important, otherwise they will be empty
        copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version

        # optional, in this config trust all private ranges, should probably be set to the outposts IP
        trusted_proxies private_ranges
    }

    reverse_proxy :3000
}
app.example.com:444 {
    # always forward outpost path to actual outpost
    reverse_proxy /outpost.goauthentik.io/* https://machinename.tailnetname.ts.net:9001

    # forward authentication to outpost
    forward_auth https://machinename.tailnetname.ts.net:9001 {
        uri /outpost.goauthentik.io/auth/caddy

        # capitalization of the headers is important, otherwise they will be empty
        copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version

        # optional, in this config trust all private ranges, should probably be set to the outposts IP
        trusted_proxies private_ranges
    }

    tls {
        dns route53 {
            access_key_id "..."
            secret_access_key "..."
        }
    }

    reverse_proxy :3000
}

This is very repetitive as I need to repeat the entire block, forward auth and all, as I have 2 different tls methods for the 2 hostnames. I then need to repeat the entire thing for each app.

Is there any way to define tls and forward_auth policies in one place and refer to them as needed?

Thank you.

2. Error messages and/or full log output:

n/a - everything is working fine

3. Caddy version:

4. How I installed and ran Caddy:

a. System environment:

macos, caddy v2.6.4 installed using xcaddy with route53 module. Tailscale.

b. Command:

caddy

c. Service/unit/compose file:

see above

d. My complete Caddy config:

see above

5. Links to relevant resources:

I think you’re looking for snippets:

If your site configs are extremely similar, that might look something like this:

(auth) {
    # always forward outpost path to actual outpost
    reverse_proxy /outpost.goauthentik.io/* https://{args.0}.tailnetname.ts.net:9001

    # forward authentication to outpost
    forward_auth https://{args.0}.tailnetname.ts.net:9001 {
        uri /outpost.goauthentik.io/auth/caddy

        # capitalization of the headers is important, otherwise they will be empty
        copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version

        # optional, in this config trust all private ranges, should probably be set to the outposts IP
        trusted_proxies private_ranges
    }
}

(site) {
    {args.0}.tailnetname.ts.net:{args.1} {
        import auth {args.0}

        reverse_proxy :3000
    }
    {args.2} {
        import auth {args.0}

        tls {
            dns route53 {
                access_key_id "..."
                secret_access_key "..."
            }
        }

        reverse_proxy :3000
    }
}

And then you can define each site as

import site machinename 3000 app.example.com:444

If your sites need some customization but do have common parts, you can define just the common parts of each server config as snippets (like the (auth) above) and still write full server blocks for each site that just have import common_bit optional_parameter sprinkled in them.

2 Likes

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