Keep Your Servers Up-To-Date

If your fresh OS image shipped with a web server preinstalled, chances are it's out of date.

New exploits pop up all the time and good developers will regularly patch security risks, so you should always ensure that you're running the latest and greatest versions.

Check your Apache version
apache2 -v

apt-get update
apt-get install apache2

You should be updating other software along your stack as well - such as PHP or MySQL if you use them.

Reject Traffic From Other Domains Pointed To Your IP

I've had a few web servers receive traffic via domain names that weren't mine.
This means that something like points to my server's IP address. That's a big no-no.

Maybe the previous owner of your server's IP address forgot to update their DNS records. Or maybe someone's pulling your leg. Regardless, there's nothing we can do about the domain registrant's DNS settings - they can point their domain name to whatever address they want.

What we can do is deny all requests that don't match your domain name.

We'll be using Name-Based Virtual Hosts to implement a catch-all condition that rejects all unrecognized domain requests before serving the correct ones.

Open your default sites-enabled config file
vi /etc/apache2/sites-enabled/000-default

Note: This directory runs your configurations in alphanumeric order, so the 000- config always runs first.

Add this to the top of your file:
NameVirtualHost *:80
<VirtualHost *:80>
  ServerName _default_
  <Location />
    Order deny,allow
    Deny from all

Note: You may not need the NameVirtualHost declaration on the first line. It only needs to be declared once throughout all config files, and it's usually already in ports.conf.

We put this "catch-all" definition as the FIRST VirtualHost declaration. This makes sure we return a 403 Forbidden to any ServerName that doesn't exist in another VirtualHost section.

You should already have an existing VirtualHost declaration below this one.
Make sure you declare its name properly, or else legitimate requests will never be served!

<VirtualHost *:80>
  DocumentRoot /var/www
  *other options*

Disable Directory Indexing

I remember a computer science professor who left directory indexing enabled while keeping important course-related documents in navigatable directories. Needless to say, this was a problem.

I'd say this is one of the most important tweaks that most beginner-level web servers never implement. Unless you have a reason to keep this enabled (maybe you're hosting files for download?), you shouldn't let users browse your directories. It gives your users more information than they need. You should always be serving your content from a front-end View anyways.

Open your default sites-enabled config file
vi /etc/apache2/sites-enabled/000-default

Find the <Directory> block for /var/www/ and remove Indexes from the Options list
<Directory /var/www/>
  #other settings
  Options Indexes  # Remove "Indexes"
  #other settings

Change Your SSH Port

Security through obscurity can be a powerful concept. Though you should be securing access to your server by other means (ex. making sure you use SSH keys instead of passwords), another precaution never hurts.

If you have an internet-facing server with port 22 open, your logs are probably filled with brute force SSH login attempts by bots. It's just the way it is - Botnets assign their machines to scan sectors of IP addresses for commonly open ports, and run brute-force hacks on them around the clock.

We can drastically reduce the number of scans your SSH port receives by simply changing it.
Wikipedia tells us that ports in the range 49152–65535 are unregistered and see little action. Feel free to pick any number in that range.

To change the port you use, open the config file
vi /etc/ssh/sshd_config

Find the following line and change your port number
port xxxxx

Restart SSHD
service ssh restart

Set Your Fully-Qualified Domain Name (FQDN)

When setting up your servers, you may tend to use simple unqualified hostnames such as "box1" or "basement".
However, you may find that your site needs a properly assigned FQDN to perform certain tasks. Apache may also throw a warning at you about your hostname every time you issue a restart.

This is commonly needed for PHP's Sendmail function. If you don't alter either your /etc/hosts or /etc/mail/ files, Sendmail will throw errors and delays at you, and the logs will read something along the lines of "sleeping for retry".

A quick edit to your hosts file can amend this problem and resolve your FQDN:
Open /etc/hosts
vi /etc/hosts

Add your simple hostname to the localhost line    localhost.localdomain localhost box1

Use mod_security

One of the easiest things you can do to secure your server is install mod_security, which is a Web Application Firewall available for Apache. This adds a bit of automation to your security and gives you a little less to worry about.

First we need to enabled mod_headers
a2enmod headers

Now install the package
apt-get install libapache-mod-security

Copy out the recommended config file
mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

To enable it, open the config file
vi /etc/modsecurity/modsecurity.conf

