Authentik and Caddy

1. Output of caddy version:

2.6.1

2. How I run Caddy:

docker container with docker compose

a. System environment:

Ubuntu Server w/ Docker 20.10.18

b. Command:

docker compose up -d

c. Service/unit/compose file:

services:
caddy:
container_name: caddy
build:
context: ./
dockerfile: Dockerfile
networks:
- caddy-net
ports:
- 80:80
- 443:443
environment:
LOG_FILE: ~/server/logs/caddy/access.log
DOMAIN: jlr.lol
EMAIL: emailredacted@zoho.com
DUCKDNS_API_TOKEN: ${DUCKDNS_TOKEN}
BOUNCER_CADDY_TOKEN: 0740e7d77e70f43e8ce143e27dd2718b
PORT_HTPC_HTTP: ${PORT_HTPC_HTTP}
PORT_HTPC_REQUESTS: ${PORT_HTPC_REQUESTS}
PORT_UPKUMA: ${PORT_UPKUMA}
labels:
- "diun.enable=true"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro # Required. Needs to be an extension-less file NOT a directory
- ~/server/config/caddy:/data # Optional, house for certs. Caddy adds its own /caddy/ directory
- ~/server/config/caddy:/config # Optional, JSON Config files. Caddy adds its own /caddy/ directory
- ~/server/logs/caddy:/server/logs/caddy
- ~/docker/caddy/users.json:/etc/caddy/auth/local/users.json #auth db
healthcheck:
test: ["CMD", "caddy", "version"]
restart: unless-stopped
networks:
caddy-net:
name: caddy-net
external: true

d. My complete Caddy config:

