Block visitors from a specific country and redirect them to an error page, using MaxMind GeoLite2 and mod_maxminddb on a Bitnami stack running on AWS Lightsail.
Environment:
/opt/bitnami/apachesudo apt-get install -y libmaxminddb0 libmaxminddb-dev mmdb-bin gcc make
Bitnami ships its own Apache binary, so the Debian package libapache2-mod-maxminddb won't work. Compile from source against Bitnami's Apache instead.
cd /tmp
wget https://github.com/maxmind/mod_maxminddb/releases/download/1.2.0/mod_maxminddb-1.2.0.tar.gz
tar xzf mod_maxminddb-1.2.0.tar.gz
cd mod_maxminddb-1.2.0
autoreconf -fiv
./configure --with-apxs=/opt/bitnami/apache/bin/apxs
make
sudo make install
Verify the module installed and was auto-added to httpd.conf:
ls /opt/bitnami/apache/modules/ | grep maxmind
grep -i maxminddb /opt/bitnami/apache/conf/httpd.conf
Expected output: LoadModule maxminddb_module modules/mod_maxminddb.so
Register for a free account at https://www.maxmind.com/en/geolite2/signup, then generate a license key under Account → Manage License Keys.
sudo mkdir -p /opt/bitnami/apache/geoip
cd /opt/bitnami/apache/geoip
sudo wget --user=YOUR_ACCOUNT_ID --password=YOUR_LICENSE_KEY \
"https://download.maxmind.com/geoip/databases/GeoLite2-Country/download?suffix=tar.gz" \
-O GeoLite2-Country.tar.gz
sudo tar xzf GeoLite2-Country.tar.gz --strip-components=1 --wildcards "*.mmdb"
ls *.mmdb
Test the database works:
mmdblookup --file /opt/bitnami/apache/geoip/GeoLite2-Country.mmdb --ip 8.8.8.8 country iso_code
# Should return: "US"
AWS Lightsail sits behind internal load balancers, so Apache sees a private 172.26.x.x IP rather than the real client IP. The real IP arrives in the X-Forwarded-For header. Enable mod_remoteip to handle this:
sudo sed -i 's/#LoadModule remoteip_module modules\/mod_remoteip.so/LoadModule remoteip_module modules\/mod_remoteip.so/' /opt/bitnami/apache/conf/httpd.conf
Verify:
grep "LoadModule remoteip_module" /opt/bitnami/apache/conf/httpd.conf
Edit /opt/bitnami/apache/conf/vhosts/example.com-vhosts.conf:
<VirtualHost 127.0.0.1:80 _default_:80>
ServerAlias *
DocumentRoot /opt/bitnami/contao/web
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 172.16.0.0/12
MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /opt/bitnami/apache/geoip/GeoLite2-Country.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code
RewriteEngine On
RewriteCond %{ENV:MM_COUNTRY_CODE} ^US$
RewriteRule !^/blocked.html$ /blocked.html [R=302,L]
<Directory "/opt/bitnami/contao/web">
Options -Indexes +FollowSymLinks -MultiViews
AllowOverride All
Require all granted
DirectoryIndex index.html index.cgi index.pl index.php index.xhtml
</Directory>
</VirtualHost>
Edit /opt/bitnami/apache/conf/vhosts/example.com-https-vhosts.conf:
<VirtualHost 127.0.0.1:443 _default_:443>
ServerAlias *
DocumentRoot /opt/bitnami/contao/web
SSLEngine on
SSLCertificateFile "/opt/bitnami/apache2/conf/bitnami/certs/server.crt"
SSLCertificateKeyFile "/opt/bitnami/apache2/conf/bitnami/certs/server.key"
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 172.16.0.0/12
MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /opt/bitnami/apache/geoip/GeoLite2-Country.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code
RewriteEngine On
RewriteCond %{ENV:MM_COUNTRY_CODE} ^US$
RewriteRule !^/blocked.html$ /blocked.html [R=302,L]
<Directory "/opt/bitnami/contao/web">
Options -Indexes +FollowSymLinks -MultiViews
AllowOverride All
Require all granted
DirectoryIndex index.html
</Directory>
</VirtualHost>
Place an error page at /opt/bitnami/contao/web/blocked.html. A minimal example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Not Available</title>
<style>
body { font-family: sans-serif; background: #f5f5f5; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; }
.container { text-align: center; max-width: 480px; padding: 2rem; }
h1 { font-size: 1.375rem; font-weight: 500; margin-bottom: 0.75rem; }
p { color: #6b7280; line-height: 1.7; }
</style>
</head>
<body>
<div class="container">
<h1>This website is not available</h1>
<p>Access to this website is restricted in your region. If you believe this is an error, please contact the site administrator.</p>
</div>
</body>
</html>
/opt/bitnami/apache/bin/httpd -t
sudo /opt/bitnami/ctlscript.sh restart apache
To confirm everything is working, add temporary debug logging to one vhost:
LogFormat "%h %{X-Forwarded-For}i %l %u %t \"%r\" %>s %b %{MM_COUNTRY_CODE}e" geoip_debug
CustomLog /opt/bitnami/apache/logs/geoip_debug.log geoip_debug
Then tail the log and make requests from different locations. You should see:
302 redirect to /blocked.html with country code US200 with their respective country codesRemove the debug directives once confirmed.
RewriteRule !^/blocked.html$ exclusion prevents an infinite redirect loop.RemoteIPInternalProxy 172.16.0.0/12 covers the full AWS internal IP range (172.16.0.0–172.31.255.255).wget command in Step 3.RewriteCond line: RewriteCond %{ENV:MM_COUNTRY_CODE} ^(US|CA|GB)$