Edit one of the first lines along the top to read:
SecRuleEngine on

Now enable it in Apache
a2enmod mod-security

Restart Apache
service apache2 restart

It would take an entire article to explain the nuances of how to configure this tool. Many users download and import custom rule sets, but we'll stick with the default configuration for now.

Use mod_evasive

Much like mod_security, mod_evasive is an easy way to secure your Apache installation. It runs some basic logic to protect your server against DDoS attacks.

Install the module
apt-get install libapache2-mod-evasive

Create a directory for logs
mkdir /var/log/mod_evasive

Give it proper permissions
chown www-data:www-data /var/log/mod_evasive/

Create and edit a new config file
vi /etc/apache2/mods-available/mod-evasive.conf

Copy this into the file, editing values as you see fit (more info below)
  DOSHashTableSize 3097
  DOSPageCount 10
  DOSSiteCount 200
  DOSPageInterval 1
  DOSSiteInterval 1
  DOSBlockingPeriod 10
  DOSLogDir /var/log/mod_evasive

DOSPageCount is the max. number of requests for the same page (or URI), and DOSSiteCount is the max. number of total requests. The intervals (in seconds) control how often you check the counts, and DOSBlockingPeriod controls how many seconds you block a client for.

For example, the above config will block a client for 10 seconds if it makes more than 10 page requests or 200 site requests per second.

Note that the timer resets with every subsequent request by the same client. If an attacker exceeds the threshold every second, then its blocking period is reset to 10 seconds every second.

Now enable the module
a2enmod mod-evasive

Restart Apache
service apache2 restart

Install Fail2Ban

Fail2Ban is a wonderful piece of software that scans log files on your server for attempted intrusions, and uses adds entries in your iptables to block the attackers. It's simple and effective - much like mod_evasive.

Install the software
apt-get install fail2ban

Don't modify the main file, copy a local version to use
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Change your local config file
vi /etc/fail2ban/jail.local

Under the JAILS section, set enabled = true to enable log scanning on whatever services you use.
I usually enable this for ssh and apache.

maxretry is how many attempts the user gets before they get blocked. Be sure to give yourself chances tries in case you get it wrong!

Note: If you changed your SSH port like I recommended above, be sure to change it in the Fail2Ban config file too. Fail2Ban scans logs for intruders, but needs to know which port to block if it finds one.

Start the service
service fail2ban start

Hide Your Server Application Version

When it comes to security, the less information we give, the better.
On the pages that Apache provides (such as 404 Not Found or 403 Forbidden), your Apache version number and Linux distribution details are listed along the bottom.

We can hide all this information with a simple tweak.

Open /your Apache config file
vi /etc/apache2/apache2.conf

Append these lines to the end
ServerSignature Off
ServerTokens Prod

Block Access To Certain Files/Types

I believe that adding redundancy to your security settings never hurts. Even if you disable directory browsing, a user can still view content in your web directory if they know the direct link to it.

So if for some reason you still have oldUglyPictureOfMyself.jpg on your server, a user can still see it if they somehow figure out the name and location of your file.

To prevent this, you should remove unneeded files from your sever.
But if you really want to keep them there:

Open your default sites-enabled config file
vi /etc/apache2/sites-enabled/000-default

To stop serving a specific file, add this:
<Files "oldUglyPictureOfMyself.jpg">
  Order allow,deny
  Deny from all

To stop serving a certain file type, add this:
<Files ~ "\.inc$">
  Order allow,deny
  Deny from all

Where .inc is the file type you do not wish to serve.

Restrict Root Browsing

Similar to how we disabled directory indexing, we can deny any root directory browsing coming from Apache. This means that even if your web server gets compromised, it isn't allowed to do much.

Open your default sites-enabled config file
vi /etc/apache2/sites-enabled/000-default

Add this to your primary config
<Directory />
  Order Deny,Allow
  Deny from all
  Options None
  AllowOverride None

Limit Size of Incoming Requests

This tweak will set a maximum size for HTTP requests that you serve. Setting a good low number will help you slow-down attacks by limiting the size of the requests.

More commonly, this setting is used to set a maximum file size for sites that accept user uploads.

Open your default sites-enabled config file
vi /etc/apache2/sites-enabled/000-default

Set your maximum request size in bytes. A few MB should suffice.
<Location />
  LimitRequestBody xxxxx