Main Linux Networking Cookbook
Book cover Linux Networking Cookbook

Linux Networking Cookbook

Key Features
• This is a hands-on solution guide to building, maintaining, and securing a network using Linux

Book Description
Linux can be configured as a networked workstation, a DNS server, a mail server, a firewall, a gateway router, and many other things. These are all part of administration tasks, hence network administration is one of the main tasks of Linux system administration. By knowing how to configure system network interfaces in a reliable and optimal manner, Linux administrators can deploy and configure several network services including file, web, mail, and servers while working in large enterprise environments.
Starting with a simple Linux router that passes traffic between two private networks, you will see how to enable NAT on the router in order to allow Internet access from the network, and will also enable DHCP on the network to ease configuration of client systems. You will then move on to configuring your own DNS server on your local network using bind9 and tying it into your DHCP server to allow automatic configuration of local hostnames. You will then future enable your network by setting up IPv6 via tunnel providers.
Moving on, we'll configure Samba to centralize authentication for your network services; we will also configure Linux client to leverage it for authentication, and set up a RADIUS server that uses the directory server for authentication.
Toward the end, you will have a network with a number of services running on it, and will implement monitoring in order to detect problems as they occur.

What you will learn
• Route an IPv6 netblock to your local network
• Modify your named instance to support setting hostnames for your IPv6 addresses
• Use SSH for remote console access
• Configure NGINX with TLS
• Secure XMPP with TLS
• Leverage iptables6 to firewall your IPv6 traffic
• Configure Samba as an Active Directory compatible directory service
Categories: Computers\\Networking
Year: 2016
Edition: 1
Language: english
Pages: 152
ISBN 10: 1785287915
ISBN 13: 978-1785287916
File: PDF, 1.42 MB
Downloads unavailable

You may be interested in


The Linux Command Line: A Complete Introduction

Year: 2019
Language: english
File: PDF, 7.11 MB

Linux Networking 

Over 40 recipes to help you set up and configure  
Linux networks

Gregory Boyce


Linux Networking Cookbook

Copyright © 2016 Packt Publishing


warranty, either express or implied. Neither the author(s), nor Packt Publishing, and its dealers 
indirectly by this book.

Publishing cannot guarantee the accuracy of this information.

First published: June 2016

Production reference: 1220616

Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham B3 2PB, UK.

ISBN 978-1-78528-791-6


Gregory Boyce

Jean-Pol Landrain

Acquisition Editor
Sonali Vernekar

Content Development Editor
Onkar Wani

Technical Editor
Naveenkumar Jain

Copy Editor
Sneha Singh

Project Coordinator
Ulhas K

Safis Editing

Hemangini Bari

Kirk D'Penha

Production Coordinator
Shantanu N. Zagade

Cover Work
Shantanu N. Zagade

About the Author

Gregory Boyce is a technologist with nearly 20 years of experience in using and managing 
Linux systems. When he's not at work or spending time with his wife and two daughters, he is 
playing around with new technologies.

Gregory spent the last 15 years working at Akamai Technologies, where he has worked in 
roles ranging from Network Operations, Internal IT, Information Security, Software Testing,  
and Professional Services.

Currently, he heads up the Linux OS team that manages Akamai's custom Linux operating 
system, which runs on their massively distributed customer facing network.

I'd like to thank my wife, Vanessa, for all the support and Akamai for 
surrounding me with such a wonderful assortment of intelligent and 
interesting people.

About the Reviewer

Jean-Pol Landrain has a BSc degree in software engineering with a focus in network,  
real-time, and distributed computing. He gradually became a software architect with more 
than 18 years of experience in object-oriented programming, in particular with C++, Java/JEE, 
various application servers, and related technologies.

He works for Agile Partner, an IT consulting company based in Luxembourg. From  
early 2006 he became dedicated to the promotion, education, and application of agile  
development methodologies.

He has reviewed numerous books both for Manning and Packt Publishing about Docker,  
Git, Spring, and message-oriented middleware.

I would like to thank my fantastic wife, Marie, and my 9 year old daughter, 
Phoebe, for their daily patience regarding my passion for technology and 
the time I dedicate to it. I would also like to thank my friends and colleagues 
because a life dedicated to technology would be boring without the fun they 
bring to it.

eBooks, discount offers, and more

and eBooks.



Why Subscribe?
 f Fully searchable across every book published by Packt

 f Copy and paste, print, and bookmark content

 f On demand and accessible via a web browser


Table of Contents
Preface v
Chapter 1: Configuring a Router 1

Introduction 1
Setting up the physical network 2
Configuring IPv4 2
Configuring IPv4 permanently 4
Connecting two networks 5
Enabling NAT to the outside 8
Setting up DHCP 10
Setting up a firewall with IPtables 12
Setting up port forwarding 13
Adding VLAN Tagging 14

Chapter 2: Configuring DNS 17
Introduction 17
Setting up your system to talk to a nameserver 17
Setting up a local recursive resolver 19
Configuring dynamic DNS on your local network 21
Setting up a nameserver for your public domain 24
Setting up a slave nameserver 26

Chapter 3: Configuring IPv6 29
Introduction 29
Setting up an IPv6 tunnel via Hurricane Electric 30
Using ip6tables to firewall your IPv6 traffic 31
Route an IPv6 netblock to your local network 32


Table of Contents

Chapter 4: Remote Access 35
Introduction 35
Installing OpenSSH 35
Using OpenSSH as a basic shell client 37
Using OpenSSH to forward defined ports 39
Using OpenSSH as a SOCKS proxy 40
Using OpenVPN 41

Chapter 5: Web Servers 45
Introduction 45
Configuring Apache with TLS 46
Improving scaling with the Worker MPM 47
Setting up PHP using an Apache module 49
Securing your web applications using  
mod_security 50
Configuring NGINX with TLS 51
Setting up PHP in NGINX with FastCGI 53

Chapter 6: Directory Services 55
Introduction 55
Configuring Samba as an Active Directory compatible directory service 55
Joining a Linux box to the domain 60

Chapter 7: Setting up File Storage 63
Introduction 63
Serving files with SMB/CIFS through Samba 63
Granting authenticated access 65
Setting up an NFS server 65
Configuring WebDAV through Apache 68

Chapter 8: Setting up E-mail 73
Introduction 73
Configuring Postfix to send and receive e-mail 74
Setting up DNS records for e-mail delivery 78
Configuring IMAP 79
Configuring authentication for outbound e-mail 81
Configuring Postfix to support TLS 83
Blocking spam with Greylisting 83
Filtering spam with SpamAssassin 85


Table of Contents

Chapter 9: Configuring XMPP 87
Introduction 87
Installing ejabberd 87
Configuring DNS for XMPP 95
Configuring the Pidgin client 96

Chapter 10: Monitoring Your Network 101
Introduction 101
Installing Nagios 102
Adding Nagios users 102
Adding Nagios hosts 104
Monitoring services 105
Defining commands 106
Monitoring via NRPE 107
Monitoring via SNMP 109

Chapter 11: Mapping Your Network 111
Introduction 111
Detecting systems on your network with NMAP 112
Detecting Systems Using Arp-Scan 113
Scanning TCP ports 115
Scanning UDP ports 117
Identifying services 119
Identifying operating systems 120

Chapter 12: Watching Your Network 123
Introduction 123
Setting up centralized logging 124
Installing a Snort IDS 126
Managing your Snort rules 128
Managing Snort logging 130

Index 133


Network administration is one of the main tasks of Linux system administration. By knowing 
mail, and servers while working in large enterprise environments.

What this book covers
Chapter 1, Configuring a Router, starts by getting you to manually configure the IP address 
information on your system and then properly configure the system to bring up its interfaces 
automatically. From there, we'll move on to extending our system to act as a router for your 
own network, including DHCP for dynamically configuring client systems.

Chapter 2, Configuring DNS, will cover setting up your internal DNS server for both resolving 
external hostnames for you, as well as hosting DNS records for your own domain.

Chapter 3, Configuring IPv6, will provide a brief introduction of IPv6. We'll configure a tunnel to 
provide IPv6 connectivity, implement firewalling using iptables6, and provide IPv6 addresses 
to the rest of your network.

Chapter 4, Remote Access, will look at methods for remotely interacting with your new network 
using OpenSSH and OpenVPN.

Chapter 5, Web Servers, will set up web servers hosting PHP code, using both the Apache 
HTTPD server and NGINX.

Chapter 6, Directory Services, will tell us how to use Samba 4 to create an Active  
Directory-compatible directory service for your network.

Chapter 7, Setting up File Storage, will give us several options to explore for hosting your own 
file storage, including Samba, NFS, and WebDAV.



Chapter 8, Setting up E-mail, will tell us how to set up an e-mail server. We'll talk about how 
e-mail works as a service, set SMTP and IMAP mail services, and enable some spam filtering.

Chapter 9, Configuring XMPP, will tell us how to configure our own XMPP based IM service, 
configure it to communicate with other XMPP services, and configure Pidgin as a client to 
utilize the service.

Chapter 10, Monitoring Your Network, will tell us how to start monitoring services on our 
network using Nagios.

Chapter 11, Mapping Your Network, will cover mapping out the network in order to discover 
what is actually there.

Chapter 12, Watching Your Network, will cover watching over our network through centralized 
logging and managing an intrusion detection system using Snort.

What you need for this book
For this book you'll need a copy of Linux, preferably Ubuntu 14.04.

You'll also want access to three computers to install Linux on. One of the servers will need to 
have three network cards built into it.

For this purpose, I would strongly recommend using Virtual machines (VMs). Virtual Box  
will allow you to do this for free and is available on Windows, Linux, or OS X. You may find 
that the commercial offerings from VMWare, Parallels, or Microsoft may provide better 
performance, however.

Who this book is for
This book is targeted at Linux system administrators who have a good basic understanding 
and some prior experience of how a Linux machine operates, but want to better understand 
how various network services function, how to set them up, and how to secure them. You 
should be familiar with how to set up a Linux server and how to install additional software  
on them.




"Modify /etc/default/isc-dhcp-server to add the interface which you should  
serve requests on."

A block of code is set as follows:

auto eth0
iface eth0 inet static

Any command-line input or output is written as follows:

