Herding cats and happy.
Limiting phpBB3 registrations by country

I have a community-oriented bulletin board running on phpBB3. I want to limit its users to local residents - or at least residents of my own country. I have nothing against people living elsewhere; it’s just that someone living in Chile probably won’t be interested in my little website in a small town in the USA unless they’re wanting to post spam to it. Here’s how I did it.

Note: I’m using Apache 2.2 on a FreeBSD server. The details for other combinations will be a little different but very similar.

Download a list of networks in my country

Country IP Blocks is a website that lists the network blocks associated with each country. While this isn’t guaranteed to be 100% accurate, it’ll be pretty close. After digging around on the site, I found that the list of all network blocks in the United States is at https://www.countryipblocks.net/e_country_data/US_allow.txt. I downloaded this to my Apache server’s Includes directory:

# cd /usr/local/etc/apache22/Includes
# curl -O https://www.countryipblocks.net/e_country_data/US_allow.txt      

Block access to the User Control Panel

The User Control Panel, or UCP, is the phpBB page that handles registration and profile editing and all that other good stuff. By limiting access to that page (located at /ucp.php on my site) to only the network blocks in the list I downloaded in the first step, I block anyone outside the US from registering an account. They can still read my public forums - they just can’t participate.

I edited the Apache configuration file for my domain to add this clause:

<Location /ucp.php>
    Order Deny,Allow
    Deny from All
    Include etc/apache22/Includes/US_allow.txt
    Allow from ::
</Location>

The <Location> tag says that the following settings will only apply to the /ucp.php page.

The Order Deny,Allow directive tells Apache to obey any “Deny” directives by default, and then override those results with any matching “Allow” directives it finds.

The next line, Deny from All means exactly that: block all users unless their IP address is listed in one of the blocks I downloaded in the first step.

The fourth line instructs Apache to slurp in all of the allow from ... lines from the network list file. I chose this approach over putting the instructions in a more common .htaccess file for two reasons:

  1. If I want to update my list of network blocks, I can just re-download that file and restart Apache to reload its contents. Since I’ve never added any other directives to that file, I don’t have to worry about merging any records or remembering to copy the “extra” statements.
  2. When you put directives in a .htaccess file, those directives are reloaded every time a visitor tries to view a page - any page. As of this moment, there are nearly 40,000 allow from directives in the network block list and that’s a lot of extra work for something that won’t change very often. By Includeing its contents directly into the Apache configuration, those directives are only loaded and interpreted once whenever the webserver starts. The downside is that I’ll have to remember to restart Apache when or if I ever update the network block list.

Next is a directive to allow all IPv6 visitors. If I ever start receiving spam from IPv6 clients, I’ll reconsider that option.

The trailing </Location> line says that we’re done with this snippet.

Relax and enjoy the show

Soon after restarting Apache, “deny” messages started filtering into my site’s error log:

[Wed Jun 29 14:10:16 2011] [error] [client 77.93.2.81] client denied by server configuration: /usr/local/www/phpBB3/ucp.php, referer: http://norfolkboard.com/ucp.php?mode=register

Interpretation: someone in Latvia tried unsuccessfully to register an account on my site. While it’s remotely possible that a local resident is visiting European relatives and suddenly wanted to check my site, the odds are much greater that I just blocked a would-be spammer from opening an account.