# Enforce geo-blocking on apache (PHP app) [TOC] ## Geo-blocking by country on Bitnami Apache (AWS Lightsail) 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:** - AWS Lightsail instance (Debian 12) - Bitnami Contao stack - Apache 2.4.54 at `/opt/bitnami/apache` --- ### Step 1: Install build dependencies and MaxMind library ```bash sudo apt-get install -y libmaxminddb0 libmaxminddb-dev mmdb-bin gcc make ``` --- ### Step 2: Compile and install mod_maxminddb Bitnami ships its own Apache binary, so the Debian package `libapache2-mod-maxminddb` won't work. Compile from source against Bitnami's Apache instead. ```bash 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`: ```bash 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` --- ### Step 3: Download the GeoLite2 database Register for a free account at [https://www.maxmind.com/en/geolite2/signup](https://www.maxmind.com/en/geolite2/signup), then generate a license key under **Account → Manage License Keys**. ```bash 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: ```bash mmdblookup --file /opt/bitnami/apache/geoip/GeoLite2-Country.mmdb --ip 8.8.8.8 country iso_code # Should return: "US" ``` --- ### Step 4: Enable mod_remoteip 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: ```bash 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: ```bash grep "LoadModule remoteip_module" /opt/bitnami/apache/conf/httpd.conf ``` --- ### Step 5: Configure the HTTP vhost Edit `/opt/bitnami/apache/conf/vhosts/example.com-vhosts.conf`: ```apache 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] Options -Indexes +FollowSymLinks -MultiViews AllowOverride All Require all granted DirectoryIndex index.html index.cgi index.pl index.php index.xhtml ``` --- ### Step 6: Configure the HTTPS vhost Edit `/opt/bitnami/apache/conf/vhosts/example.com-https-vhosts.conf`: ```apache 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] Options -Indexes +FollowSymLinks -MultiViews AllowOverride All Require all granted DirectoryIndex index.html ``` --- ### Step 7: Create the blocked page Place an error page at `/opt/bitnami/contao/web/blocked.html`. A minimal example: ```html Not Available

This website is not available

Access to this website is restricted in your region. If you believe this is an error, please contact the site administrator.

``` --- ### Step 8: Test and restart Apache ```bash /opt/bitnami/apache/bin/httpd -t sudo /opt/bitnami/ctlscript.sh restart apache ``` --- ### Verification To confirm everything is working, add temporary debug logging to one vhost: ```apache 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: - US IPs → `302` redirect to `/blocked.html` with country code `US` - All other IPs → `200` with their respective country codes Remove the debug directives once confirmed. --- ### Notes - The `RewriteRule !^/blocked.html$` exclusion prevents an infinite redirect loop. - The `RemoteIPInternalProxy 172.16.0.0/12` covers the full AWS internal IP range (`172.16.0.0`–`172.31.255.255`). - The GeoLite2 database should be updated monthly. Consider a cron job using the same `wget` command in Step 3. - To block additional countries, extend the `RewriteCond` line: `RewriteCond %{ENV:MM_COUNTRY_CODE} ^(US|CA|GB)$`