CMS Plugin · Geo-Blocking

Geo-Blocking & Country Access Control

Restrict the public site to an allow-list of countries, with a /locked page for everyone else and a private bypass link that keeps you in — configured entirely from the admin, and always fail-open.

What it does

Geo-blocking restricts the public CMS site to visitors from an allow-list of countries. Anyone browsing from a country that is not on the list is redirected to a /locked page instead of the site — while a private bypass link lets you (and anyone you trust) still get in from a blocked country.

It ships off by default, is configured entirely from the admin, and survives redeploys — no server access, no config files to edit by hand. The country resolution happens server-side, so the block cannot be clicked away in the browser.

Nothing locks you out by accident. A missing country database or a bad setting always fails open — the site keeps serving normally rather than blocking the world.

Allowed countries & the lock page

The allow-list is not a separate list you retype here — it is exactly the set of countries you have enabled under Settings → Taxes & Countries (/admin/settings/tax-and-countries). That one screen is the single source of truth, so the countries you already sell to are the countries that can reach the site. The Blocked-countries tab shows a live “N countries allowed” count and links straight to it.

A blocked visitor is redirected to the page named by the target slug (default /locked). Build /locked as an ordinary CMS page — a short “this site is not available in your region” message, styled like the rest of your site. If you leave the target slug empty, blocked visitors instead receive an HTTP 451 (“unavailable for legal reasons”) with no redirect.

The bypass link

So you are never locked out of your own site, geo-blocking supports a bypass query — a secret key=value you add to any URL, for example:

https://your-site.example/?allowme=yes

Opening the site once with that parameter mints a signed bypass cookie (default lifetime 30 days) and drops you onto the clean URL — from then on you browse normally from anywhere, until the cookie expires. Share the link with anyone who needs access from a blocked country.

The cookie is a tamper-proof HMAC token carrying only an expiry — no personal data — and is signed with a secret dedicated to this feature (never your application's main key). A forged or expired token is simply ignored.

Always self-test the bypass link before flipping the block on, so you can confirm you still have a way in.

Country database (MaxMind GeoLite2 / DB-IP)

Turning a visitor's IP address into a country needs a local IP-to-country database in the standard MMDB format. It is not bundled with the platform (licensing), so you drop one in and it can be refreshed without a rebuild. Two free sources work interchangeably:

  • MaxMind GeoLite2-Country — free with a MaxMind account and license key; refreshable automatically with geoipupdate. MaxMind's licence requires attribution in your product / privacy documentation.
  • DB-IP IP-to-Country Lite — no account, CC-BY licensed, same file format. Drop it in under the same filename.

The database file lives at ${VAR_DIR}/cms/geoip/GeoLite2-Country.mmdb on the host. If it is absent, every visitor simply reads as “unknown country” and the site serves normally (see fail-open, below). Note that localhost and private network addresses have no country and always resolve as unknown.

Turning it on

Geo-blocking is managed from the Blocked countries tab under CMS → Routing Rules (/admin/cms/routing-rules). The full checklist:

  1. Choose the allowed countries at /admin/settings/tax-and-countries — enabling / disabling countries there is the allow-list.
  2. Provide the country database (MaxMind GeoLite2 or DB-IP Lite) at ${VAR_DIR}/cms/geoip/GeoLite2-Country.mmdb.
  3. Build the /locked page as a normal CMS page.
  4. Set the bypass query (e.g. allowme=yes), cookie lifetime and target slug in the Blocked-countries tab, and self-test the bypass link.
  5. Enable the block and Save.

Under the hood, saving the tab calls PUT /api/v1/admin/cms/geo-block (and GET reads the current config plus the derived allowed-country set); the settings are stored in the cms_geo_block_config singleton. Changes take effect within seconds — no restart, no reload.

Safety — it fails open

Geo-blocking is deliberately conservative: any doubt resolves to letting the visitor through, never to locking the site.

  • Off by default — a fresh install blocks nobody.
  • Missing / unreadable database — every visitor reads as unknown and the site serves normally.
  • Unknown country (private IP, unresolved) — passes through, unless you deliberately opt in to “block unknown country”.
  • Admin, API and the lock page stay reachable — the operator can always log in, and the /locked page's own assets are never blocked (no redirect loop).

Block responses are marked not cacheable, so a CDN or prerender layer never serves a stale block to an allowed visitor (or the reverse).

GDPR note

Resolving an IP address to a country is a form of processing — mention it in your privacy policy, and add the MaxMind attribution if you use GeoLite2. The feature is designed to be privacy-light: no IP address is stored beyond the request that resolves it, and the bypass cookie carries only an opaque expiry and a signature — no identity, no location history.

In short

Point the allow-list at the countries you already enable, drop in a free country database, publish a /locked page, set a bypass link and switch the block on from CMS → Routing Rules → Blocked countries. Visitors from other countries land on your lock page; you and anyone with the bypass link keep full access; and if anything is missing, the site simply stays open. See the CMS plugin reference for the content model the /locked page and routing rules build on.