Implementing GeoBlocking in Pangolin Stack with Traefik

Updated to “GitHub - david-garcia-garcia/traefik-geoblock: Traefik Geoblock Plugin

Which is much efficient than the older plugin.

First, let’s understand why you might want geoblocking:

  • Restrict access to specific countries
  • Prevent unauthorized access from high-risk regions
  • Comply with regional regulations
  • Reduce potential attack surface

Here’s a step-by-step guide to implement geoblocking:

  1. First, modify your traefik_config.yml to add the GeoBlock plugin. Add this under the experimental plugins section:
experimental:
  plugins:
    # ... existing plugins ...
    geoblock:
      moduleName: "github.com/david-garcia-garcia/traefik-geoblock"
      version: "v1.0.1"
  1. In your dynamic_config.yml, add the GeoBlock middleware configuration. You can add this under the middlewares section:
pangolin-geoblock:
    plugin:
        geoblock:
            enabled: true
            defaultAllow: false
            databaseFilePath: "/plugins-storage/IP2LOCATION-LITE-DB1.IPV6.BIN"
            allowPrivate: true
            logBannedRequests: true
            banIfError: true
            disallowedStatusCode: 403
            allowedCountries:
                - US # United States
                - CA # Canada
                - GB # United Kingdom
                - IN # India
                # Add more countries as needed from the ISO 3166-1 alpha-2 codes
            allowedIPBlocks:
                - "192.168.0.0/16"
                - "10.0.0.0/8"
            bypassHeaders:
                X-Internal-Request: "true"
                X-Skip-Geoblock: "1"
  1. Apply the middleware to your enterypoints in traefik_config.yml. You can add it to specific paths:
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: "30m"
    http:
      middlewares:
	  - pangolin-geoblock@file
  1. Set up the IP2Location database by mounting it to your Traefik container. Add this to your Docker Compose file:
services:
  traefik:
    # ... existing config ...
    volumes:
      # ... existing volumes ...
      - ./IP2LOCATION-LITE-DB1.IPV6.BIN:/plugins-storage/IP2LOCATION-LITE-DB1.IPV6.BIN
  1. Restart your Traefik container to apply the changes:
docker compose restart traefik

Important Configuration Options:

  • defaultAllow:

    • false: Block by default, only allow listed countries (whitelist mode)
    • true: Allow by default, only block listed countries (blacklist mode)
  • allowPrivate: Set to true if you want to allow local network requests

  • allowedCountries or blockedCountries: List of two-letter ISO country codes to allow or block

  • allowedIPBlocks or blockedIPBlocks: CIDR ranges to always allow or block

  • bypassHeaders: Headers that will skip geoblocking entirely

  • banIfError: Block requests if IP lookup fails

  • databaseAutoUpdate: Enable automatic database updates

    databaseAutoUpdate: true
    databaseAutoUpdateDir: "/data/ip2database"
    databaseAutoUpdateToken: ""  # For premium IP2Location
    databaseAutoUpdateCode: "DB1"
    

Monitoring and Troubleshooting:

  1. Check Traefik logs for geoblocking activity:
docker compose logs -f traefik
  1. Enable detailed logging options in the configuration for debugging:
logLevel: "debug"
logFormat: "json"
logPath: "/var/log/geoblock.log"  # Empty for Traefik's standard output
logBannedRequests: true
  1. Monitor the JSON logs which include fields like:
    • IP address that triggered the action
    • Country code
    • Request host and method
    • Processing phase where the action occurred

Security Considerations:

  1. Always use the middleware with HTTPS (websecure entrypoint)
  2. Consider implementing rate limiting alongside geoblocking
  3. Use allowPrivate carefully based on your needs
  4. Whitelist domains [“download.ip2location.com”, “www.ip2location.com”] if using auto-updates

Remember to update your countries list based on your specific needs.

Don’t just copy paste it. Edit the list before use.

Please take Care of your yml indentation. Otherwise plugin will give errors.

I have tested this configuration on all three major OS Ubuntu 24.04, debian 12 and alma 9

10 Likes

Thanks you so much for this guides, i was having a lot of troubles with other proxies but since im using Pangoling + your guides i could set up an amazing proxy! :heart_with_arrow:

1 Like

How could the rate limit be implemented correctly with this configuration? Together with fail2ban?

Thanks for the guide, works like a charm. Only issue is there is no log file, or even a /traefic folder in /var/log on my Debian install.

1 Like

Traefik has a built in rate limiter:

http:
  middlewares:
    pangolin-ratelimit:
      rateLimit:
        average: 100
entryPoints:
  web:
    address: :80
  websecure:
    address: :443
    http:
      middlewares:
        - pangolin-ratelimit@file
        - pangolin-geoblock@file
        - crowdsec@file

its already there in pangolin by default.

