Method Filtering LAN/WAN Traffic

I’m looking for an equivalent of ipfilter from Caddy 1.

Effectively I’d like to be able to hide some of my subdomains to be accessible only to my LAN, but using a public domain name that I own. ipfilter appeared to do this, but it’s no longer compatible with Caddy starting with v2.

Documentation mentions remote_ip but it lacks a proper example and it’s very bare. Would that be the matcher to use?

Let’s say I have {

} {


Where I want just accessible from How would I write it?

Aye, this is the one.

It’s fairly straightforward - it accepts any number of ranges (syntax <ranges...>), and those ranges are OR’d (“For most matchers that accept multiple values, those values are OR’ed”, further up the page).

Ranges can be “exact IPs or CIDR ranges”, to quote the doc. So, same behaviour as ipfilter with regards to specifying the ranges.

Once you’ve matched, you then need to specify how you want to handle those requests. You’re probably looking for the respond directive:

As an extra hint, you can pair the remote_ip matcher with the not matcher to negate it. That way you can do “if not then deny”. The respond directive is how you would deny.

1 Like

Aha, yes, that’s what I was looking into before I responded to Matthew. Makes perfect sense! I knew there must of been a way to reverse the filtering logic, and of course in the end it follows Caddy’s simplicity. Cheers!


This plus @francislavoie 's mention of the not matcher looks perfect. Will try this out in the next few days and confirm. Cheers!

1 Like

Would someone please be able to provide an example? I’ve attempted to do it based on what is written above, but I can’t get it right as Caddy wont accept it. Visually seeing an example would be great.

Based on the directive and the request matcher format provided in the wiki, I thought it might be something like,

respond not remote_ip, 403

but that doesn’t work.

You need to use a named matcher. See the matcher docs, the only thing you can have inline with another directive is either * (to match any request), a path starting with /, or a named matcher starting with @. This is because matchers are optional, so the Caddyfile parser needs something to determine whether something is a matcher or not. Everything afterwards are arguments to the directive (in this case respond)

Also commas are not a valid argument separator in the Caddyfile, spaces only. If you need an argument with spaces (some text etc) then you can wrap it with double quotes.

Thanks, had to re-read those sections a few times. This seems to work, and I created a snippet to reuse on a few internal only pages.

(local_only) {
        @local_subnets {
                not remote_ip
        respond @local_subnets 403

import local_only
1 Like

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