{ # Global options block. Entirely optional, https is on by default
email redactedemail@zoho.com # Optional email key for lets encrypt
debug # this is optional; makes Caddy log more details
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
order crowdsec first # this ensures that the CrowdSec module is executed before any other HTTP handlers
crowdsec {
api_url http://crowdsec:8080/ # the URL where your CrowdSec LAPI can be reached. Caddy connects directly, so use the default port 8080
api_key 0740e7d77e70f43e8ce143e27dd2718b # the secret API key for the bouncer to authenticate against LAPI
}
auth.jlr.lol {
header {
server #anonymizes Caddy
# disable FLoC tracking
Permissions-Policy interest-cohort=()
# enable HSTS
Strict-Transport-Security max-age=31536000;
# disable clients from sniffing the media type
X-Content-Type-Options nosniff
# clickjacking protection
X-Frame-Options DENY
# keep referrer data off of HTTP connections
Referrer-Policy no-referrer-when-downgrade
}
encode zstd gzip
crowdsec
reverse_proxy https://authentik_server_1:9443
log {
level ERROR
output file {$LOG_FILE} {
roll_size 3MiB
roll_keep 5
roll_keep_for 24h
format json                                                                                                                                                                                                                              }
}
www.jlr.lol {
redir jlr.lol
}

3. The problem I’m having:

4. Error messages and/or full log output:

Curl Output:

curl: (60) SSL certificate problem: self-signed certificate                                                                                                                                                                                More details here: https://curl.se/docs/sslcerts.html                                                                                                                                                                                                                                                                                                                                                                                                                                 curl failed to verify the legitimacy of the server and therefore could not                                                                                                                                                                 establish a secure connection to it. To learn more about this situation and                                                                                                                                                                how to fix it, please visit the web page mentioned above.

Logs:

{"level":"error","ts":1665548013.0090258,"logger":"http.log.error.log3","msg":"x509: certificate signed by unknown authority","request":{"remote_ip":"73.254.98.51","remote_port":"10113","proto":"HTTP/2.0","method":"GET","host":"auth.jlr.lol","uri":"/","headers":{"Sec-Ch-Ua-Platform":["\"Windows\""],"Upgrade-Insecure-Requests":["1"],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.37"],"Sec-Fetch-User":["?1"],"Accept-Language":["en-US,en;q=0.9"],"Sec-Ch-Ua":["\"Chromium\";v=\"106\", \"Microsoft Edge\";v=\"106\", \"Not;A=Brand\";v=\"99\""],"Sec-Ch-Ua-Mobile":["?0"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Site":["none"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-Dest":["document"],"Accept-Encoding":["gzip, deflate, br"],"Cache-Control":["max-age=0"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"auth.jlr.lol"}},"duration":0.043758474,"status":502,"err_id":"qibtyttsz","err_trace":"reverseproxy.statusError (reverseproxy.go:1271)"}

5. What I already tried:

No one seems to use Caddy and Authentik for examples online so I couldn’t find many examples linking the two.

6. Links to relevant resources:

Certificates | authentik (goauthentik.io)

Reverse-proxy | authentik (goauthentik.io)

Please run caddy fmt to indent your config. It’s extremely difficult to read your config without tabulation.

This means that Caddy doesn’t trust the certificate used by your Authentik server.

Since it’s running on the same server, just use HTTP instead of HTTPS to connect to it. There’s no benefit here to proxy over HTTPS, since the traffic all happens on your own machine.

1 Like

How can I format the caddyfile when I’m running it in a docker container? docker exec doesn’t seem to work unless I’m being dumb. Also are you saying to set the auth subdomain to point to the 9000 port (the http port default for authentik)?

docker-compose exec caddy caddy fmt --overwrite /etc/caddy/Caddyfile

Although you mounted it as :ro so it won’t be able to manipulate the config. In which case, remove --overwrite and just copy the output and replace it with your editor.

Also, it seems like you pasted your yaml config without indentation… which doesn’t make sense because the indentation is required in yaml.

yeah, i copy pasted it from nano but it un-indented in the code editor on discourse, and then added spaces instead of new-lines which i had to manually edit, i promise i have normal indentation in my config lmao

What terminal are you using? If you’re on Windows, I strongly recommend installing Windows Terminal which doesn’t have this problem (whereas Command Prompt does)

1 Like

I’m using Authentik with a Caddy reverse proxy.
My config for this is really simple:

authentik.example.com {
        reverse_proxy http://server:9000 {
                header_down Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"
                header_up X-Real-IP {remote_host}
        }

        log {
                output discard
        }
}

i use the http port of Authentik (default 9000) and “server” is the Contaner name of Authentik. No need for logs for me.

1 Like

What’s your config for outposts?

I just use the embedded outpost, no additional one.

What’s your entire config look like including apps then? Struggling to wrap my head around apps vs outposts.

My apps use Authentik direct (via OpenID Connect), not via Proxy or LDAP.
For example Portainer has a OIDC configuration option, see https://goauthentik.io/integrations/services/portainer/
I’m using the URLs from the main Authentik installation and the Portainer application & provider there.
Outposts are needed if you want to use LDAP or you want to have an additional Proxy outpost (the embedded one has also the proxy mode enabled), but i haven’t used it.
If you want to use forward auth with Authentik and Caddy, see https://goauthentik.io/docs/providers/proxy/forward_auth#caddy

I have an uptime-kuma instance so I need to use a proxy outpost unfortunately. I’m tryna use the embedded one with this config:

status.jlr.lol {
  header {
    -server #anonymizes Caddy

    # disable FLoC tracking
    Permissions-Policy interest-cohort=()

    #enable HSTS
    Strict-Transport-Security max-age=31536000;

    # disable clients from sniffing the media type
    ?X-Content-Type-Options nosniff

    # clickjacking protection
    ?X-Frame-Options DENY

    # keep referrer data off of HTTP connections
    ?Referrer-Policy no-referrer-when-downgrade
  }

  encode zstd gzip

  crowdsec

  # always forward outpost path to actual outpost
  reverse_proxy /outpost.goauthentik.io/* http://auth.jlr.lol

  # forward authentication to outpost
  forward_auth http://auth.jlr.lol {
    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->

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

  reverse_proxy uptime-kuma:3001
}

However, I keep getting too many redirects now.

Are you expecting this to run before forward_auth? Because that might be the problem.

Caddy sorts directives according to this directive order which puts forward_auth above reverse_proxy.

So if you need to have your outpost proxy run first, you can wrap the whole thing (both proxies & forward auth) inside a route to override the order.

i set up a Uptime Kuma instance just now. if you want to use forward auth as in your caddy config, you have to configure the Authentik Uptime Kuma provider as a proxy provider with “Forward auth (single apllication)” mode, not “Proxy” and the external URL as in Caddy (in your case https://status.jlr.lol)
My working Caddyfile config for Uptike Kuma:


status.kumbi.info {
        reverse_proxy /outpost.goauthentik.io/* http://server:9000
        forward_auth http://server:9000 {
                uri /outpost.goauthentik.io/auth/caddy
                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-Out
post 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 http://uptime-kuma:3001 {
                header_down Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"
                header_up X-Real-IP {remote_host}
        }

        log {
                output discard
        }
}

uptime-kumi is the name of the Uptime Kuma container, as is server the name of the Authentik container, both in the same docker network as Caddy.

1 Like

With Chrome this is working, with Firefox it’s downloading a blank “caddy” file, is there any difference in link handling or something between the two that causes this? Adding an trailing slash to the end makes the link unknown. For now though, it seems to literally be a browser diff as I tried both configs and they work. I guess I was lucky that I can’t be arsed to use the same browser at work, at school, and at home?

Works for me with Chromium based Browsers (Edge, Vivaldi), Firefox, Safari.

I had incorrect content cached, so redirects didn’t refresh even after ctrl+shift+r. Thanks all.

1 Like

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