Trying to geo block part of website

1. The problem I’m having:

I’m trying to geoblock the landing page of my website outside of my country and leave the path /shares/* open to all countries.
For that purpose I’m using caddy-maxmind-geolocation module. I’m able to geoblock but everything is geoblocked even with the configuration I currently have.

2. Error messages and/or full log output:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

3. Caddy version:

v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY=

4. How I installed and ran Caddy:

a. System environment:

b. Command:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

c. Service/unit/compose file:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

d. My complete Caddy config:

{
    dynamic_dns {
            provider cloudflare {$CLOUDFLARE_API_TOKEN}
            domains {
                    dotflow.cc transfer
            }
    }

    acme_dns cloudflare {$CLOUDFLARE_API_TOKEN}

    debug

    crowdsec {
        api_url http://crowdsec:8080
        api_key {$CROWDSEC_API_KEY}
        ticker_interval 15s
    }
}

(logging) {
        log {
                output file /var/log/caddy/access.log {
                        roll_size 10MiB
                        roll_keep 1
                }
        }
}

example.com {
    import logging
    route {
        crowdsec
    }
    @mygeofilter {
      maxmind_geolocation {
        db_path "/usr/share/GeoIP/GeoLite2-Country.mmdb"
        allow_countries PT
      }
    }

    handle /shares/* {
        reverse_proxy 192.168.1.16:9998
    }

    handle {
        reverse_proxy @mygeofilter 192.168.1.16:9998
    }
}

5. Links to relevant resources:

I don’t have the MaxMind module installed, so this is just a guess rather than me knowing exactly what I’m doing. But can you try the following?

example.com {
    import logging
    route {
        crowdsec
    }

    handle /shares/* {
        reverse_proxy 192.168.1.16:9998
    }

    handle {
        maxmind_geolocation {
           db_path "/usr/share/GeoIP/GeoLite2-Country.mmdb"
           allow_countries PT
        }
        reverse_proxy 192.168.1.16:9998
    }
}

This is what I get and caddy won’t start:

INF ts=1741728082.7687137 msg=using config from file file=/etc/caddy/Caddyfile

Error: adapting config using caddyfile: parsing caddyfile tokens for 'handle': unrecognized directive: maxmind_geolocation - are you sure your Caddyfile structure (nesting and braces) is correct?, at /etc/caddy/Caddyfile:62

Edit:
Sorry for the confusion but it was actually working as I had before in my initial message, but I misunderstood how the “wildcard” * works in there apparently.

I thought

/shares/*

would include all subpaths under /shares, so if I had /shares/whatever/ it’d still fall under the allow all countries. But what was happening is that only /shares/ was being allowed to all countries.

Now the question is, how does it work and how can I have it be all subpaths under /share/ ?

I’ve tried so many things but I can’t get it to work, only

example.com/shares

is unblocked, everything else is blocked, even

example.com/shares/something

is also blocked.

From my understanding if you leave path empty after “handle” it defaults to * which means it’ll handle the whole domain and I think that’s what is happening to everything other than

/shares

Is there a way to handle just the root?

path matching is exact unless you use astrisk (wildcard). We typically recommend doing something like this to ensure consistency when handling sensitive edges:

redir /prefix /prefix/
handle /prefix/* # etc...

I’ve tried using / to handle root host access but it won’t work for a reason I don’t understand.
If I do

        handle /shares* {
            reverse_proxy 192.168.1.16:9998
        }
        handle / {
            reverse_proxy @mygeofilter 192.168.1.16:9998
        }

everything except for /shares/ gets blocked everywhere, including my own country, /shares/whatever/ can’t be accessed anywhere either.
Only /shares/ becomes accessible, everything else gets blocked in all countries including mine.

This is very confusing to me.

Edit:
Also, if I do

        handle /shares* {
            reverse_proxy 192.168.1.16:9998
        }
        handle {
            reverse_proxy @mygeofilter 192.168.1.16:9998
        }

then everything except for /shares/ gets blocked outside of my country, the geoip filter works and everything is accessible in my country. Problem is I have links that are generated with /share/whatever that I’d need being accessed all over the world and with either of these setups they’re not.

What I’m trying to achieve is:

block example.com/ everywhere except for my country

and:

allow example.com/shares/* in the whole world

It is solved, I was missing some paths for the webserver to make it function, that’s why it was not showing when I added the / to it.
The paths were working as intended, it was just me being a noob. :head_shaking_vertically:

This made it work:

example.com {
    import logging
    route {
        crowdsec
    }

    @allowpt {
      maxmind_geolocation {
        db_path "/usr/share/GeoIP/GeoLite2-Country.mmdb"
        allow_countries PT
      }
    }

    handle / {
        reverse_proxy @allowpt 192.168.1.16:9998
    }
    handle /build* {
        reverse_proxy 192.168.1.16:9998
    }
    handle /api* {
        reverse_proxy 192.168.1.16:9998
    }
    handle /shares* {
        reverse_proxy 192.168.1.16:9998
    }
    handle /get-logo* {
        reverse_proxy 192.168.1.16:9998
    }

Sorry for bothering you guys with my lack of experience… and thanks for the help. :+1:

2 Likes

Thank you for posting the final solution!

1 Like