Homelab administrators often lock down self-hosted applications using an identity provider like Authelia or Authentik. This creates a hard authentication barrier before a visitor reaches the application backend. Strict zero-trust access blocks brute-force attacks and vulnerability exploits, but it breaks a common workflow: sharing a public link with users who do not have an SSO account. You can solve this by configuring Caddy to bypass the authentication gateway for specific URLs, exposing only the exact paths required for the share links to function.
Caddy Forward Auth Mechanics
Caddy provides the forward_auth directive to handle external authentication. It proxies a clone of the incoming HTTP request to an authentication gateway. If the gateway returns a successful 2xx status code, Caddy copies the authorized user headers and passes the request to your application. If the gateway returns any other status code, Caddy forwards the gateway's response back to the client. This usually triggers an HTTP 302 redirect to the SSO login portal.
To protect an entire application, a basic Caddyfile block looks like this:
nextcloud.example.com {
forward_auth authelia:9091 {
uri /api/verify?rd=https://auth.example.com
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}
reverse_proxy nextcloud:80
}
This configuration rejects all unauthenticated traffic. No public share links will load under this block because the authentication gateway intercepts every request.
Configuring Homelab Reverse Proxy Public Share Links
To allow external users to access specific files without a login, you must split the Caddy configuration. Caddy uses named matchers and the handle directive to apply rules selectively based on the request path.
For Nextcloud, public shares are generated under the /s/ path. Bypassing this single path is not enough. The user will see a broken HTML page without styling. Nextcloud requires CSS, JavaScript, and image assets located in other directories to render the share page correctly.
This Caddyfile snippet bypasses authentication for the required paths and protects the rest of the application:
nextcloud.example.com {
# Match the share path and necessary asset directories
@public path /s/* /index.php/s/* /apps/* /core/* /dist/* /img/* /js/* /css/* /avatar/* /svg/*
# Allow public access to the matched paths
handle @public {
reverse_proxy nextcloud:80
}
# Protect everything else with Authelia
handle {
forward_auth authelia:9091 {
uri /api/verify?rd=https://auth.example.com
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}
reverse_proxy nextcloud:80
}
}
This setup routes any request matching the @public rules directly to Nextcloud. All other requests fall through to the second handle block and hit the forward_auth directive.
You apply the same logic if you use Authentik instead of Authelia. The URI endpoint and the copied headers differ, but the Caddy handle structure remains identical:
# Protect everything else with Authentik
handle {
forward_auth authentik:9000 {
uri /outpost.goauthentik.io/auth/caddy
copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid
}
reverse_proxy nextcloud:80
}
The API Trap with Immich
Not all applications handle public shares using simple static HTML paths. Modern platforms often operate as single-page applications that rely heavily on backend APIs.
When you create a shared link in Immich, the frontend loads via the /share/ path. The frontend then makes asynchronous calls to the /api/ endpoints to fetch the actual photo data. If you bypass just the /share/ path, the user gets a blank interface. The initial page loads, but Authelia blocks the subsequent API requests.
Whitelist the entire /api/ path and you expose the administrative endpoints, nullifying the security benefits of the reverse proxy. To securely expose Immich share links via Caddy, you must whitelist the exact API routes required for shared links. These specific routes change across major updates.
Because maintaining a precise list of API paths requires constant intervention, administrators often deploy the community-maintained Immich Public Proxy. This runs as a separate, stateless Docker container that exclusively handles shared links. It strips metadata and blocks unauthorized paths automatically, removing the need to modify your Caddy forward auth rules for the main Immich instance.
Caddy Protect Self Hosted Apps and Mobile Clients
Many administrators implement Caddy protect self hosted apps setups to block automated scanners, but this approach breaks native mobile clients. Mobile applications for Nextcloud, Immich, and Jellyfin expect direct access to the application API. When Caddy intercepts a mobile app's API request and returns an Authelia HTML login redirect, the mobile app fails to parse the response. The application crashes or hangs. It will not display the SSO login portal.
You have three options to handle native mobile applications:
- Bypass the API paths completely. This reduces the security benefit of the identity provider because scanners can hit the application's login form directly.
- Require a VPN like Tailscale or WireGuard on mobile devices. The application stays fully internal, and you only use the public domain for web access.
- Use application-specific bypass headers.
Some mobile clients allow you to inject custom HTTP headers into your requests. You can configure Caddy to bypass forward_auth if a specific secret header is present.
immich.example.com {
@mobile_bypass header Immich-Skip-Authelia "SuperSecretString123"
handle @mobile_bypass {
reverse_proxy immich:2283
}
handle {
forward_auth authelia:9091 {
uri /api/verify?rd=https://auth.example.com
copy_headers Remote-User
}
reverse_proxy immich:2283
}
}
This configuration acts as a static API key. If the header is present, the request bypasses Authelia. You must use TLS (HTTPS) on your public domain to encrypt the header in transit and prevent interception.
Preventing Header Spoofing Vulnerabilities
When Caddy validates a request through the authentication gateway, it copies identity headers to the backend application. The application reads these headers to log the user in automatically.
You must ensure external users cannot spoof these headers to gain administrative access on the bypassed public routes. Caddy normally clears incoming headers before passing them to the application if configured properly, but explicit bypass blocks require manual intervention.
In your Caddyfile, ensure the reverse_proxy directive does not implicitly trust incoming identity headers from the outside. If an attacker visits a bypassed path like /s/xyz and manually includes a Remote-User: admin HTTP header, Caddy must strip it. The forward_auth directive automatically overwrites these headers on a successful login, but for paths in the @public block, no overwrite occurs.
You must manually strip the headers from unauthenticated requests to prevent privilege escalation:
handle @public {
request_header -Remote-User
request_header -Remote-Groups
request_header -Remote-Name
request_header -Remote-Email
reverse_proxy nextcloud:80
}
This directive removes the headers before the request reaches Nextcloud.
The backend application also needs verification. Nextcloud requires the trusted_proxies array in its config.php file to validate where the headers come from.
'trusted_proxies' => ['192.168.1.100'],
Set this to the IP address of your Caddy server or Docker network gateway. If you leave trusted_proxies empty or misconfigured, Nextcloud may accept spoofed headers from untrusted sources, rendering your SSO setup useless.
What's Next
- Ansible for Homelabbers: Automate From One Playbook
- Let's Encrypt 64-Day Certificates: Homelab SSL Automation
- Proxmox VE Homelab Setup: Install and Configure (2026)
FAQ
Does forward_auth break native mobile apps?
Yes. Mobile apps expect direct API access and fail when redirected to a login portal. You must either bypass the API paths, use custom headers, or rely on a VPN for mobile access.
Do I need to bypass CSS and JS paths for share links?
Usually, yes. Nextcloud share pages rely on assets in the /apps/ and /core/ directories. Bypassing only the /s/ path results in a broken layout.
Can I use Authentik instead of Authelia?
Yes. Caddy's forward_auth directive works with any authentication gateway that supports the forward authentication specification.
Originally published at linuxcore.dev.
Top comments (0)