1. The problem I’m having:
I have a stack of docker containers, and most of them are in 2 networks Bridge and MacVlan Config. I am using Caddy to reverse proxy some of this dockers.
For example the Sonarr and other *Arr stack , have the option to provide auth for requests outside of the network.
I am also using Authelia , to manage a single place to maintain authentication.
The expected outcome would be that requests proxied by Caddy , to be recognised as coming from the same network, thus not receiving the Arr auth page, and avoiding the double log in. In the same time , I want to leave the basic Arr auth in place, for the usecases that I make some mistakes, and access to those services does not pass through Caddy.
I guess that X-Fowarded-For should be populated with the Caddy ip also ? In fact , i Have no X-Forwarded-For header populated. If my understanding is incorrect I am open to suggestions.
2. Error messages and/or full log output:
{"level":"info","ts":1731581837.1196558,"logger":"http.log.access.log4","msg":"handled request","request":{"remote_ip":"212.54.141.21","remote_port":"57743","client_ip":"212.54.141.21","proto":"HTTP/3.0","method":"GET","host":"sonarr.thnds.ro","uri":"/","headers":{"Sec-Ch-Ua":["\"Chromium\";v=\"130\", \"Brave\";v=\"130\", \"Not?A_Brand\";v=\"99\""],"Upgrade-Insecure-Requests":["1"],"Sec-Fetch-Mode":["navigate"],"Sec-Ch-Ua-Mobile":["?0"],"Accept-Language":["en-GB,en;q=0.6"],"Accept-Encoding":["gzip, deflate, br, zstd"],"Cookie":["REDACTED"],"Priority":["u=0, i"],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8"],"Sec-Gpc":["1"],"Sec-Fetch-Site":["none"],"Sec-Fetch-User":["?1"],"Sec-Fetch-Dest":["document"],"Sec-Ch-Ua-Platform":["\"macOS\""]},"tls":{"resumed":true,"version":772,"cipher_suite":4865,"proto":"h3","server_name":"sonarr.thnds.ro"}},"bytes_read":0,"user_id":"","duration":0.000614253,"size":111,"status":302,"resp_headers":{"Content-Type":["text/html; charset=utf-8"],"Referrer-Policy":["strict-origin-when-cross-origin"],"Date":["Thu, 14 Nov 2024 10:57:16 GMT"],"Location":["https://permis.thnds.ro/?rd=https%3A%2F%2Fsonarr.thnds.ro%2F&rm=GET"],"Set-Cookie":["REDACTED"],"X-Frame-Options":["DENY"],"Content-Length":["111"],"X-Dns-Prefetch-Control":["off"],"Server":["Caddy"],"X-Content-Type-Options":["nosniff"],"Permissions-Policy":["accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), xr-spatial-tracking=(), interest-cohort=()"]}}
Curl example from within the sonarr docker instance
# curl -vL sonarr.thnds.ro
* Host sonarr.thnds.ro:80 was resolved.
* IPv6: (none)
* IPv4: 212.54.141.21
* Trying 212.54.141.21:80...
* Connected to sonarr.thnds.ro (212.54.141.21) port 80
> GET / HTTP/1.1
> Host: sonarr.thnds.ro
> User-Agent: curl/8.9.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://sonarr.thnds.ro/
< Server: Caddy
< Date: Thu, 14 Nov 2024 11:14:12 GMT
< Content-Length: 0
<
* shutting down connection #0
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://sonarr.thnds.ro/'
* Host sonarr.thnds.ro:443 was resolved.
* IPv6: (none)
* IPv4: 212.54.141.21
* Trying 212.54.141.21:443...
* Connected to sonarr.thnds.ro (212.54.141.21) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
* subject: CN=sonarr.thnds.ro
* start date: Nov 12 13:24:31 2024 GMT
* expire date: Feb 10 13:24:30 2025 GMT
* subjectAltName: host "sonarr.thnds.ro" matched cert's "sonarr.thnds.ro"
* issuer: C=US; O=Let's Encrypt; CN=E5
* SSL certificate verify ok.
* Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
* Certificate level 1: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://sonarr.thnds.ro/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: sonarr.thnds.ro]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.9.1]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: sonarr.thnds.ro
> User-Agent: curl/8.9.1
> Accept: */*
>
* Request completely sent off
< HTTP/2 302
< alt-svc: h3=":443"; ma=2592000
< content-type: text/html; charset=utf-8
< date: Thu, 14 Nov 2024 11:14:12 GMT
< location: https://authelia.thnds.ro/?rd=https%3A%2F%2Fsonarr.thnds.ro%2F&rm=GET
< permissions-policy: accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), xr-spatial-tracking=(), interest-cohort=()
< referrer-policy: strict-origin-when-cross-origin
< server: Caddy
< set-cookie: authelia_session=729zMCq9_dituruFqW*52UzWK1tEphM2; expires=Thu, 14 Nov 2024 12:14:13 GMT; domain=thnds.ro; path=/; HttpOnly; secure; SameSite=Lax
< x-content-type-options: nosniff
< x-dns-prefetch-control: off
< x-frame-options: DENY
< content-length: 111
* Ignoring the response-body
<
* Connection #1 to host sonarr.thnds.ro left intact
* Issue another request to this URL: 'https://authelia.thnds.ro/?rd=https%3A%2F%2Fsonarr.thnds.ro%2F&rm=GET'
* Host authelia.thnds.ro:443 was resolved.
* IPv6: (none)
* IPv4: 212.54.141.21
* Trying 212.54.141.21:443...
* Connected to authelia.thnds.ro (212.54.141.21) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
* subject: CN=authelia.thnds.ro
* start date: Nov 11 17:52:43 2024 GMT
* expire date: Feb 9 17:52:42 2025 GMT
* subjectAltName: host "authelia.thnds.ro" matched cert's "authelia.thnds.ro"
* issuer: C=US; O=Let's Encrypt; CN=E5
* SSL certificate verify ok.
* Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
* Certificate level 1: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://authelia.thnds.ro/?rd=https%3A%2F%2Fsonarr.thnds.ro%2F&rm=GET
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: authelia.thnds.ro]
* [HTTP/2] [1] [:path: /?rd=https%3A%2F%2Fsonarr.thnds.ro%2F&rm=GET]
* [HTTP/2] [1] [user-agent: curl/8.9.1]
* [HTTP/2] [1] [accept: */*]
> GET /?rd=https%3A%2F%2Fsonarr.thnds.ro%2F&rm=GET HTTP/2
> Host: authelia.thnds.ro
> User-Agent: curl/8.9.1
> Accept: */*
>
* Request completely sent off
< HTTP/2 200
< alt-svc: h3=":443"; ma=2592000
< content-security-policy: default-src 'self'; frame-src 'none'; object-src 'none'; style-src 'self' 'nonce-4OSzM2V775GThzAbD3nRMPXUOJdeGvMa'; frame-ancestors 'none'; base-uri 'self'
< content-type: text/html; charset=utf-8
< date: Thu, 14 Nov 2024 11:14:12 GMT
< permissions-policy: accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), xr-spatial-tracking=(), interest-cohort=()
< referrer-policy: strict-origin-when-cross-origin
< server: Caddy
< x-content-type-options: nosniff
< x-dns-prefetch-control: off
< x-frame-options: DENY
< content-length: 1064
<
<!DOCTYPE html>
<html lang="en">
<head>
<base href="https://authelia.thnds.ro/" />
<meta property="csp-nonce" content="4OSzM2V775GThzAbD3nRMPXUOJdeGvMa" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Authelia login portal for your apps" />
<link rel="manifest" href="./manifest.json" />
<link rel="icon" href="./favicon.ico" />
<title>Login - Authelia</title>
<script type="module" crossorigin src="./static/js/index.BvAVkNRl.js"></script>
<link rel="stylesheet" crossorigin href="./static/css/index.Bv3M1sZD.css">
</head>
<body
data-basepath=""
data-duoselfenrollment="false"
data-logooverride="false"
data-privacypolicyaccept=""
data-privacypolicyurl=""
data-rememberme="true"
data-resetpassword="true"
data-resetpasswordcustomurl=""
data-theme="light"
>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
* Connection #2 to host authelia.thnds.ro left intact
3. Caddy version:
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
4. How I installed and ran Caddy:
a. System environment:
-
Docker version 20.10.12, build e91ed57
-
Linux tiny 6.8.0-40-generic #40~22.04.3-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 30 17:30:19 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
b. Command:
docker compose up -d
c. Service/unit/compose file:
version: '3'
services:
caddy:
image: caddy:latest
container_name: caddy
hostname: caddy
domainname: caddy
restart: unless-stopped
networks:
Bbackend:
Afrontend:
ipv4_address: 192.168.1.12
volumes:
- /share/dockers/caddy/config:/config
- /share/dockers/caddy/logs:/logs
- /share/dockers/caddy/config/Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
networks:
Bbackend:
external: true
Afrontend:
external: true
volumes:
caddy_data:
external: true
d. My complete Caddy config:
(logging) {
log {
output file /logs/{args[0]}.log {
format json
roll_size 2mb
roll_keep 30
roll_keep_for 720h
}
}
}
(secure) {
forward_auth {args.0} authelia:9141 {
uri /api/verify?rd=https://authelia.thnds.ro
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}
}
{
servers {
trusted_proxies static 192.168.1.0/24 172.18.0.0/16 172.17.0.0/16
client_ip_headers X-Forwarded-For X-Real-IP
}
}
authelia.thnds.ro {
import logging permis
reverse_proxy authelia:9141
}
sonarr.thnds.ro {
import logging sonarr
import secure *
reverse_proxy sonarr:8989
}
:80, :443 {
import logging catchall
respond "Bye!" 403 {
close
}
}