Normally, at University open days, I run demonstrations of some of my services to prospective students and their parents. This year, the set up has changed slightly and instead of being in the hospitality suite, my stall was located in the main information fayre in the sports hall. The problem is that, presumably because a big three-storey metal room is basically a faraday cage, there is no good wifi in the University’s sports hall.
I solved this problem by copying all of my services (which all run on web servers) to a Raspberry Pi and running them from there. The clever bit is that I set up a DNS and DHCP server on the Pi so that any client machine (namely my laptop) connected to the same network would treat the Pi as if it were the internet, without needing any clever configuration client side. I could have just set my laptop up to have a static IP address and a custom hosts file, but the solution I used is far more elegant and allows for multiple clients to be plugged in and I only have to reconfigure the Pi, not the clients.
To do this, first you need to install Raspbian. I’m using 2017-08-16-raspbian-stretch-lite from the official website, but the instructions are different (particularly when setting up static IP addresses) on different versions, so these may not work for you if you’re using a different version. On first boot the Pi will resize the partition and then reboot itself, on second boot ensure it’s connected to the internet and install some packages.
sudo apt-get update
sudo apt-get install isc-dhcp-server dnsmasq
sudo apt-get install apache2 php5 libapache2-mod-php5
You need to do this now, because once you start messing with the network configuration you will (at best) have no internet access, or (at worst) unleash all manner of gremlins into the process, making the whole thing very hard to debug. Once the packages are installed, disconnect from the local network and the internet in order to prevent insanity from ensuing.
Static IP
First thing to note is that a Pi normally checks the network for a DHCP server to decide its IP address. Well, as the Pi itself is going to be the DHCP server, we need to configure it so that it assigns itself one on boot. I’m going with 192.168.0.200 just because that’s an address not used on my local network at home and I can therefore plug the Pi into it with minimal fuss, but you don’t have to use this address if you don’t want. The rest of the article is written assuming you are using this address.
Firstly we need to work out the hardware name of the Pi’s network hardware. This was always eth0
in the old days, but things have changed. Type ifconfig
and look for a long string of characters beginning with ‘e’. This is your Pi’s network hardware address. Write this down, it’s different on every Pi, and you’ll need it later.
Firstly edit /etc/dhcpcd.conf
(backup old version if you’re paranoid - I always do). You’ll need sudo because the file is owned by root.
Clear the contents of the file and type this in its place (replacing hardware_address
with your Pi’s hardware address)
interface hardware_address
static ip_address=192.168.0.200/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1
Reboot the pi and type ifconfig
again. This time, the long hardware address should have a line somewhere just beneath it saying inet=192.168.0.200
. This is our confirmation that it’s happily assigning itself the IP address we told it do.
DHCP with isc-dhcp-server
Now edit /etc/default/isc-dhcp-server
, again, backing it up first if you like.
Look for the line starting with INTERFACESv4
and make sure the value for INTERFACESv4
is set to your Pi’s hardware address. INTERFACESv6
, if it exists, should be set to a blank string.
Now edit /etc/dhcp/dhcpd.conf
. This file is massive, but pretty much everything will be commented out, with a # symbol at the start of most lines. Uncomment things as required. We specifically need the following lines in the file…
option domain-name "matrix";
option domain-name-servers 192.168.0.200;
authoritative;
‘matrix’ can be anything, it’s just the name I chose for my Pi. Next, add the following configuration at the bottom of the file…
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.11 192.168.0.150;
option domain-name-servers 192.168.0.200;
option routers 192.168.0.200;
}
This make sure that any new devices plugged into the network are allocated an IP address somewhere between 192.168.0.11 and 192.168.0.150, and that they also all use this particular Pi to do internet domain name lookups. This doesn’t do anything yet, but is in readiness for the next section.
Make the server start on boot…
sudo update-rc.d isc-dhcp-server start
and start it now, manually, with…
sudo service isc-dhcp-server start
Hopefully the server should start with no errors. If you get errors at this point, don’t go any further, fix them first. You’ll save yourself a lot of grief later on.
DNS with dnsmasq
DNS is the service that converts human-readable domain names like google.com into numerical IP addresses that computers understand. We are going to set up the Pi as a DNS server that responds to every relevant domain name with its own IP address, fooling clients into thinking it’s the actual server.
First, stop the service
sudo service dnsmasq stop
Edit the file /etc/dnsmasq.conf
to include the following…
cache-size=10000
dhcp-reply-delay=2
Now edit the /etc/hosts
file to include local resolutions for all the domain names we want to spoof. For example…
192.168.0.200 data.southampton.ac.uk
192.168.0.200 data.soton.ac.uk
192.168.0.200 maps.southampton.ac.uk
192.168.0.200 map.southampton.ac.uk
192.168.0.200 maps.soton.ac.uk
192.168.0.200 map.soton.ac.uk
We need to make sure every domain name that the client might call is set to our Pi’s local static IP address. Hosts doesn’t support wildcards, so if you want to spoof a lot of domains, you might want to look into dnsmasq’s advanced options instead. Once you’ve set the hosts, start the DNS service
sudo service dnsmasq start
HTTP with Apache
Nearly there! We’ve set up the Pi to tell the entire network that it can handle any web request that a client can throw at it, so let’s deliver on that promise!
First, create directories in /var/www
for all websites that the Pi is to answer to. For example:
/var/www/data.southampton.ac.uk/htdocs
/var/www/maps.southampton.ac.uk/htdocs
Edit Apache’s main configuration file, /etc/apache2/sites-available/000-default.conf
# Ensure that Apache listens on port 80
Listen 80
<VirtualHost *:80>
DocumentRoot /var/www/data.southampton.ac.uk/htdocs
ServerName data.southampton.ac.uk
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /var/www/maps.southampton.ac.uk/htdocs
ServerName maps.southampton.ac.uk
</VirtualHost>
Obviously, replace the two examples with your own values.
Apache has a nice feature that allows you to test a configuration without comitting to it, not necessary in this situation, but good if you’re fiddling with a live server. Check your config with the following
sudo apache2ctl configtest
It might warn that you’ve not set the global host name, which is fine, but it should come up with no other errors. If it doesn’t, well just restart Apache
sudo apache2ctl restart
And that should be it. You should now be able to plug any laptop into the same network as the Pi and it will immediately get an IP address in the 192.168 address range. Furthermore, any attempts to access the websites in question from the laptop should just display the content from the Pi without giving the user any clue that it’s not the real website.