Blocking by country and subdivision in Nginx
Geoblocking a single country in Nginx on Debian was the subject of an earlier tutorial. Extending it to cover both a country and an individual state comes down to loading two GeoIP databases, mapping the jurisdictions you want to exclude to explanatory strings, and returning HTTP 451 from the server block.
Mappings in the GeoIP config
Set up geoipupdate as usual first. Then, in /etc/nginx/conf.d.geoblock.conf, pull in the country and city databases, and map the countries and states you want to block to short strings naming the applicable law. This produces the variables $geoblock_country_law and $geoblock_state_law.
geoip2 /var/lib/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_iso_code country iso_code;
}
geoip2 /var/lib/GeoIP/GeoLite2-City.mmdb {
$geoip2_data_state_name subdivisions 0 names en;
}
map $geoip2_data_country_iso_code $geoblock_country_law {
GB "the UK Online Safety Act";
default "";
}
map $geoip2_data_state_name $geoblock_state_law {
Mississippi "Mississippi HB 1126";
default "";
}
The 451 response page
Create an HTML page to serve to geoblocked IPs — for example at /var/www/custom_errors/451.html. Its special comments are Server-Side Include directives; they insert the contents of nginx's $geoblock_law variable, which is set below.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Unavailable Due to
<!--# echo var="geoblock_law" default=""-->
</title>
</head>
<body>
<h1>Unavailable Due to
<!--# echo var="geoblock_law" default=""-->
</h1>
</body>
</html>
Wiring it into the server block
Next, in /etc/nginx/sites-enabled/whatever.conf, add an error page for status code 451 (unavailable for legal reasons). Inside the main location block, test $geoblock_country_law and $geoblock_state_law and use them to return 451, assigning $geoblock_law for the SSI template at the same time:
server {
...
# Status 451 renders this page
error_page 451 /451.html;
location /451.html {
ssi on;
internal;
root /var/www/custom_errors/;
}
location / {
# If either geoblock variable is set, return status 451
if ($geoblock_state_law != "") {
set $geoblock_law $geoblock_state_law;
return 451;
}
if ($geoblock_country_law != "") {
set $geoblock_law $geoblock_country_law;
return 451;
}
}
}
As usual, verify with nginx -t and apply with service nginx reload.
Accuracy and effects
Geoblocking is a poor experience in general. Cell phone 5G connections and hotel WiFi in Amsterdam and Frankfurt have been improperly identified as being in the UK, and people outside Mississippi will certainly be blocked by a state-level rule.
Because aphyr.com allows readers to post and confirm comments with email addresses, the site falls within the scope of Mississippi's 2024 HB 1126, which restricts holding "personal identifying information" unless the site also verifies the age of the person creating the account. Bluesky resorted to geoblocking Mississippi, and a small forum whose operators consulted lawyers reached the same conclusion: collecting email addresses brought it into scope, and it was unclear whether the LLC would shield its officers from personal liability. Conversations with Ofcom previously suggested aphyr.com might be illegal in the UK under the Online Safety Act.
No network is obliged to live with this outcome — calling your representatives is one way to press for better legislation.