I have a question (forgive me, i’m learning!) … i followed the instructions and installed geoblock functionality in traefik. tested the access with a vpn from one of the blocked countries (i have whitelisted only some countries - rest should be blocked) and it seemed to be working. lately i added crowdsec to my configuration and crowdsec keeps blocking chinese ips that are trying to access. so just for interess and because i’m still learning: does that mean that crowdsec checks first (like before geoblock)? otherwise the chinese ips would not make it through geoblock, right?

You should ideally have geoblock first as a middleware and then crowdsec, that way you can take advantage of both plugins and the load on crowdsec becomes less and say suppose if geoblock missies something crowdsec will catch it.

2 Likes

makes sense… but how do i do that?

Edit: Is it right to just change the sequence of the middlewares in dynamic_conf.yml so that geoblock is the first one followed by crowdsec?

The order of the middlewares in the dynamic_conf.yml does not matter, where is a MUST is at the traefik_config.yml , in that one you need to place “pangolin-geoblock@file” the very firts one.

1 Like

Hi community,
nscuro/traefik-plugin-geoblock: traefik plugin to whitelist requests based on geolocation

This plugin is also interesting and has more options

experimental:
  localPlugins:
    geoblock:
      moduleName: github.com/nscuro/traefik-plugin-geoblock
pilot:
  token: "xxxxxxxxx"

experimental:
  plugins:
    geoblock:
      moduleName: github.com/nscuro/traefik-plugin-geoblock
      version: v0.14.0

Dynamic

http:
  middlewares:
    geoblock:
      plugin:
        geoblock:
          # Enable this plugin?
          enabled: true
          # Path to ip2location database file
          databaseFilePath: /plugins-local/src/github.com/nscuro/traefik-plugin-geoblock/IP2LOCATION-LITE-DB1.IPV6.BIN
          # Whitelist of countries to allow (ISO 3166-1 alpha-2)
          allowedCountries: [ "AT", "CH", "DE" ]
          # Blocklist of countries to block (ISO 3166-1 alpha-2)
          blockedCountries: [ "RU" ]
          # Default allow indicates that if an IP is in neither block list nor allow lists, it should be allowed.
          defaultAllow: false
          # Allow requests from private / internal networks?
          allowPrivate: true
          # HTTP status code to return for disallowed requests (default: 403)
          disallowedStatusCode: 204
          # Add CIDR to be whitelisted, even if in a non-allowed country
          allowedIPBlocks: ["66.249.64.0/19"]
          # Add CIDR to be blacklisted, even if in an allowed country or IP block
          blockedIPBlocks: ["66.249.64.5/32"]
1 Like

Hi hhf! One question, what are the key differences between that one and the one that you show at the top? is worth the try?

1 Like

it has more options compared to the one which I have posted in the tutorial.
but please check the issues before deploying Issues · nscuro/traefik-plugin-geoblock

1 Like

thank you!! Working perfectly!

1 Like

thank you. something cool coming up next week.

2 Likes

Hi, thank you for the great plugin and the detailed guide!

I have a question regarding the database paths:

In the dynamic config, I set:

databaseFilePath: "/plugins-storage/IP2LOCATION-LITE-DB1.IPV6.BIN"
databaseAutoUpdate: true
databaseAutoUpdateDir: "/data/ip2database"

And in my Docker Compose, I have:

volumes:
  - ./IP2LOCATION-LITE-DB1.IPV6.BIN:/plugins-storage/IP2LOCATION-LITE-DB1.IPV6.BIN

I’m confused about the two paths:

  • Shouldn’t the auto-update path (databaseAutoUpdateDir) match where I’m mounting the .BIN file?
  • What happens if I enable auto-update and also manually mount the .BIN file?
  • Will the plugin automatically pick the latest .BIN from the auto-update dir instead of the mounted one?
  • Can I skip mounting altogether if auto-update is enabled?

Just trying to understand the correct setup to avoid conflicts or unused mounts.

1 Like

I’ll lcome back to it at a later time, I’m sure I need to have the database created first.

"plugin":"plugin-geoblock","module":"github.com/david-garcia-garcia/traefik-geoblock","runtime":"","time":"2025-05-10T00:09:40Z","level":"error","message":"2025/05/10 00:09:40 time=2025-05-10T00:09:40.579Z level=ERROR msg=\"could not find file\" plugin=geoblock@file file=IP2LOCATION-LITE-DB1.IPV6.BIN path=/plugins-storage/IP2LOCATION-LITE-DB1.IPV6.BIN\n"}
{"level":"error","entryPointName":"websecure","routerName":"ws-router@file","error":"geoblock@file: failed to open database: open /plugins-storage/IP2LOCATION-LITE-DB1.IPV6.BIN: no such file or directory","time":"2025-05-10T00:09:40Z"}