1. Caddy version (caddy version
):
devel (The one with TLS client auth yesterday: httpcaddyfile: Add client_auth options to tls directive (#3335) · caddyserver/caddy@1dfb114 · GitHub)
2. How I run Caddy:
a. System environment:
Docker on Debian Buster
b. Command:
docker-compose up
c. Service/unit/compose file:
version: "3.2"
networks:
default:
external:
name: proxy
services:
caddy:
container_name: caddy
image: caddy:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ../volumes/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- ../volumes/caddy/cloudflare-origin-pull-ca.pem:/etc/caddy/cloudflare-origin-pull-ca.pem:ro
- ../volumes/caddy/config:/config
- ../volumes/caddy/data:/data
- ../volumes/caddy/logs:/logs
# php-fpm roots
- ../volumes/caddy/sites:/sites
- ../volumes/nextcloud/html:/php-fpm-root/nextcloud
- ../volumes/nextcloud/apps:/php-fpm-root/nextcloud/custom_apps
# Testing
- ../volumes/caddy/caddy:/usr/bin/caddy
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
d. My complete Caddyfile or JSON config:
# /etc/caddy/Caddyfile
# Global config
{
# Let's Encrypt
email email@domain.com
# No admin
admin off
}
(webconf) {
# Add zstd and gzip compression to requests
encode zstd gzip
# Remove headers (leading "-")
header {
-x-powered-by
}
}
# Add common headers for non-reverse_proxy sites
(non_reverse_proxy_headers) {
header {
Strict-Transport-Security "max-age=31536000;"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
Content-Security-Policy "frame-src 'self'; frame-ancestors 'self'; object-src 'none';"
}
@cache_css_js {
path_regexp cache_css_js \.(?:css|js)$
}
@cache_media {
path_regexp cache_media \.(?:jpg|jpeg|gif|png|bmp|ico|swf|xml|ogg|m4a|mp3)$
}
# 1 week
header @cache_css_js Cache-Control max-age=604800
# 2 weeks
header @cache_media Cache-Control max-age=1209600
}
# Only allow connections from Cloudflare (and internal)
# Additionally sets the correct user IP address
(cloudflare) {
# This isn't doing anything yet
@internal {
remote_ip 192.168.0.0/16
}
# This works!
tls {
client_auth {
mode require_and_verify
trusted_ca_cert_file /etc/caddy/cloudflare-origin-pull-ca.pem
}
}
# I assume this works, haven't tested it yet
request_header remote-addr {http.request.header.CF-Connecting-IP}
}
apps.example.com {
root * /sites/apps.example.com/public/
file_server
php_fastcgi php:9000
log {
output file /logs/apps.example.com/access.log
format single_field common_log
}
import cloudflare
import non_reverse_proxy_headers
import webconf
}
3. The problem I’m having:
The TLS client auth thing seems to be working! I can only connect to my server going through Cloudflare, and I didn’t have to set up a ton of (occasionally updating) whitelist URLs to only allow Cloudflare connections. Very cool! I’m excited for 2.1 to come out!
The next step is that I want to allow internal IPs to bypass this. If the remote_ip is internal, don’t do the TLS client auth and the request_header remote-addr
replacement. I didn’t know if there was a way to only apply configuration options to certain matchers (I think that’s the right terminology)? It seemed like the matchers were only used for doing actual routing/rewriting/responds.
4. Error messages and/or full log output:
(There are no errors/log output)
5. What I already tried:
The above works for forcing all connections to go through Cloudflare, but obviously that @internal
matcher isn’t doing anything at the moment. I was considering doing some sort of handler setup, where internal IPs would be handled the same exact way as the external Cloudflare IPs (just copy the config to both handlers), but without the TLS stuff. I think that would work, but I’m not too jazzed about duplicating config code, especially when I’d also have to do it for my 11 other sites I have set up in the Caddyfile. I’d prefer to just add an import cloudflare
to all the sites, if possible.
I’m all ears for any other solutions though! I like the TLS client auth so much though, I might just remove all of my internal IPs from my network DNS resolver. Only cons to that are ISP data caps and speeds.
6. Links to relevant resources:
7. Extra Credit
Is there a location for submitting suggestions? I think it would be amazing to have snippets that take arguments. I think in code, so whenever I find myself duplicating code, I abstract it out and move it to a method. I have 12 sites configured, half of them are just copy pastes with the site name changed. If i could just import php_site apps.example.com
, that’d be very cool.