NginX – Blocking per IP address or range

Yep I know what your thinking, blocking  by IP inside NginX, shouldn’t you be doing that at firewall level instead? Yes, if it comes from the actual IP, you should. Programs such as Fail2ban provide the functionality to automatically block unscrupulous IPs via iptables thus the traffic never gets anywhere near your software.

The problem comes however when your using a service such as Cloudflare. As far as the firewall is concerned the IP is that of Cloudflare, not the actual end user. Thus we then have to fall back on the next layer, which in this case is NginX. Utilising the RealIP Module we can set the user’s actual IP address into the correct server variable. Once we’ve done this anything running from NginX (PHP-FPM etc.) will see the remote address as the correct one rather than Cloudflare’s IP.

Anyway, to the point, blocking the IPs you don’t like. To do this you simply need to use NginX’s geo module. With this you can compare the provided remote address to a list and set a variable inside the http definition in nginx.conf:

geo $ban_ip {
default 0;
10.1.0.0/24 1;
192.168.0.254 1;
};

Once you’ve set this up you can use that variable inside the individual server definitions to send different http response codes for those specific IP addresses:

if ($ban_ip) {
return 404;
}

or you can tell NginX to simply drop the connection,

if ($ban_ip) {
return 444;
}

which if combined with Cloudflare will show the user Cloudflare’s cached version of your site, so the end user is still getting your site, without your server ever serving their client anything.

Thanks for this lovely snippet of information go to Alexander Azarov.

Fedora 18 – non-graphical boot and ifconfig

After downloading Fedora 18 and creating a minimal install virtual machine I went straight to doing the default I always do.  As I was creating a test server I need to be able to see what’s happening during boot so I disable the graphical boot.

Previously (at-least up to Fedora 15) I’d used the plymouth commands to switch the graphical boot to details which had worked.

[[email protected] ~]# plymouth-set-default-plugin details
[[email protected] ~]# /usr/libexec/plymouth/plymouth-update-initrd

However, when I tried this with Fedora 18, nope, not working, the community to the rescue. Another individual  (Nigel Smith) had had the same issue and found the solution in editing the default grub configuration file. So if you need the same visit here:

http://nwsmith.blogspot.co.uk/2012/10/customizing-grub2-boot-options-in.html

While I was at it I also noticed that ifconfig produced a “Command not found”. Erm … wha? Where did that go? Isn’t that like a basic linux command? Turns out in Fedora 18 it’s been removed due to the alternative and replacement iproute package being in place for “many years”. So you’ve now got 2 choices:

1. use the ip command:

ip addr

2. install the net-tools package:

yum -y install net-tools

Formatting a Date in PHP using ISO Format

We all know how to format a date in PHP when using the date functions, but what happens if you’ve only got the ISO format? This doesn’t work with PHP’s date functions.

Well I got this exact situation whilst using Zend_Locale in Zend Framework. Because the locale data files utilised are sourced externally the format comes back in ISO format.  A conversion function is provided (Zend_Locale_Format::convertPhpToIsoFormat) however that’s converting the wrong way and won’t help in this situation.

I went ahead and wrote a quick function which will return a formatted date using a provided ISO format, rather than PHP format.  It works like the PHP function and accepts the same parameters.

You can find the function as a gist on github:

<?php

function date_iso($format, $timestamp = null)
{
	if ($timestamp === null) {
		$timestamp = time();
	}

	$convert = array(
		'a' => 'A' , 'B' => 'B', 'D' => 'z', 'ddd' => 't', 'dd' => 'd', 'd' => 'j',
		'EEEE' => 'l', 'EE' => 'D', 'eee' => 'N', 'e' => 'w', 'HH' => 'H', 'H' => 'G',
		'hh' => 'h', 'h' => 'g', 'I' => 'I', 'l' => 'L', 'MMMM' => 'F', 'MMM' => 'M',
		'MM' => 'm', 'M' => 'n', 'mm' => 'i', 'r' => 'r', 'SS' => 'S', 'ss' => 's',
		'U' => 'U', 'ww' => 'W', 'X' => 'Z', 'YYYY' => 'o', 'yyyy' => 'Y', 'yy' => 'y',
		'ZZZZ' => 'P', 'zzzz' => 'e', 'Z' => 'O', 'z' => 'T'
	);

	$values = preg_split(
		'/(a|B|D|d{1,3}|EEEE|EE|eee|e|HH|H|hh|h|I|l|M{1,4}|mm|r|SS|ss|U|ww|X|YYYY|yyyy|yy|ZZZZ|zzzz|Z|z|[^a-zA-Z]+)/',
		$format,
		-1,
		PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
	);
	foreach ($values as $key => $value) {
		if (isset($convert[$value])) {
			$values[$key] = date($convert[$value], $timestamp);
		}
	}
	return implode($values);
}