# ip link set dev eth0 up

# ip link show eth0

for example, in menus or dialog boxes, appear in the text like this: "Under User Functions, 
click Create Regular Tunnel. You may create up to 5 tunnels."

Warnings or important notes appear in a box like this.

Tips and tricks appear like this.

Reader feedback
develop titles that you will really get the most out of.

To send us general feedback, simply e-mail, and mention the 
book's title in the subject of your message.

contributing to a book, see our author guide at



Customer support
get the most from your purchase.

by visiting, selecting your book, clicking on 

To view the previously submitted errata, go to
information will appear under the Errata section.


Please contact us at with a link to the suspected  
pirated material.

valuable content.

If you have a problem with any aspect of this book, you can contact us at questions@, and we will do our best to address the problem.

Chapter 1


Configuring a Router

In this chapter, we will cover:

 f Setting up the physical network

 f Configuring IPv4

 f Configuring IPv4 permanently

 f Connecting two networks

 f Enabling NAT to the outside

 f Setting up DHCP

 f Setting up a firewall with IPtables

 f Setting up port forwarding

 f Adding VLAN Tagging

This chapter introduces some of the basic networking concepts and the methods to utilize 
them on Linux systems. It provides us with a good base to build upon. We're going to start 
with two computers connected with a single network cable and work our way from there to 
configure a router to connect your network to the Internet.

Routers are devices that are configured to span multiple networks and forward packets 
between them as needed. They also perform Network Address Translation (NAT) in order  
to allow your private network to share a single public IPv4 address.

Configuring a Router


Setting up the physical network
Before we start configuring the networking within Linux, we need to physically connect the 
systems. The simplest configuration involves connecting the two computers with a single 
cable, although connecting them to a switch may make more sense for additional expansion. 
Once physically connected, we need to confirm that they are working as expected.

How to do it…
On each Linux system, use the ip command to check for a network link as shown:

# ip link set dev eth0 up

# ip link show eth0

state UP mode DEFAULT group default qlen 1000

    link/ether 00:0c:29:6e:8f:ab brd ff:ff:ff:ff:ff:ff

Some people may choose to use ethtool, mii-tool, or mii-diag to perform the  
same action.

Make sure to run the same command on both the systems, especially if you're connecting to a 
switch rather than directly connecting the two systems.

How it works…
The first command brings up the network interface card (NIC). This activates the interface 
and allows it to start the process to check for a network link or electrical connection between 
the two systems.

Next, the show command gives you a bunch of information about the link. You should see a 
state showing UP. If it shows DOWN, then you have a link issue of some sort. This could be a 
disconnected/bad cable, a bad switch, or you forgot to bring up the network interface.

Configuring IPv4
Now that we've established a link between the machines, let's put some IP addresses on 
the systems so that we can communicate between them. For now, let's look at manually 
configuring IP addresses rather than auto-configuring them via DHCP.

Chapter 1


How to do it…
We need to manually configure the IP addresses using the ip command. Let's start  
with server 1:

# ip addr add dev eth0

# ip addr list eth0

state UP group default qlen 1000


    inet brd scope global eth0

       valid_lft forever preferred_lft forever

    inet6 fe80::20c:29ff:fe6e:8fab/64 scope link

       valid_lft forever preferred_lft forever

Now we need to perform the same action on server 2, but with instead  

How it works…
There are a few things in play here, so it probably makes sense to go through them one  
at a time.

