1. The problem I’m having:
I am trying to deny access to some proxy sites using the @denied not client_ip ...
string in my caddy file(s). When using just RFC1918 addresses via private_ranges
everything works as expected. Adding more than just private_ranges
does not appear to work correctly. I would like to restrict access to only RFC1918 addresses, the IPv6 block assigned by my ISP, and (now that I have added tailscale to the mix) the 100.64.0.0/10 CGNAT block.
# private_ranges RFC1918
# 100.64.0.0/10 tailscale
# 2601:601:600:7a40:0:0:0:0/60 Camp: comcast delegated supernet.
@denied not client_ip private_ranges 100.64.0.0/10 2601:601:600:7a40:0:0:0:0/60
# OR
}
@denied {
not client_ip private_ranges
not client_ip 100.64.0.0/10
# not client_ip 2601:601:600:7a40:0:0:0:0/60 #Same result if I remove IPv6
}
I even went as far as trying this. 100.95.184.67 is my current tailscale IP.
@denied not client_ip 100.95.184.67
2. Error messages and/or full log output:
$ curl -vL sonarr.cozzo.net
* Host sonarr.cozzo.net:80 was resolved.
* IPv6: (none)
* IPv4: 10.10.0.2
* Trying 10.10.0.2:80...
* Connected to sonarr.cozzo.net (10.10.0.2) port 80
> GET / HTTP/1.1
> Host: sonarr.cozzo.net
> User-Agent: curl/8.6.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://sonarr.cozzo.net/
< Server: Caddy
< Date: Mon, 09 Dec 2024 23:26:25 GMT
< Content-Length: 0
<
* Closing connection
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://sonarr.cozzo.net/'
* Host sonarr.cozzo.net:443 was resolved.
* IPv6: (none)
* IPv4: 10.10.0.2
* Trying 10.10.0.2:443...
* Connected to sonarr.cozzo.net (10.10.0.2) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES128-GCM-SHA256 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: CN=sonarr.cozzo.net
* start date: Dec 8 17:13:15 2024 GMT
* expire date: Mar 8 17:13:14 2025 GMT
* subjectAltName: host "sonarr.cozzo.net" matched cert's "sonarr.cozzo.net"
* issuer: C=US; O=Let's Encrypt; CN=E6
* SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://sonarr.cozzo.net/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: sonarr.cozzo.net]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.6.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: sonarr.cozzo.net
> User-Agent: curl/8.6.0
> Accept: */*
>
< HTTP/2 200
< alt-svc: h3=":443"; ma=2592000
< content-type: text/plain; charset=utf-8
< referrer-policy: same-origin
< server: Caddy
< strict-transport-security: max-age=31536000; includeSubdomains
< x-content-type-options: nosniff
< x-frame-options: SAMEORIGIN
< x-xss-protection: 1; mode=block
< content-length: 59
< date: Mon, 09 Dec 2024 23:26:25 GMT
<
* Connection #1 to host sonarr.cozzo.net left intact
Your request from 100.95.184.67 was dropped.%
3. Caddy version:
$ sudo docker exec 62338e8af401 caddy version
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
4. How I installed and ran Caddy:
Via a docker compose file:
/mnt/git/docker/apps/caddy/docker-compose.yml
---
services:
caddy:
container_name: caddy
image: caddy:latest
restart: unless-stopped
build: .
env_file:
- /mnt/docker/secrets/caddy.env
cap_add:
- NET_ADMIN
networks:
- frontend
dns:
- 1.1.1.1
- 1.0.0.1
ports:
- "80:80"
- "80:80/udp"
- "443:443"
- "443:443/udp"
volumes:
- /mnt/docker/configs/caddy/caddy:/etc/caddy # Custom caddy file - root
- /mnt/docker/configs/caddy/site:/srv # Default site
- /mnt/docker/configs/caddy/data:/data
- /mnt/docker/configs/caddy/config:/config
- /mnt/docker/configs/caddy/caddyfiles:/caddyfiles # Site config files, rproxy redirects, etc.
networks:
frontend:
external: true
a. System environment:
- Digital ocean droplet: Ubuntu 24.10
- eth0 - Public
- eth1 - Internal (VPC) 10.10.0.0/16
- Tailscale: Proxy server is acting as an exit node and advertizing the 10.10.0.0/16 subnet.
** Other nodes are just member nodes.
b. Command:
$ sudo docker compose -f /mnt/git/docker/apps/caddy.do.cozzo.net/docker-compose.yml up -d
c. Service/unit/compose file:
N/A
d. My complete Caddy config:
/mnt/docker/configs/caddy/caddy/Caddyfile
:80, :443 {
redir https://proxy.do.cozzo.net
}
proxy.do.cozzo.net {
root * /srv/default
file_server
}
# Import caddy files so each site can be unique
import /caddyfiles/*.caddy
Site specific BROKEN:
/mnt/docker/configs/caddy/caddyfiles/sonarr.do.cozzo.net.caddy
sonarr.cozzo.net, do-sonarr.cozzo.net {
reverse_proxy p-docker01.do.cozzo.net:8989
header {
Strict-Transport-Security "max-age=31536000; includeSubdomains"
X-XSS-Protection "1; mode=block"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "same-origin"
}
tls {
dns cloudflare {env.CF_API_TOKEN}
resolvers 1.1.1.1
}
# Only respond to RFC1918
# private_ranges RFC1918
# 100.64.0.0/10 tailscale
# 2601:601:600:7a40:0:0:0:0/60 Camp: comcast delegated supernet.
# @denied not client_ip private_ranges 100.64.0.0/10 2601:601:600:7a40:0:0:0:0/60
}
@denied {
not client_ip private_ranges
not client_ip 100.64.0.0/10
# not client_ip 2601:601:600:7a40:0:0:0:0/60 #Same result if I remove IPv6
}
abort @denied
respond "Your request from {client_ip} was dropped."
}
Working config:
/mnt/docker/configs/caddy/caddyfiles/kuma.do.cozzo.net.caddy
kuma.cozzo.net, do-kuma.cozzo.net, uptime.cozzo.net, status.cozzo.net {
reverse_proxy p-proxy.do.cozzo.net:3001
header {
Strict-Transport-Security "max-age=31536000; includeSubdomains"
X-XSS-Protection "1; mode=block"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "same-origin"
}
#tls {
# dns cloudflare {env.CF_API_TOKEN}
# resolvers 1.1.1.1
#}
}
5. Links to relevant resources:
Public
dig proxy.do.cozzo.net +noall +answer
proxy.do.cozzo.net. 300 IN A 165.232.153.168
dig docker01.do.cozzo.net +noall +answer
docker01.do.cozzo.net. 300 IN A 164.92.74.175
Internal
dig p-proxy.do.cozzo.net +noall +answer
p-proxy.do.cozzo.net. 300 IN A 10.10.0.2
dig p-docker01.do.cozzo.net +noall +answer
p-docker01.do.cozzo.net. 300 IN A 10.10.0.4
Apps proxied
https://sonarr.cozzo.net
dig sonarr.cozzo.net +noall +answer
sonarr.cozzo.net. 300 IN CNAME p-proxy.do.cozzo.net.
p-proxy.do.cozzo.net. 300 IN A 10.10.0.2
dig kuma.cozzo.net +noall +answer
kuma.cozzo.net. 300 IN CNAME proxy.do.cozzo.net.
proxy.do.cozzo.net. 300 IN A 165.232.153.168
Apps direct
https://sonarr.do.cozzo.net:8989
dig sonarr.do.cozzo.net +noall +answer
sonarr.do.cozzo.net. 104 IN CNAME p-docker01.do.cozzo.net.
p-docker01.do.cozzo.net. 104 IN A 10.10.0.4
dig kuma.do.cozzo.net +noall +answer
kuma.do.cozzo.net. 300 IN CNAME p-proxy.do.cozzo.net.
p-proxy.do.cozzo.net. 300 IN A 10.10.0.2
From within the caddy container:
/srv # ping p-docker01.do.cozzo.net
PING p-docker01.do.cozzo.net (10.10.0.4): 56 data bytes
64 bytes from 10.10.0.4: seq=0 ttl=63 time=6.348 ms
64 bytes from 10.10.0.4: seq=1 ttl=63 time=3.873 ms
^C
/srv # ping sonarr.do.cozzo.net
PING sonarr.do.cozzo.net (10.10.0.4): 56 data bytes
64 bytes from 10.10.0.4: seq=0 ttl=63 time=5.042 ms
64 bytes from 10.10.0.4: seq=1 ttl=63 time=1.897 ms
^C
/srv # wget sonarr.do.cozzo.net:8989/
Connecting to sonarr.do.cozzo.net:8989 (10.10.0.4:8989)
Connecting to sonarr.do.cozzo.net:8989 (10.10.0.4:8989)
saving to 'index.html'
index.html 100% |*****************************************************************************************************************************************************************************************************************************************| 9654 0:00:00 ETA
'index.html' saved
/srv # rm index.html
/srv # wget p-docker01.do.cozzo.net:8989/
Connecting to p-docker01.do.cozzo.net:8989 (10.10.0.4:8989)
Connecting to p-docker01.do.cozzo.net:8989 (10.10.0.4:8989)
saving to 'index.html'
index.html 100% |*****************************************************************************************************************************************************************************************************************************************| 9654 0:00:00 ETA
'index.html' saved