First, let's start off by looking at the IP address that we're configuring. The and are a part of a series of netblocks set aside for private networks by RFC1918, IP 
Address Allocation for Private Internets. RFC1918 sets aside three large ranges, (, (, and (

For our purpose, we're configuring, which is an IP range that includes This includes 256 addresses, of which 254 are usable after setting aside as the network address and as the broadcast address. Both our  
systems get one IP in that range, which should allow them to communicate between them.

Next, we use the ip command to define an address on the eth0 device using one of 
the IP addresses in that range. You need to make sure that each machine in that range 
has a different IP address in order to prevent IP address conflicts, which would make 
communication between the two systems impossible and communication with different 
systems difficult.

Configuring a Router


Some people may be accustomed to seeing the ifconfig command rather than the 
ip command used here. While it will certainly do the job in most cases, net-tool (and its 
ifconfig command) has been deprecated by most distributions since the turn of the 
century, in favor of iproute2 and its ip command.

Once the commands have been run on both servers, you should be able to ping them from 
each other. Log in to and run the following:

# ping –c 2 –n

If everything is configured properly, you will be able to see successful ping responses at  
this point.

Configuring IPv4 permanently
In the previous section we configured the network interface, but this configuration is only 
valid while the system is up and running. A reboot will clear this configuration, unless you take 
steps to make sure that it is configured on each boot. This configuration will be specific to the 
distribution that you are running, although most distributions fall under either the Debian or 
Red Hat methods.

How to do it…
Let' see how it works in Debian/Ubuntu:

1. Add eth0 configuration to /etc/network/interfaces:
auto eth0
iface eth0 inet static

2. Bring up the network interface:

# ifup eth0

Let' see how it works in Red Hat/CentOS:

1. Add the eth0 configuration to /etc/sysconfig/network-scripts/ifcfg-

Chapter 1


2. Bring up the network interface:

# ifup eth0

How it works…
Linux distributions are configured through init systems, such as Upstart, SystemD, or 
SysVInit. During the initialization process, the interfaces, or ifcfg-eth0 files, are used 
as a configuration for the networking setup scripts. These scripts then use the same ip 
commands, or possibly ifconfig commands to set up and bring up the network interface.

Connecting two networks
For our next step, we're going to add a second interface to server 1. In addition to 
being configured on eth0, we're going to configure on eth1. The second 
interface could just as easily be, but let's make sure that the networks are 
obviously different.

The systems should be configured similar to Figure 1:



Server 1


Server 2


Server 3

Configuring a Router


How to do it…
Let's connect two networks:

1. Configure the network interface on eth1 on server 1:
# ip link set dev eth1 up

# ip addr add dev eth1

# ip addr list eth1

3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_
fast state UP group default qlen 1000

    link/ether 00:0c:29:99:ff:c1 brd ff:ff:ff:ff:ff:ff

    inet scope global eth1

       valid_lft forever preferred_lft forever

    inet6 fe80::20c:29ff:fe99:ffc1/64 scope link

       valid_lft forever preferred_lft forever

2. Connect your third system to eth1 on server 1.

3. Configure eth0 on server 3 with an IP address of
# ip link set dev eth0 up

# ip addr add dev eth0

# ip addr list eth1

3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_
fast state UP group default qlen 1000

    link/ether 00:0c:29:99:ff:c2 brd ff:ff:ff:ff:ff:ff

    inet scope global eth1

       valid_lft forever preferred_lft forever


       valid_lft forever preferred_lft forever

4. Add a default route on server 3:
# ip route add default via

5. Enable routing on server 1:
# echo net.ipv4.ip_forward=1 > /etc/sysctl.conf

# sysctl -p /etc/sysctl.conf

6. Add a default route on server 2:

# ip route add default via

Chapter 1


How it works…
When you configure an IP address on a Linux system, you automatically have a route defined, 
which states that in order to access another IP address in the same subnet, you should use as your gateway. This tells the IP stack that the system, if it exists, will be on the same 
layer as the two network segments, and that it should use ARP to determine the MAC address 
it should communicate with.

If you want to talk to a machine outside of that subnet, the system will need to know how 
to communicate with it. This is done by defining a route with a gateway IP address that you 
forward the packet to. You then depend on the gateway system to forward the packet to the 
correct destination.

Most commonly, you'll deal with a default route, which is the route that the system uses for 
any packet that is not deemed to be local. In our configuration, we tell the system that the 
default route is, which asks us to forward any non-local packets to an IP address 
configured on our server 1 box. This means that server 1 will act as our router.

You can also define more specific routes where you can explicitly define an IP address to 
forward packets to a specific IP address or subnet. This can be useful in a network where 
one router provides access to the Internet and a second router provides access to a second 
internal network.

At this point server 3, configured as, knows that IP addresses on are local and any other packet should be sent to in order to 
be forwarded. However, if you attempt to ping a system that is outside your local network (for 
example, it will not arrive. This is because routing on Linux systems is disabled by 
default and needs to be enabled on server 1 before it can forward packets. Enabling routing 
can be done by setting /proc/sys/net/ipv4/ip_forward to 1, or via sysctl, which is 
the manner in which we've chosen to set it.

Once routing is enabled, packets addressed from server 3 will be received by your router and 
forwarded to (server 2) via eth0 on the router. will receive the packet from 
your router and promptly attempt to respond. This response will fail, as server 2 does not have 
a defined route for accessing the network. This is fixed by adding a default 
route on server 2 as well, but sending to the router's interface on the network.

Now server 3 knows how to address server 2, server 2 knows how to address server 3, and 
server 1 routes packets between the two as needed. Congratulations, you have connected  
two networks.

Configuring a Router


Enabling NAT to the outside
Connecting two local networks is useful, but these days it's more common to want to connect 
a local network to the Internet. The basic concept works the same, but with the necessary 
addition of NAT. NAT rewrites your packet headers in order to make them appear as if they 
come from your router, thus effectively hiding your system's address from the destination.

How to do it…
Create a third NIC (eth2) on server 1 and connect it to your cable modem or ISP's router.

1. Configure eth2 to receive an IP address via DHCP:
auto eth2
iface eth2 inet dhcp

2. Use iptables to enable NAT on packets heading out through eth2:

# /sbin/iptables -t nat -A POSTROUTING -o eth2 \


# /sbin/iptables -A FORWARD -i eth2 -o eth0 -m \


# /sbin/iptables -A FORWARD -i eth0 –o eth2 -j ACCE PT

How it works…
In the last section, we discussed how in order for two systems on different networks to be able 
to talk to each other, they need to have routes defined which will forward packets to a router 
that can deliver the packet to the appropriate destination. The same is true on the Internet.

If server 2 attempts to contact an IP address on the Internet, for example Google's 
nameserver at, your router will pass them onto the destination. Let's give that a try:

# ping -c 2

PING ( 56(84) bytes of data.

--- ping statistics ---


No responses were received. So what went wrong here?

Chapter 1


You'll recall that I said the IP addresses that we were using were defined by RFC1918 as 
internal IP address space. Due to this, these IP addresses are not directly usable as Internet 
hosts. In our example, one of the two following things will happen:

 f Our router will send packets out of the Internet-facing interface, where it will  
travel across the Internet to our destination, which will respond to the packet.  
The response will not be able to find its way back to our system due to the  
un-routed nature of the destination.

 f Our router will send the packets out of its Internet-facing interface, where the next 
hop will drop the packets due to implementing egress filtering of traffic with invalid 
source addresses.

Iptables is a command-line tool in Linux for interfacing with the Linux kernel firewall, which is 
implemented as a part of the netfilter subsystem.

Let's break down the first command line:

 f The -t option specifies the packet matching table to use. In this case, we're going to 
use the nat table.

 f f-A indicates that the specified rule should be appended to the selected chain, 
which in this case is POSTROUTING. The POSTROUTING chain is processed after the 
kernel handles packet routing.

 f -o specifies the output interface. In our example, the eth0 interface contains the 
internal IP systems and eth2 leads to the Internet.

 f -j specifies what to do if the packet matches the rule. In this case, we're going to 
masquerade the packet (modify the IP).

Put them together and we have matching packets heading out on eth2; rewrite the source IP 
address and track it in the NAT table.

The second command is added in the -m command, which matches a packet property, in 
this case state. For the packets that came in on eth1 (from the Internet), and destined to 
eth0 (lan), check to see if they are related to or are a part of an established connection. If 
so, accept the packet and assign it to the FORWARD chain. The FORWARD chain handles any 
packet that is being passed through your router rather than the packets originating from the 
system (OUTPUT chain) or packets destined to your system (INPUT chain).

Finally, any packets that come in on eth0 (lan) and are heading out on eth2 (Internet) 
are just automatically accepted.

Configuring a Router


Setting up DHCP
You now have a router that provides Internet access to all systems behind it, but the systems 
behind it need to be manually configured with IP addresses while avoiding conflicts. You also 
need to configure them with DNS servers for resolving host information. To solve this, we're 
going to configure a DHCP server on your router to be responsible for handing out addresses.

Dynamic Host Configuration Protocol (DHCP) allows you to centralize your IP address 
management. Machines which are added to a network will issue a DHCP request asking any 
available DHCP server to provide it with configuration information including IP address, subnet 
mask, gateway, DNS server, and so on.

How to do it…
Let's set up DHCP in Debian/Ubuntu:

1. Install a DHCP server:
# sudo apt-get install isc-dhcp-server

2. Modify /etc/default/isc-dhcp-server to add the interface which you should 
serve requests on:
# sudo sed –i "s/^INTERFACES.*/INTERFACES="eth0"\


3. Modify /etc/dhcp3/dhcpd.conf to configure the network information you want  
to serve:

ddns-update-style none;
option domain-name "";
option domain-name-servers,;
default-lease-time 600;
max-lease-time 7200;

subnet netmask {
  option routers;

Chapter 1


Let's set up DHCP in Red Hat/CentOS

1. Install a DHCP server:
# sudo yum install dhcp

2. Modify /etc/dhcp/dhcpd.conf to configure the network information you want  
to serve:

ddns-update-style none;
option domain-name "";
option domain-name-servers,;
default-lease-time 600;
max-lease-time 7200;

subnet netmask {
  option routers;

How it works…
The first thing you might notice about the difference between Debian-and Red Hat-based 
systems is that in Debian-based systems, you need to explicitly define the interfaces to listen 
on, while this is not needed on Red Hat systems. This is because Red Hat has chosen to trust 
ISC DHCP's built-in restriction to only listen on interfaces that have an IP address in the same 
subnet as DHCP leases were set up for.

Let's look at the configuration for the DHCP server itself.

The first section defines the global configuration parameters:

 f ddns-update-style: This defines optional functionality to update a DNS server 
with hostnames for the machines in your network. We'll look at this option in detail 
later in the book.

 f option domain-name: This defines the domain name for your network. On Linux 
DHCP clients, this populates the search field that specifies the domain to search in 
for non-fully qualified domain names.

 f option domain-name-servers: This specifies the default DNS servers, which 
your clients should use for domain resolution. In this example, we've used Google's 
public nameserver, but you may instead want to use your ISP's nameservers or a 
different public service.

Configuring a Router


 f Max-lease-time and default-lease-time: This defines how many seconds 
the IP address can dedicate to the requesting machine. Clients can also request for a 
specific lease length. Max-lease-time puts a cap on how long they can request it for, 
while default-lease-time comes into play if they don't request a specific lease length. 
Longer leases cut down on the number of IP address changes you may experience, 
while shorter leases make sure that you don't run out of IP addresses if you have a  
lot of short-term users on the network.

 f authoritative directive: This tells the DHCP server that it is the authority for 
this particular network. Sometimes, clients that have recently had a lease on another 
network may attempt to re-request the same IP address. An authoritative server may 
send them a DHCPNAK (negative acknowledgement) to tell them that they must 
request a new IP address. If your DHCP server is not the only one on the network,  
you may set it as not authoritative in order to avoid this behavior.

The second section is the subnet declaration. Your DHCP server must know about all the 
subnets configured on the interface that it has been told to serve DHCP addresses on. For the 
subnets on which it should serve addresses, you should define the range of IPs to hand out 
and you most likely want to define your network gateway as well. If your machine has multiple 
IP addresses on the interface and you only want to serve IPs to one of them, you should still 
define the subnet, but leave out the range and gateway information from within the brackets. 
For example:

subnet netmask {

Now that your DHCP server is configured, it will automatically hand out the IP addresses 
to all machines that connect to the network which are configured to request addresses via 
the DHCP protocol, which is often the default. It will keep track of these leases in a human-
readable format in /var/lib/dhcpd/dhcpd.leases, in order to avoid having multiple 
machines receive the same address.

Setting up a firewall with IPtables
We touched upon iptables a little while discussing NAT, but now we're going to go a bit 
deeper into configuring a secure firewall for your network.

How to do it…
A properly configured firewall should be configured in a default deny configuration with specific 
allows (Whitelist) for what you want to accept:

# iptables -A INPUT -i lo -j ACCEPT 



Chapter 1


# iptables -P INPUT DROP 

# iptables -P FORWARD DROP

# iptables -P OUTPUT ACCEPT

# iptables -A FORWARD -i eth0 -j ACCEPT

# iptables -t nat -A POSTROUTING -o eth2 \


# iptables -A FORWARD -i eth2 -o eth0 -m \


# iptables -A FORWARD -i eth0 -j ACCEPT

How it works…
We start off by setting an ACCEPT policy on traffic destined to the local system on the 
localhost adapter (-i lo). A lot of software expects to be able to communicate over the 
localhost adapter, so we want to make sure we don't inadvertently filter it.

Next, we set an ACCEPT policy for any packet that matches a state (-m state) of 
ESTABLISHED, RELATED. This command accepts packets which are a part of, or related to, 
an established connection. ESTABLISHED should be pretty straightforward. RELATED packets 
are special cases that the connection tracking module needs to have a prior knowledge of. 
An example of this is the FTP protocol operating in active mode. The FTP client in active mode 
connects to the server on port 21. Data transfers however, operate on a second connection 
originating from the ftp server from port 20. During the operation of the connection, the port 
21 packets are ESTABLISHED, while the port 20 packets are RELATED.

The third command accepts any TCP connection (-p tcp) destined for port 22 (--dport 
22) that is destined for your system. This rule allows you to SSH into the machine.

Next, we will define the default policies. By default, we drop packets on the INPUT and 
FORWARD chains and accept packets on the OUTPUT chain.

The last three lines you'll recognize from the NAT section, which tells the firewall to allow any 
packets starting on the internal network and heading out to the Internet.

Additional ACCEPT rules based upon destination ports can be opened as needed as INPUT 
lines, like the port 22 one.

Setting up port forwarding
In the previous section, we configured iptables to accept connections to port 22 in order to 
allow people to SSH into the host. Sometimes, you want to forward a port to a system behind 
the firewall instead of having the service run on the firewall itself. For example, you may have 
a web server running on port 8080 on an internal box that you want to expose to the Internet 
via port 80 on the firewall.

Configuring a Router


How to do it…
1. Rewrite packets addressed to port 80 to instead go to port 8080:

# iptables -t nat -A PREROUTING -p tcp -i eth2 --dport 80 \

-j DNAT --to-destination 

2. Accept any packets addressed to port 8080:

# iptables -A FORWARD -p tcp -d \

--dport 8080 -m state --state NEW,ESTABLISHED,RELATED \


How it works…
This example is a lot simpler since it builds upon concepts we've already learned. We just 
have two simple commands:

 f First we set up a PREROUTING rule which will be processed once the packet is 
received, prior to any routing rules being applied. If the packet is TCP and came in on 
the Internet interface (eth2) with a destination port, then the packet is added to the 
destination NAT (DNAT) chain with a final destination of port 8080.

 f Next, any packet destined for port 8080 is either a new connection  
or an established connection; the packet is then accepted for forwarding to  
the destination.

Adding VLAN Tagging
Right now we have a rather simple network configuration. We have a single router with a 
public-facing IP address on one interface and a private IP address on the second interface. 
But what if we want to have multiple private networks behind the route?

Our first option in this scenario would be to add additional IP addresses to the internal 
interface. The ip command allows you to assign multiple IPs to a single interface, with 
optional interface aliases like eth0:0. This will allow you to assign IP addresses to systems 
behind the firewall within one of the few ranges and have them all route appropriately.

The downside of this approach is that all the internal IPs exist within the same collision 
domain of the network. This has a few implications, including the ability to move systems 
between those IP ranges and potentially bypassing access control rules, as well as problems 
assigning addresses via DHCP due to confusion about what address range to hand out.

Chapter 1


The second option would be to put a third network card in the router and then either plug the 
additional card into a dedicated switch or separate out the existing switch into multiple VLANs 
and plugging the new network card into a port on a dedicated VLAN for that network. The 
downside here is the additional cost of the NIC (assuming you have space to add it) and then 
either the usage of an extra switch port or an extra switch.

The third option is to configure the switch into dedicated VLANs and plug the LAN side of your 
router into a port configured as a trunk. From there, Linux can be configured to use VLAN 
tagging to split your single physical interface into a pair of virtual interfaces and tag packets, 
as appropriate, so that the switch automatically adds them to the appropriate VLAN.

How to do it...
There are two steps required in order to use VLAN tagging on your Linux server:

1. The first is to hook it up to a switch that has VLAN enabled, connected to a port 
which is allowed to act as a trunk. The specifics around how to configure a switch in 
this mode are outside of the scope of this book, since they are specific to the switch 
itself. You'll want to find a managed switch which supports the 802.1Q standard and 
consult its documentation for configuration.

2. The second thing you'll need is to create virtual interfaces assigned to the desired 
VLAN. In our case, we're going to create two virtual interfaces, which are assigned to 
vlans 1 and 2.

# ip link add link eth0 name eth0.1 type vlan id 1

# ip link add link eth0 name eth0.2 type vlan id 2

Now that they exist, you can treat them like normal network interfaces and configure them as 
we did in the section on adding a second network.

Note that eth0.1 is a naming convention, not a requirement at this 
point. You could instead choose to name the interfaces names wireless 
and wired if you wanted to.

Making this change permanent can be rather distribution specific and may depend on the 
use of the vconfig command, which is distributed through the VLAN package on Debian/
Ubuntu. Debian-based distributions will automatically create VLAN interfaces if you specify an 
interface in /etc/network/interfaces which is named as a physical interface, followed 
by a period, and then a VLAN ID, as eth0.1 is our example.

Configuring a Router


How it works...
VLAN tagging, as defined by the 802.1Q standard, functions at the Ethernet layer level. A 
standard Ethernet frame contains 4 fields, the destination MAC address, the source MAC 
address, the EtherType or length field (depending on the type of frame), the data (the IP 
packet), and a frame check sequence (FCS). 802.1Q works by adding a VLAN tag  
between the source MAC address and then the EtherType/length field.

A switch that supports 802.1Q may have one or more network ports that are configured to 
act as a Trunk. Trunk ports will accept VLAN tagged packets and will pass them along as 
appropriate. They will detect the specified VLAN tag, determine the appropriate VLAN the 
packet is destined to, and will deliver the packet to any switch ports that are on that VLAN. 
Tagged packets can even pass between multiple switches as long as they are properly 
configured. If a packet is received without a tag on it, it will have a tag added automatically, 
based upon the VLAN associated with the switch port it was received on.

Chapter 2


Configuring DNS

In this chapter, we will cover:

 f Setting up your system to talk to a nameserver

 f Setting up a local recursive resolver

 f Configuring dynamic DNS on your local network

 f Setting up a nameserver for your public domain

 f Setting up a slave nameservers

This chapter introduces the Domain Name System (DNS). You'll learn what DNS is, how 
it works, and how to configure it to work according to your requirements. We'll start by 
configuring your machines to be able to resolve hostnames, such as  
and we'll work toward learning to configure your own domain.

Setting up your system to talk to a 

In the previous chapter, we did some basic testing of your network connection by pinging other 
hosts by IP address directly. However, I'm sure you'd rather not visit web pages by requesting 
them by IP address, rather than by the domain name. This problem is solved using a recursive 
DNS server to resolve the hostnames into IP addresses, which your computer can then 
connect to.

Configuring DNS


How to do it…
Let's set up a DNS server to resolve the hostnames into IP addresses:

1. Configuring Linux to use a DNS server is very easy. Just add a single line to /etc/

2. You may also want to add a domain line, which will allow you to access things by their 
hostname rather than by their fully qualified domain name (FQDN). For example, 
domain in resolv.conf will allow you to ping 
as just mail.

If your system uses DHCP for receiving its IP address, then the content of this file can be 
managed through the configuration of the DHCP server. This makes easier management of 
nameserver IPs and domains on your network possible.

How it works…
The nameserver line in /etc/resolv.conf provides the IP address of a nameserver that 
your system is allowed to query against. In this particular example, we're using, which 
is a publicly available recursive DNS server owned and operated by Google. You may also want 
to consider using a nameserver provided by OpenDNS or one provided by your ISP. A properly 
configured recursive nameserver is restricted to only allow queries from the intended users, 
so you'll want to make sure that you're either using one intended for the general public or one 
intended specifically for you.

When your system attempts to contact a site, such as, the browser will 
attempt to see if the matching IP address already exists in the browser's hostname cache.

If it does not, it issues a gethostbyname request to the local C library, which then checks 
its local configuration in /etc/nsswitch.conf to determine how lookups should be 
performed. You may find something similar to hosts: files dns in that file, which 
indicates that for finding host information, you should first look at local files, such as  
/etc/hosts, and you should check DNS if that fails.

Assuming that you didn't have a matching entry in /etc/hosts, your C library's stub DNS 
resolver will look in /etc/resolv.conf for the IP address of your DNS server and will 
then send a DNS query with recursion enabled over UDP port 53 to the listed DNS server. 
The server will check its local cache for an answer and will issue queries to the various 
authoritative nameservers, starting with the nameservers of the DNS root (.), followed by 
org, and then finally, example. The nameservers, for example, will pass back the IP address 
associated with to your recursive nameserver, which will then pass it 
back to you.

Chapter 2


Setting up a local recursive resolver
Since all attempts to access a website require that you look up the hostname, the 
responsiveness of your nameserver can have a large impact on the loading of a webpage.  
A slow nameserver can delay the initial loading of the webpage as well as the loading of  
the various embedded images, video, and JavaScript, which might have been pulled  
third-party sites.

In this section, we'll be looking at setting up our own recursive nameserver, which will help  
cut down on the round trips between you and your resolver. We will additionally configure  
it to forward uncached queries to a public recursive nameserver in order to take advantage  
of their caching.

How to do it…
Let's set up the local recursive resolver:

1. Install bind9 on Ubuntu; this can be done with sudo apt-get install bind9. 
On Red Hat and CentOS, it can be done with yum install bind instead. For other 
distributions, consult the relevant documentation.

2. Add an allow-recursion entry in the options section of the bind9 configuration in 
order to prevent it from being used for denial of service attacks:
allow-recursion {;

3. Consider listening to only your internal IP address with the following option:
listen-on {;

4. If you want to use a forwarders, add the following to your options section:

forwarders {;;

Configuring DNS


How it works…
While your mileage may vary from distribution to distribution, bind9 is often distributed 
with a default configuration that acts as a recursive nameserver with no restrictions on who 
can issue queries against it. This sort of configuration can be abused by people looking to 
perform a DNS-based amplified denial of service attack by sending you a spoofed UDP packet 
containing a request, which results in a large response. This causes you and a large number 
of other servers to send the large responses to the DoS target.

The allow-recursion setting that we've provided tells bind9 to only answer to recursive 
queries from your local network and the special localhost variable that includes all IP 
addresses configured on the server itself. Once this setting is in place, the server will respond 
to these queries with a short refused response rather than a potentially large data response.

listen-on takes restrictions one step further by allowing you to tell the server to not bind to 
particular network interfaces at all. If you're running on a router with multiple interfaces, you 
can choose to have bind9 to only listen on the internal interface. Depending on your firewall 
configuration, this means that someone sending a request on an external interface will either 
get an ICMP destination port unreachable message or no response at all.

Finally, the forwarders' setting configures a list of DNS servers that you can go to in the event 
that it does not already have an entry cached. In this case, we're using the two public Google 
servers again, but you can choose to use your ISP's nameservers instead.

There's more…
There's one additional piece of information that is very useful to know if you are planning on 
running your own DNS server. As previously noted, the DNS protocol typically operates over 
UDP port 53. This is due to the low overhead nature of the UDP protocol, which does not 
require any sort of handshake to create and then tear down the connections. Over UDP, DNS 
is able to issue a single packet for a request and mostly receive a single packet as a response.

You may note that I said typically. Due to a limit on the maximum size of a UDP DNS request 
or response packet, the protocol can switch to TCP instead. The maximum size of a DNS 
request/response is 512 bytes unless EDNS0 is being used to increase the size to 4096 
bytes. Any packet larger than those sizes will trigger a switch from UDP to TCP by the server 
sending a partial packet with the truncated bit set.

While a majority of DNS traffic that you'll see will be UDP, keep in mind that during 
troubleshooting and firewall rule writing, you may see TCP as well.

Chapter 2


Configuring dynamic DNS on your local 

Right now you get your IP address configured automatically via DHCP and you're able to 
resolve DNS records from the internet via your DNS server. With the use of Dynamic DNS,  
you can also leverage your DNS server to address your local systems by name as well.

How to do it…
Let's configure dynamic DNS on your local network:

1. First, we need to configure your bind instance to host DNS for your internal domain, 
as well as reverse DNS for your IP range. For our example, we'll use a domain of
zone "" {         
  type master;
  notify no; 
  file "/var/lib/bind/";
zone "" {      
  type master;
  notify no; 
  file "/var/lib/bind/"; 

2. Next we populate the zone in  IN  SOA (
)     IN      NS
router    IN      A

Configuring DNS


3. Then we populate the reverse zone in
@ IN SOA (
IN    NS 
1                    IN    PTR

4. In order to connect the DHCP and DNS services, we need to generate a HMAC key for 
securing the communication. This can be completed by executing dnssec-keygen 
-a HMAC-SHA512 -b 512 -r /dev/urandom -n USER DDNS. This command 
will generate a pair of files named Kddns_update.+NNN+NNNNN.private and 

5. Create a file called ddns.key and insert the following content with <key> replaced 
by the string marked Key: in the .private file:
key DDNS {
  algorithm HMAC-SHA512;
  secret "<key>"; 

6. Copy ddns.key to both /etc/dhcp and /etc/bind with the proper permissions 
using the following:
# install -o root -g bind -m 0640 ddns.key \
# install -o root -g root -m 0640 ddns.key \

7. Tell bind about the DDNS updating key by adding it to /etc/bind/named.conf.
include "/etc/bind/ddns.key";

8. Then tell bind to allow updating of the zones you previously created by adding an 
allow-update entry to your zones so that they look similar to the following:
zone "" {         
  type master;
  notify no;
  file "/var/lib/bind/";
  allow-update { key DDNS; };

Chapter 2


9. Now we need to update the DHCP server to have it hand out your nameserver instead 
of Google's and send hostname updates to your DNS server using the correct key:

option domain-name "";
option domain-name-servers;
default-lease-time 600;
max-lease-time 7200;
ddns-updates           on;
ddns-update-style      interim; 
ignore                 client-updates; 
update-static-leases   on;
include "/etc/dhcp/ddns.key"; 

subnet netmask {
  option routers;
zone EXAMPLE.ORG. {   
  key DDNS; 

zone {   
  key DDNS; 

How it works…
Bind/named supports the ability to dynamically update DNS records through the use of 
clients, which are configured to sign the update messages using HMAC. The server is able 
to validate the authenticity of the messages by performing the same hashing operation that 
the client had performed with the same shared key. If the hash value sent by the client with 
the message matches the hash value calculated locally by the server, then we know that the 
client and server both have the same shared key.

This dynamic update feature can be leveraged to create/modify DNS records on the fly using 
the nsupdate command. In our case, we're going to have ISC DHCPD send the update 
commands directly, as new hosts are found.

Configuring DNS


As a system requests an IP address through the DHCP protocol, the client includes its 
hostname as a part of the initial discovery request. This hostname is recorded as a part of the 
lease. When ISC DHCP is set up for DDNS, it issues a DNS update request to the configured 
DNS server. Now your system is resolvable by other clients, at least until its lease expires.

Setting up a nameserver for your public 

Setting up a nameserver for a public domain works the same way as setting up a DNS server 
for an internal hostname, just with a few additional parts that we'll want to make sure are in a 
good state.

How to do it...
Let's set up a nameserver for a public domain:

1. Set up a properly configured SOA record:  IN  SOA (

2. Set up a record for NS hosts:
Ns1    IN      A

3. Set up glue records:

       IN      NS
Ns1    IN      A

How it works…
The first step is to configure the start of authority (SOA) for your domain. The SOA provides 
basic information about the zone itself. It contains a number of fields, including:

 f The zone.

 f IN: Class of the record. IN is Internet, which you'll see for the majority of DNS records 
that you see.

Chapter 2


 f SOA: Start of authority.

 f This is the primary/master DNS server for the zone.

 f This is the responsible party for the domain. This should be 
an e-mail address with the @ character changed to a (.). So in this example, admin@ should be contactable.

 f 2015081401: This is the serial number of the zone. This is a 32-bit integer, which 
should increment when the zone changes. If the primary DNS server is not configured 
to notify slaves of changes, the slaves will automatically perform a zone transfer 
when this value increases. Using a numeric date for the serial is a common practice.

 f 28800: This is the refresh period. It defines how often a slave should contact the 
master in order to check for updates of the serial number. You might see warnings  
if this value is less than 20 minutes or greater than 12 hours.

 f 3600: Retry period. If a slave server cannot contact its master, how often should  
it retry?

 f 604800: Expire period. If retries have failed beyond this period of time, the slave 
server will stop acting as an authority for the domain.

 f 38400: This is the minimum/default TTL value. According to the RFC, this defines 
the lowest possible TTL value for a record in the zone. In practice, most DNS server 
implementations treat this as the default TTL value for records which do not set  
it explicitly.

The next two items define the same information in two separate places. NS records point to 
the A record for the DNS server, which is authoritative for the zone. For example, ns1.example.
org is authoritative for the zone. That, however, leaves a bootstrapping problem in 
which the A record for is defined within the zone file.

The solution for this bootstrapping issue is to use glue records. Glue records are stub records 
that exist at the point of delegation and define NS records for a zone as well as their matching 
A records. These values will be overridden by the records provided by the zone itself.

A good example of glue records comes when you register a domain. In our example domain, is delegated by the .org DNS infrastructure. Your domain registrar should 
provide you with a mechanism to add NS records and their matching A records on the  
.org servers.

Since the glue records are managed outside of your zone, they're very easy to neglect when 
updating your DNS infrastructure. If your name servers are changing, you'll want to change 
them in the zone as well as in the glue records.

Configuring DNS


Setting up a slave nameserver
The nameserver infrastructure that we've configured so far is sufficient to get the domain 
to function, but it is currently a single point of failure. In order to deal with your existing 
nameserver being unreachable for some reason, we're going to want to add at least one 
additional nameserver for your network.

Now, maybe your initial thought would be to configure the nameservers identically and create 
some method to synchronize the zone files across the systems. Luckily, this isn't needed. 
Rather, bind/named can handle the synchronization internally, through the use of zone 
transfer (AXFR) requests or incremental zone transfer (IXFR) requests secured with the same 
type of HMAC keys utilized by the DHCP server to send updates to the DNS server. Rather than 
making changes to a single record though, zone transfers send the entire zone file, including 
all records.

How to do it…
1. Generate another HMAC key to use in authenticated zone transfers:


2. Create a file called transfer.key and insert the following content with <key> 
replaced by the string marked Key: in the .private file. Copy it to /etc/bind on 
both the master and slave servers:
algorithm HMAC-SHA512;
secret "<key>"; 

3. Include transfer.key on both the master and slave servers in /etc/bind/
include "/etc/bind/transfer.key"; 

4. Modify the zone definition on your master server to send notifications of changes to 
the slave and allow transfers:
zone "" {         
type master;
notify yes; 
file "/var/lib/bind/";
also-notify {; }; // Slave server IP
allow-transfer { key TRANSFER; }; 
allow-update { key DDNS; };

Chapter 2


5. Configure bind9 on your second server to be a slave for your zone, and tell it to use 
the TRANSFER key for communicating with your master server:

zone "" {   
type slave;   
masters {; };
file "/var/lib/bind/"; 
server { 
keys { TRANSFER; }; 

How it works…
Zone transfers use the same HMAC-based communication method (TSIG) that is used for 
updating zones by the DNS server. In order to implement the least privilege, we do want to  
use a different key set, though. There is no reason for a slave server to have write access 
to the master in our use case. Additionally, we may not want the DHCP server to be able to 
download the complete zone file.

The rest of the configuration has to make do with telling the master to notify the slave in  
the event of a change and having the slave know how to trigger a transfer as well as serve 
DNS requests.


Configuring IPv6

In this chapter, we will cover configuring IPv6 on your network. Specifically:

 f Setting up an IPv6 tunnel via Hurricane Electric

 f Using ip6tables to firewall your IPv6 traffic

 f Route an IPv6 netblock to your local network

The IPv4 protocol used on the Internet today was first deployed on ARPANET in 1983.  
It uses 32 bit addresses, which limits the number of IP addresses to 4,294,967,296.  
While this may seem like a lot, that number is being rapidly depleted, even with the  
boost that NAT provided us.

The replacement, IPv6, improves on IPv4 by switching to 128 bit addressing, which should 
provide enough IP address space for the foreseeable future. It also makes a number of other 
improvements including auto-configuration of addresses, simplified processing for routers due 
to more standardized sizes for packet headers, and additional areas as well.

Even with those improvements, and the impending IPv4 exhaustion, IPv6 has had an 
extremely slow rollout. The initial design was completed in 1998 but as of the end of 2009 the 
percentage of users who visited Google with IPv6 connectivity was below 0.25%. Since 2009, 
adoption has accelerated, with the user saturation increasing from less than 3% to more than 
5% in 2014 alone. In mid-2015, the rate was above 8%.

Part of the issue is the incompatibility between the two protocols. You can consider IPv6 a 
completely separate protocol, which may operate in parallel with IPv4. In order to cope with 
this reality, networks typically roll it out in a dual stack configuration where systems have IPv4 
and IPv6 addresses and provide a preference to one or the other depending on needs.

Configuring IPv6


Depending on your ISP, you may find that you already have a dual protocol network stack 
enabled. We're going to start off by assuming that this is not already in place, and we will 
set up IPv6 networks using one of the existing public tunnel providers which provide IPv6 
connectivity tunneled over IPv4. You can think of it as being similar to a VPN.

Setting up an IPv6 tunnel via Hurricane 

Hurricane Electric is a major backbone and colocation provider based in the US. In addition to 
their hosting/transit services, they also host, another free IPv6 tunnel 
provider, and, a training and certificate site for 
learning about IPv6 networking.

Unlike AYIYA tunnels from SixXS, IPv6 tunnels from Hurricane Electric operate over IP protocol 
41, which is defined by the IPv6 Encapsulation protocol (RFC2473). This is a separate protocol 
from ICMP, TCP and UDP.

The downside of this approach is that it does not operate over NAT firewalls natively. This may 
be an issue if your new firewall device is operating behind an ISP firewall with its own NAT.  
The ability to forward protocol 41 traffic to a machine behind the NAT is device specific and 
does not work on all firewalls.

How to do it…
1. Visit and click Sign up now!, and sign up for a  

Free account.

2. Under User Functions, click Create Regular Tunnel. You may create up to 5 tunnels.

3. Enter your IP address under IPv4 endpoint.

4. Select a tunnel end point which is close to you.

5. Collect the local and remote IPv4 and IPv6 addresses provided by HE's website, and 
use them to populate your configuration.

6. For Ubuntu/Debian systems, you can then configure the interface in  
/etc/network/interfaces, the code is as follows:
auto he-ipv6
iface he-ipv6 inet6 v4tunnel
        address CLIENTIPv6
        netmask 64
        endpoint SERVERIPv4
        local CLIENTIPv4
        ttl 255
        gateway SERVERIPv6

Chapter 3


7. For configuring on the command line, you can use:

modprobe ipv6
ip tunnel add he-ipv6 mode sit remote SERVERIPv4 local LOCALIPV4 
ttl 255
ip link set he-ipv6 up
ip addr add LOCALIPv6 dev he-ipv6
ip route add ::/0 dev he-ipv6
ip -f inet6 addr

How it works…
Hurricane Electric IPv6 tunnels use the standard 6in4 Tunnel Protocol (RFC4213) that's 
built automatically into both net-tools (ifconfig) and iproute2 (ip command). Additionally, 
Debian and Ubuntu have support for 6in4 built directly into their network initialization scripts, 
which allow for simplified configuration.

 f ip tunnel add he-ipv6 mode sit remote SERVERIPv4 local 
LOCALIPV4 ttl 255: This command adds a Simple Internet Transition (SIT) tunnel, 
which is represented as an interface named he-ipv6. SIT tunnels require that you 
provide both the local and remote ipv4 addresses.

 f ip link set he-ipv6 up: Bring up our new he-ipv6 interface

 f ip addr add LOCALIPv6 dev he-ipv6: Assign your local ipv6 address to  
that interface.

Using ip6tables to firewall your IPv6 traffic
Firewalling IPv6 traffic on Linux is handled by the ip6tables command. This tool is the IPv6 
version of the iptables command we've already used, and it operates in almost exactly the 
same manner. The big difference is that with IPv6 the use of NAT is highly discouraged.

How to do it…
Let's run the command to establish.

# ip6tables -6 -A INPUT -i lo -j ACCEPT 
# ip6tables -6 -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 
# ip6tables -6 -A INPUT -p tcp --dport 22 -j ACCEPT
# ip6tables -6 -P INPUT DROP 
# ip6tables -6 -P FORWARD DROP
# ip6tables -6 -P OUTPUT ACCEPT
# ip6tables -6 -A FORWARD -i eth0 -j ACCEPT
# ip6tables -6 -A FORWARD -i eth1 -o eth0 -m \

Configuring IPv6


How it works…
The ip6table rules here are identical to the iptables rules in Chapter 1, Configuring a 
Router with a few exceptions:

 f A lack of NAT

 f -6 options

NAT was initially created to deal with the problem of a limited supply of IPv4 addresses. Over 
time, people began to think of NAT as a security control, which was not its intended purpose. 
The use of NAT additionally introduces a number of protocol specific problems, and a variety 
of IP range conflicts when connecting multiple internal networks which may use overlapping 
RFC1918 address ranges.

With IPv6 we have plenty of IP addresses to be allocated, so the best practice is to instead 
depend on host and network firewalling as well as secure configuration of services rather  
than depending on the use of NAT to obscure access to systems.

The -6 option does not do anything in ip6tables. In iptables however, the -6 option tells the 
command to ignore the option. Similarly, there is a -4 option in iptables which does not 
have any effect, but will tell ip6tables to ignore the command.

The beauty of this configuration is that you can then have a single rules file that can be 
processed by both iptables and ip6tables and each command will only take action  
against the rules that it should pay attention to.

Route an IPv6 netblock to your local 

So far, all we've done is allocate a single IPv6 address to your machine that is hosting the 
tunnel. One of the nice things about IPv6 however, is the ability to obtain a large number of 
public IP addresses for your local networks rather than using NAT. In fact, Hurricane Electric 
and SixXS both offer complementary /48 networks to use with your tunnel. A /48 includes 
2^80 IP addresses, or 1,208,925,819,614,629,174,706,176. Much better than the one 
IPv4 address you typically get from a consumer IP address. To utilize them, you just need to 
advertise their availability.

Chapter 3


How to do it...
Install radvd via your package management system:

1. Configure /etc/radvd.conf:
interface eth1
   AdvSendAdvert on;
   prefix 2001:DB8:1:1::/64

2. Start radvd via the init script or as appropriate for your distribution.

How it works…
Rather than requiring DHCP for IP address allocation (although DHCPv6 is available if 
desired), IPv6 implements the Neighbor Discovery Protocol (NDP) as defined by RFC 2461. 
NDP uses multicast on the link layer to discover neighbors and routers on the local network 
and can allow client systems to auto configure addresses for themselves based upon what 
address ranges local routers are advertising.

The Router Advertisement Daemon, or radvd, is an open source implementation of the 
Neighbor Discovery Protocol. The simple configuration that we provide here advertises the 
2001:DB8:1:1::/64 network on eth1. 2001:DB8:1:1::/64 is part of a larger /32 network 
which is made available for documentation purposes. You should instead replace this value 
with the /64 network that you obtained from SixXS, Hurricane Electric, or your ISP.


Remote Access

In this chapter, we will cover the following points:

 f Installing OpenSSH

 f Using OpenSSH as a basic shell client

 f Using OpenSSH to forward defined ports

 f Using OpenSSH as a SOCKS proxy

 f Using OpenVPN

One of the nice things about having a Linux network is the ability to access it remotely in  
a secure manner. Best of all, you have a number of options available to you depending on  
your needs.

Installing OpenSSH
Our first option for remote access is the simplest, assuming that you just need to be able to 
remotely access a shell on your Linux system. All Linux distributions offer the ability to install 
a Secure Shell (SSH) server. The most common SSH server available is OpenSSH, which is 
distributed by the OpenBSD team. A lighter weight option called Dropbear is also available  
and is often found in embedded Linux platforms, such as OpenWRT.

Remote Access


How to do it…
Installing OpenSSH on a Linux system is very easy but the specifics on how to do it will depend 
on the Linux distribution that you are using.

Let's install SSH server in Debian/Ubuntu through the following command:

# sudo apt-get install ssh

For Fedora, CentOS, and other RedHat derivatives, it would be sudo yum install 

Now, once OpenSSH is installed, anyone with network access to tcp port 22 on your system 
may attempt to log in to your system. If this machine is your firewall or if you forward port 22 
from your firewall to this box, it could potentially mean anyone on the Internet. In fact, if this is 
the case, you can expect to see the attempt to log in to your system using common usernames 
and passwords within hours of installing the package. There are a few common steps that you 
should take in order to avoid being the next victim to have their system attempting to brute 
force the world. The steps are:

 f Use strong passwords. When you first installed your Linux distribution, did you use 
a trivial password like password or any other dictionary words? Or worse, have no 
password at all? If this is the case, then you can expect to be exploited quickly. This 
also applies to system accounts that you may have created for a manually installed 
software package or web service.

 f Restrict who can log in sshd_config, which is in /etc/ or /etc/ssh/. The  
default is to allow logins for all users. On a minimum, you can disable root logins by 
setting PermitRootLogin number. For more control, you can choose to supply a 
comma separated list of usernames to AllowUsers in order to limit logins to just 
those users.

 f You may choose to additionally move SSH to a non-standard port using the Port 
definition in sshd_config. This option will not provide any protection against a 
determined attacker, but will at least limit noise from SSH brute force attacks since 
they're typically performed with a script limited to the default ssh port of 22.

 f Another method to deal with bots is with the using a tool that monitors failed logins 
and uses firewall rules to block access for repeat offenders. This will limit the scope 
of their attack attempts to a configurable number of login attempts. A few tools that 
implement this method are fail2ban and DenyHosts.

 f Finally, for a high value system, you can consider using SSH keys rather than 
passwords for logins. This allows you to replace fairly weak passwords/passphrases 
with SSH public keys using RSA, DSA, or ECDSA cryptography, which are not  
feasible to attack. Note that this would need to be used in conjunction with  
disabling password authentication in sshd_config or it will not provide any 
additional security.

Chapter 4


How it works…
Once installed, OpenSSH listens on TCP port 22 and allows authenticated SSH clients to 
connect and perform a number of actions including the following:

 f Obtaining a shell (the most common usage)

 f Forwarding defined TCP ports from the client to the server or vice versa, including 
ports on remote systems.

 f Dynamically forwarding TCP ports by acting as a SOCKS proxy for any application that 
supports SOCKS4 or SOCKS5.

 f Forwarding X11 applications from the remote system to display on your local system.

 f Copying files using scp (secure copy) or sftp (secure file transfer program).  
Note that sftp is different than ftps, which is the much older FTP protocol  
operating over SSL.

 f Acting as a layer 2 or layer 3 VPN.

The server provides a public cryptographic key upon login that can be used to validate that 
the server is what you expect it to be. While there is no public CA infrastructure like you'd have 
with TLS in order to validate the authenticity of the server, you can either choose to trust the 
server certificate on first login and inspect for changes to the key or you may share the public 
key via an external secure channel prior to your login.

For login authentication purposes, the sshd daemon either requires read access to /etc/
passwd and /etc/shadow or more commonly ties into your system's PAM (Pluggable 
Authentication Modules) system, which provides a layer of abstraction between services  
and the actual authentication system under the covers.

As mentioned in the preceding section, you may also choose to use SSH keys, which leverage 
PAM for user account information but will require the user to have a private key that matches 
a public key specified in ~/.ssh/authorized_keys. You can read more about the use of 
public key cryptography with SSH by running man ssh-keygen.

Using OpenSSH as a basic shell client
You have a number of client options if you're looking to access a shell on a system running an 
SSH daemon.

Remote Access


How to do it…
If you are connecting from another *nix system, such as Linux or Mac OS X, you can launch a 
terminal and use the SSH command-line tool from OpenSSH:

 f A free graphical SSH client called PuTTY is available for Linux, Mac, and Windows. 
PuTTY provides you a terminal on the remote system rather than providing any form 
of local shell access. Windows binaries and the sources to build *nix clients can be 
obtained at

 f Various SSH clients are also available for Android and iOS devices.

How it works…
The OpenSSH client available on the terminal from systems similar to *nix is the simplest 
approach. Simply launch on your Mac or an xterm on your Linux system and 
run ssh username@host. If the username@ is omitted, then the ssh client will attempt 
to log in using your local username. The host may be a valid DNS record or an IP address. 
You may optionally supply a port with –p PORT in the event that you have your SSH daemon 
running on a non-standard port.

PuTTY, on the other hand, provides a graphical manner to supply the host information:

Chapter 4


Upon login, you will be prompted for the username and password. Alternatively, the username 
may be supplied in advance under the Connection | Data section of the menu.

Using OpenSSH to forward defined ports
One extremely useful piece of functionality is the ability to forward ports from the remote 
system to your local system or vice versa.

How to do it…
 f Forward a remote port locally: –L 8000:

 f Forward a local port remotely: –R 5000:localhost:22

 f Make either port available from remote systems with –g

How it works…
The –L option allows you to make a remote port available locally. The arguments are  

Remote Access


In our example, we're logging into a remote system and then forwarding port 80 on of your local system. This means that if you connect your web browser to 
localhost port 8000, you will actually be hitting the server on This is useful 
for accessing resources behind a firewall or just changing the network your connection is 
established from. Note that if you're specifically using this for a web server, you may need to 
play tricks with your host files or ports in use in order to work around web applications that 
expect the correct Host header or attempt to redirect your connection to a specific port. You'll 
also want to note that binding to local ports under 1024 require that you run as root, which is 
why we've forwarded port 80 to port 8000 locally. If you need to make it available on port 80 
instead, you will need to run as root using sudo.

The -R option works the same way with the same arguments, but makes a local network port 
accessible on the remote side instead. In our example, we're taking localhost port 22 and 
making it available on port 5000 on the remote system. This would allow users of the remote 
system to log into your local system by specifying port 5000 to their SSH client.

The default behavior for both of these commands is to bind to a localhost so that only local 
users may have access to connect to the remote resource. This may be changed with the 
–g option, which tells the ssh client to bind to all addresses instead, making the forwarded 
port available to anyone who is able to establish a connection to it. Be sure that you fully 
understand the security implications of this option before you use it.

Using OpenSSH as a SOCKS proxy
If you're looking to access webpages through an SSH proxy, you may find that the –L option is 
a bit too limiting, since you need to specify each individual web server that you're forwarding 
and give each one its own local port.

If your remote network contains an HTTP proxy like Squid or Apache's mod_proxy, then you 
may choose to forward the port of that proxy server. If you don't have one available, then 
consider using OpenSSH's built in SOCKS proxy functionality.

How to do it…
Enabling the SOCKS proxy is trivial. Just specify –D 8000 where 8000 is the local port that 
you want to configure the clients to use. Then just configure your client to use that port as a 
SOCKS proxy. For some clients, you'll need to explicitly tell them to use remote DNS if you're 
connecting to resources which are not remotely resolvable.

The following screenshot will show you how to configure this in a modern version of Firefox. 
The actual configuration of a SOCKS proxy will vary based on the software.

Chapter 4


How it works…
Once you have a port set up as a SOCKS proxy, it listens for valid SOCKS proxy requests. Once 
received, the SSH client forwards the request on to the SSH daemon, which then establishes 
a connection to the remote system. The SSH client and daemon then work together to forward 
the requests and responses back and forth between the client and server.

This functionality can be incredibly useful if you are on an untrusted network and want to be 
able to browse the internet without concerns about traffic sniffing on the local network.

Using OpenVPN
OpenVPN is a full SSL VPN solution that allows you to connect two networks at layer 2 or 3 
via a TCP or UDP tunnel. It is available on or via your distributions 
package repositories.

Remote Access


OpenVPN offers a number of options for authentication. We're going to set up a simple 
configuration, which will get you up and running. From there, there are multiple options,  
which you may want to consider for your needs.

How to do it…
1. Install OpenVPN on the server with sudo apt-get install openvpn for Debian 

derivatives like Ubuntu, or sudo yum install openvpn.

2. Generate a static key:
openvpn --genkey --secret /etc/openvpn/static.key

3. Set up the server configuration. You can see examples in /usr/share/doc/
openvpn/examples/sample-config-files. For our purpose, we'll start  
with the following:
proto udp
user nobody
secret /etc/openvpn/static.key
verb 3

4. Create a client configuration file:
remote wanaddress
proto udp
dev tun
secret /path/to/static.key
verb 3

5. Copy the static key to the client via scp, copy/paste, or another manner. You'll  
want to make sure that you keep this key secure as it will now allow access to  
your network.

6. (Optional) If your OpenVPN server is not the router for your local network, you'll need 
to forward port 1194 to your openvpn server, and define a static route which routes 
traffic addressed to to your OpenVPN system.

7. Connect the VPN from the client as root:
sudo openvpn --config client.conf

8. You should now be able to ping any IP on your local network.

Chapter 4


How it works...
For authentication purposes, OpenVPN offers the ability to use TLS certificates for both the 
client and server or optionally use a single static key. In this case, we're using the static key 
approach for a fast and easy configuration. This method requires that we share a single key 
generated by OpenVPN's genkey command on both ends of the connection.

Let's look at the server configuration:

proto udp
user nobody
secret /etc/openvpn/static.key
verb 3

To start with, we're specifying that we'll run over the UDP protocol. OpenVPN supports 
tunneling over both TCP and UDP, but UDP is recommended and is the default. The reason for 
this is because UDP does not include any re-transmission functionality. When transmitting TCP 
or UDP over a tunnel, an additional layer of fault tolerance below it can cause unnecessary 
overhead in the event of packet loss where both TCP layers attempt to solve the problem.

Next we will specify the user that the openvpn daemon should run as. This is a security 
precaution which makes sure that in the event of a compromise of the daemon, the user  
will get access to an unprivileged account rather than root.

Next we specify the secret file. You'll want to provide the complete path to where the file  
may be found. In my example, I've used the openvpn configuration directory used on  
Ubuntu systems.

The ifconfig command is used to specify the tunnel end points. The first IP address is the 
address on the local system that will provide a connection to the second IP, which is the client 
tunnel endpoint.

comp-lzo is an optional configuration option that provides lzo compression for the 
connection. This utilizes more CPU power in order to compress the network traffic, which may 
substantially increase your throughput in the event that you're sending highly compressible 
content like text. If your traffic is mostly already encrypted/compressed or binary, you may see 
less improvement. In this event you may decide to disable the option.

Finally, verb 3 defines the verbosity level for logging purposes. Verb 3 is considered 
medium output and is useful for normal operation. When troubleshooting a problem,  
you may want to use 9 instead, which is the verbose level.

Remote Access


Ok, now we'll look at the client configuration:

remote wanaddress
proto udp
dev tun
secret /path/to/static.key
user nobody
verb 3

You'll see that the configuration here is very similar. The big differences are that you're 
specifying a host to connect to via the remote variable. This may be the hostname or IP 
address of your public IP address.

The options to ifconfig are also reversed since we're creating the opposite side of the 
tunnel so the local versus remote variables changed.

We also add a new route variable that will define the IP ranges which are tunneled. Traffic 
from the client in this case will be routed over the internet as normal unless the recipient 
traffic is in the range, in which case openvpn will tunnel the traffic.

Now that the configuration files exists, we can launch the openvpn client by running sudo 
openvpn --client openvpn.conf. The sudo is required here, as setting up tunnels 
requires root privileges. Once the daemon is running, it will drop privileges to the user that  
you specified in the user variable.


Web Servers

In this chapter we will cover:

 f Configuring Apache with TLS

 f Improving scaling with the Worker MPM

 f Setting up PHP using an Apache module

 f Securing your web applications using mod_security

 f Configuring NGINX with TLS

 f Setting up PHP in NGINX with FastCGI

One of the powerful things that Linux on servers allows you to do is to create scalable web 
applications with little to no software costs. We're going to discuss setting up web applications 
on Linux using Apache HTTPD and NGINX (pronounced Engine-X), securing those servers and 
look at some of the limitations for scaling.

Apache HTTPD, commonly referred to as just Apache, is the number one web server software 
in the world. As of November 2015, it is estimated to host roughly half of all websites live on 
the Internet. It was initially created as a set of patches to the NCSA HTTPD server in 1995. In 
fact, the name Apache was a play on the fact that it was a patchy server. These days Apache 
HTTPD is a very robust, flexible, and feature packed web server option.

NGINX is a newer offering, with the initial release having come out in October of 2004. While 
less feature filled than Apache, it can often handle a larger load while utilizing less memory 
than Apache does. It can also be used as a load balancer or reverse proxy frontend for 
language specific application servers, such as Mongrel from the Ruby on Rails project.

Web Servers


Configuring Apache with TLS
These days, installing Apache with TLS is easier than ever, although the specific process can 
vary from distribution to distribution due to differences in configuration layout. Let's look at 
two of the current major examples.

How to do it…
Let's start installing and configuring on Ubuntu 14.04:

1. Install the package:
sudo apt-get install apache2

2. Enable the SSL modules and stock SSL configuration:
sudo a2enmod ssl

sudo a2ensite default-ssl

3. Add the appropriate SSL certs to the machine. The private key file should be delivered 
to /etc/ssl/private while the public certificate and relevant intermediate certs 
should be delivered to /etc/ssl/certs.

4. Update the Apache configuration to point to the correct certs. Edit /etc/apache2/
sites-enabled/default-ssl.conf in the editor of your choice and update the 
SSLCertificateFile and SSLCertificateKeyFile variables to point to your 
new cert and key. If you're hosting your own internal CA, you'll want to uncomment 
SSLCertificateChainFile and point it to your CA chain.

5. Restart the service:

service apache2 restart

Let's start installing and configuring on CentOS 7:

1. Install apache and mod_ssl:
sudo yum install httpd mod_ssl

to /etc/pki/tls/private while the public certificate and relevant intermediate 
certs should be delivered to /etc/pki/tls/certs.

3. Update the Apache configuration to point to the correct certs. Edit /etc/
httpd/conf.d/ssl.conf in the editor of your choice and update the 
SSLCertificateFile and SSLCertificateKeyFile variables to point to your 
SSLCertificateChainFile and point it to your CA chain.

Chapter 5


4. Enable httpd to start on boot:
sudo systemctl enable httpd.service

5. Start the daemon:

service httpd start

How it works…
In order to serve SSL/TLS traffic, you need to have Apache installed, as well as a module 
for Apache which supports the protocol. In this case, we're using mod_ssl, which enables 
OpenSSL support for Apache. Another option would be to use mod_gnutls, which  
uses GnuTLS.

In the Ubuntu case, mod_ssl is included automatically in the apache2 package. You just 
need to enable it using a2enmod (Apache 2 Enable Module) and a2enableconf (Apache 2 
Enable Configuration). Ubuntu will automatically launch the Apache process on boot up.

For CentOS, you need to install the additional mod_ssl package instead, but once installed 
it is enabled automatically. CentOS does require an additional step in order to enable the 
daemon on boot up however, which is handled via systemctl, part of the system package.

Improving scaling with the Worker MPM
Apache2 offers a variety of Multi-Processing Modules (MPM) for defining how the daemon 
will handle scaling. The default is typically prefork, which is a simple MPM which uses 
separate processes for handling each request. Scaling can be improved by using the Worker 
MPM or the newer Event MPM, which utilize threading in addition to processes in order to 
improve performance.

How to do it…
Configuring the worker MPM on Ubuntu 14.04.

Ubuntu 14.04 uses the multi-threaded Event MPM by default, but it may be disabled 
automatically if any non-threadsafe modules such as mod_php are enabled.

To determine which MPM is in use, execute a2query –M in order to determine what  
is configured.

You may then swap out the existing MPM with:

a2dismod mpm_$(a2query –M)
a2enmod mpm_worker
service apache2 restart

Web Servers


That the preceding action will fail if you have any non-thread safe 
modules enabled.

Configuring the Worker MPM on CentOS 7

CentOS 7 uses the prefork MPM by default since it is the more compatible offering, but it 
does ship a variety of MPMs in the package. The definition of which MPM is to be used can 
be found in /etc/httpd/conf.modules.d/00-mpm.conf. Just comment out the existing 
MPM and uncomment the desired one before restarting with service httpd restart.

How it works…
In order for Apache to scale to handle large numbers of simultaneous connections, it uses 
a potentially large number of processes. Each process that runs uses up a fixed amount of 
memory, meaning that the more connections you are using at a given time, the more memory 
you are consuming on your system.

Loaded modules such as mod_php add to the memory utilization for each process, increasing 
memory consumption further. Additionally, if your web application code interacts with 
databases, then each Apache process that is running code which interacts with the database 
will require its own database connection. This can cause additional resource strains as you 
increase the number of connections that your database needs to deal with.

In order to give people the flexibility for how they handle connections, Apache is very 
configurable. There are directives which define the number of processes to run at startup 
(StartServers), as well as a minimum and maximum number of spare/idle servers which 
should be running (MinSpareServers, MaxSpareServers).

For workloads that require the ability to handle many more connections, you need to look into 
Apache's options for Multi-Processing Modules (MPM). The two main MPMs you should look 
at for Unix-like systems are the pre-fork MPM, which is the default, and the worker MPM.

The pre-fork MPM allows for a single connection per process. So if you want to be able to 
handle 500 simultaneous connections, then you'll need to start 500 processes, utilizing  
500 times the resources of a single process.

The worker MPM is a hybrid approach that uses a combination of processes and threads 
to increase capacity without increasing memory utilization as much. This MPM module 
adds an additional directive called ThreadsPerChild that defines the number of threads 
each process will run. With a default of 25 threads, this means that you can handle 500 
connections using just 20 processes, thus dramatically decreasing your required memory.

Chapter 5


The event MPM is similar to worker, but attempts to handle request processing more cleanly 
by handing off connections which are idle but being kept open by a browser to separate 
threads which can easily just sit and wait until additional processes are brought in.

Now, there is a very good reason why the pre-fork MPM is the default rather than worker or 
event. Any code which executes within the Apache webserver, like mod_php, will be running 
multi-threaded with multi-threaded MPMs. If a module is not thread safe, then you may 
experience crashes or other problems.

Setting up PHP using an Apache module
PHP is a very common programming language to use on Apache webserver, largely due to  
its ease of use. Luckily this also equates to being very easy to install on most distributions  
as well.

How to do it…
Setting up PHP on Ubuntu 14.04:

1. Install PHP's apache module:
sudo apt-get install libapache2-mod-php5

2. Ubuntu's package should enable the module by default, but you can test it to be sure 
by running a2query -m php5. If it is not enabled, it may be enabled by running 
a2enmod php5.

Setting up PHP on CentOS 7:

1. Install PHP, including the Apache module.
sudo yum install php

2. CentOS also enables the module by default. In order to confirm that it is installed, 
look for /etc/httpd/conf.modules.d/10-php.conf. If you have difficulties 
executing PHP code, you may need to restart the Apache service with service 
httpd restart.

How it works…
The PHP module gets linked into the Apache application during startup, adding the capability 
to detect PHP web application code and process it automatically. This loading is handled 
dynamically based upon the webserver configuration file.

Web Servers


Securing your web applications using  

Now that you're able to execute the PHP code, you're also ready for people to attempt to 
exploit your PHP code. While PHP code can certainly be secure, it often appeals to new 
developers who have not yet learned secure coding practices. In a situation like this, it  
can be helpful to have some additional protection in the form of a Web Application Firewall.

Mod_Security is an open source Web Application Firewall (WAF) for Apache. It is able 
to interpret full HTTP requests and responses in order to detect and block attempts at 
performing various HTTP attacks like SQL injection, cross site scripting and others.

How to do it…
The first thing you need to do is to install and enable the module in detection mode:

Installing on Ubuntu 14.04:

1. Install the package:
sudo apt-get install libapache2-mod-security2

2. Setup the mod_security configuration file:

3. Restart the service:

Sudo service apache2 restart

Installing on CentOS 7:

1. Install the package:
sudo yum install mod_security

2. Setup the mod_security core rules set:
sudo yum install mod_security_crs

3. Switch the configuration to detection only:
sudo sed -i 's/SecRuleEngine On/SecRuleEngine DetectionOnly/g' /

4. Restart the service:

sudo service httpd restart

Chapter 5


Once it is installed in detection mode, you should start seeing possible exploitation attempts 
in /var/log/apache2/modsec_audit.log on Ubuntu or /var/log/httpd/modsec_
audit.log on CentOS. You'll want to evaluate any detection exploitation attempts in order  
to confirm that there are no false positives with your application before enabling it in  
blocking mode.

Once you're comfortable that the rules are behaving as expected, they can be switched to 
blocking mode by setting SecRuleEngine to on in /etc/modsecurity/modsecurity.
conf (Ubuntu) or /etc/httpd/conf.d/mod_security.conf (CentOS).

How it works…
Mod_security works by watching incoming HTTP requests and outgoing HTTP responses 
and looking for specific patterns that indicate known malicious request types. By default, it 
is configured with their Core Rules Set (CRS), but additional rules may be written with a bit 
of knowledge of the format of the rules. For now, sticking with the core rules or other rules 
written by experienced users is your best bet.

Rules are defined on the system in /usr/share/modsecurity-crs/ on Ubuntu or /usr/
lib/modsecurity.d/ for CentOS.

Configuring NGINX with TLS
While we've covered Apache's HTTPD server so far in this chapter, there are other options 
available for use on Linux platforms as well. One popular offering is NGINX (pronounced 
engine-x), which works well as a lightweight, fast, multithreaded offering.

We're going to look at how to set it up as a TLS webserver.

How to do it…
Installing on Ubuntu 14.04:

1. Install the software:
sudo apt-get install nginx

2. Configure the server for TLS by uncommenting the HTTPS server section of /etc/
nginx/sites-available/default while populating the ssl_certificate, 
ssl_certificate_key and ssl_ciphers variables.

3. Restart the daemon:

sudo service nginx restart

Web Servers


Installing on CentOS 7:

1. On CentOS 7, NGINX is not included in the default repos, but is available in the Extra 
Packages for Enterprise Linux (EPEL) repository.

2. Install the EPEL repo:
sudo yum install epel-release

3. Install the nginx package:
yum install nginx

4. Configure the server for TLS by adding an https server section to /etc/nginx/
server {
    listen       443 ssl;
    server_name  localhost;

    ssl_certificate      /etc/pki/tls/certs/certw.crt;
    ssl_certificate_key  /etc/pki/tls/private/cert.key;

    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;

    ssl_ciphers  HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers  on;

    location / {
        root   html;
        index  index.html index.htm;

5. Enable nginx to start on boot:
systemctl enable nginx

6. Restart nginx:

Service nginx restart

How it works...
For the most part, the configuration of NGINX is very straightforward. The only complicated 
part is the enabling of the EPEL repository on CentOS systems. This is required as nginx is 
not supported by Red Hat as a part of the core Red Hat Enterprise distribution, which CentOS 
is part of.

Chapter 5


Setting up PHP in NGINX with FastCGI
As we mentioned is an earlier chapter, linking modules into a multi-threaded HTTP server 
requires that the code in the module be thread safe. NGINX works around this by utilizing 
the fastcgi protocol to interact with interpreters rather than linking them directly into the 
process. This does not have quite the performance of the more native approach, but you can 
limit what content runs through the processor.

How to do it…
Configuring on Ubuntu 14.04:

1. Install the PHP FastCGI wrapper:
sudo apt-get install php5-fpm

2. Modify php's configuration file to disable cgi.fix_pathinfo, this setting opens 
the door to security vulnerabilities by allowing PHP to guess at what your request was 
intending to request:
sed 's/.*cgi.fix_pathinfo=.*/cgi.fix_pathinfo=0/g' /etc/php5/fpm/

service php5-fpm restart

3. Configure nginx to talk to the php5-fpm daemon (default is /etc/nginx/sites-
available/default) within the relevant server definitions:
location ~ \.php$ {
  try_files $uri =404;
  fastcgi_pass unix:/var/run/php5-fpm.sock;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME \
  include fastcgi_params;

4. Restart nginx:

service nginx restart

Web Servers


Configuring on CentOS 7:

1. Install the PHP FastCGI wrapper:
sudo apt-get install php-fpm

2. Enable the php wrapper to start on boot:
systemctl enable php-fpm

3. Modify PHP's configuration file to disable cgi.fix_pathinfo, this setting opens 
intending to request:

service php-fpm restart

4. Configure nginx to talk to the php-fpm daemon (default is /etc/nginx/nginx.
conf) within the relevant server definitions:
location ~ \.php$ {
    root           html;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME \
    include        fastcgi_params;

5. Restart nginx:

service nginx restart

How it works…
The php5-fpm/php-fpm packages on Ubuntu/CentOS install a daemon which listens on a 
Unix socket or TCP port and accepts PHP code for processing. This allows us to handle the 
PHP code without having the php library linked into the web server but without requiring the 
overhead of starting a CGI application for each request.

Now that we have a service which handles PHP interpretation, nginx can concentrate on 
serving up normal HTML, JavaScript and image content and can essentially proxy any PHP 
requests directly to php5-fpm directly. It then passes the responses back to nginx for the 
server to se