How to secure an apache 2 Web Server


This document was written for an Apache 2 Web Server running under Linux Raspbian (Debian based Linux distribution for Raspberry) but it is ,of course, also valid for any Linux Flavour.

Securing the file system

The Apache “ServerRoot” folder contains the Web Server configuration files (ServerRoot is set to /etc/apache2 under Raspbian).
This folder must belong to root (user & group) and must only be writable to root (set the permissions to 755). The same applies to the Apache binaries.

The “DocumentRoot” folder that hosts the Web Site content (usually /var/www) can be writable by users if necessary (those who need to update the site) and must be readable by the Apache user.

Running with low privileges

The Apache Web Server must run with a standard user.
This is important in order to limit the impact if an attacker manages to exploit a vulnerability of Apache or one of its modules.
If you run apache with as root, the attacker could get all privileges against your system.

File: /etc/apache/envvars
User www-data
Group www-data

N.B. The given user and group must be created.

Hide software & system information

Even if hiding some technical data does not secure your web server, there’s no reason to help attackers finding vulnerabilities.

– Limit the Apache banner provided in the Http Response Header to the minimum:
File: /etc/apache2/conf.d/security
Directive: ServerTokens Prod

– Disable Apache information in the footer of server generated pages (errors, …)
File: /etc/apache2/conf.d/security
Directive: ServerSignature Off

– You may also define custom error pages in order to display only what you want

File: /etc/apache2/sites-enabled/000-default (Or file containing your web site configuration)

Directive: ErrorDocument 404 /missing.html

Limit the risk of Denial of service incidents

You should adapt Apache configuration according to your server capability.

File: /etc/apache2/apache2.conf
– KeepAlive: Set it ti On in order to authorize HTTP/1.1 protocol (persistent connection).
– KeepAliveTimeout: Max number of seconds to wait for a request in a persistent connection before closing it.
– MaxClients: Limit the number of simultaneous connections.
– MaxKeepAliveRequests: Max number of requests allowed per persistent connection
– Timeout: Max number of seconds to wait for data from the client (it’s also valid for other input/output context)
– LimitRequestBody: Limit the total size (in byte, 0 = unlimited) of the HTTP request body (if you authorize file upload, adjust it accordingly). You may also limit the size of other request attributes with LimitRequestFields, LimitRequestFieldSize and LimitRequestLine.

You may also consider the following directives: MaxSpareServers, MaxRequestsPerChild, ThreadsPerChild, ServerLimit and MaxSpareThreads. You must also set their value according to your system capabilities.


KeepAlive On
MaxClients 150
MaxKeepAliveRequests 100
KeepAliveTimeout 5
Timeout 60
LimitRequestBody 1048576

Define correct access right to your web site

First, deny access to the entire file system:
File: /etc/apache2/sites-enabled/000-default


<Directory />
Order deny,allow
Deny from all
Options None
AllowOverride None

The « Options None » et « AllowOverride None » directives disable all server features (Indexes, ExecCGI, …) and all .htaccess directives for the entire web site. If needed, you’ll still be able to define these directives in other Directory sections.

Take care if you also define a <Location /> section as its settings can supersede the <Directory /> settings (as Location directives are processed after Directory and .htaccess directives). Moreover, Location directives apply to URL and so, they shouldn’t be used to define access rights to the file system. Use Location sections to define access rights to resource which are not located in the file system (usually using a SetHandler directice, for instance to define access to /status through server-status handler).
Then, allow access to the public part of your web site:

File: /etc/apache2/sites-enabled/000-default
<Directory /var/www>
Order Deny,Allow
Allow from all
Options None
AllowOverride None
You may now restrict access to other resources based on IP addresses or domain name

File: /etc/apache2/sites-enabled/000-default
<Location /status>
SetHandler server-status
Order Deny,Allow
Deny from all
Allow from
Allow from

At last, you can control the access to the private part of your web site using authentication:

File: /etc/apache2/sites-enabled/000-default

Basic Mode (requires auth_basic module)


<Directory /private>
Options None
AllowOverride None
AuthName “restricted stuff”
AuthType Basic
AuthUserFile “/etc/apache2/.passwd”
require valid-user

To create the users, use the htpasswd command: htpasswd -c -m /etc/apache2/.passwd <username>
(replace <username> by the login to create and enter the password when requested)
N.B. “-c” option must be use only to create the file
Digest mode (requires mod_digest module)


<Directory /private>
Options None
AllowOverride None
AuthName “”
AuthType Digest
AuthDigestProvider file
AuthDigestDomain /private/
AuthUserFile “/etc/apache2/.passwd”
require valid-user
To create the users, use the htdigest command: htdigest -c /etc/apache2/.passwd <realm> <username>
(replace <username> by the login to create and <realm> to the same value as “AuthName” directive and enter the password when requested)
N.B. “-c” option must be use only to create the file
If you want to ask for authentication except from a given IP address or network, use both “satisfy any” and “Allow from ” directives:

<Directory /private>
Options None
AllowOverride None
AuthName “”
AuthType Digest
AuthDigestProvider file
AuthDigestDomain /private/
AuthUserFile “/etc/apache2/.passwd”
require valid-user
Deny from all
Allow from
Satisfy any

The “satisfy any” directive requires that one of both conditions to be true to grant access to this directory.

.htaccess files

.htaccess can be used to override some “Directory” directives (useful for users who don’t have access to the apache configuration file). AllowOverride directive define the options that can be override using .htaccess files.
If you allow the use of .htaccess, you should forbid access to these files from the Internet :

File: /etc/apache2/apache2.conf
AccessFileName .htaccess
<Files ~ “^\.ht”>
Order deny,allow
Deny from all
Satisfy all

If you don’t need .htaccess files at all, set directives “AllowOverride” and “AllowOverrideLists” to None and the web server will ignore them.

Configuring some security features in HTTP Headers

Disabling Entity Tag (Etag)
Disabling the Etag is not really a security measure but setting the Etag can, in some circumstances, decrease performance (serving an object that could be taken in the browser cache) or malfunctions (taking an object in the browser cache whereas it should request the newer one from the web site).
Disabling Etag, the usual cache mechanism will be used (Last-Modified / If-Modified-Since) for static content.

File: /etc/apache2/apache2.conf
Directive: FileETag None

Enforcing Cookies security
N.B. You must load “headers” module to enable this setting.
You can enforce secure mode and http only for the cookies using the following header directives.

File: /etc/apache2/conf.d/security
Directive: Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure

Dealing with ClickJacking issue
N.B. You must load “headers” module to enable this setting.
An attacker can trick a user by making him click on a hidden link using a transparent layer. For instance, the user click on a button that seems legitimate but that will perform an undesired action like redirecting him to the attacker web site.

File: /etc/apache2/conf.d/security
Directive: Header always append X-Frame-Options SAMEORIGIN

Protecting against X-XSS Protection
X-XSS-Protection is a HTTP header understood by some recent browsers. The X-XSS-Protection header field allows web sites to  toggle on and off the “XSS Filter” of these browsers, which prevents some types of XSS attacks. You can enforce this setting at the Apache level.
File: /etc/apache2/conf.d/security
Directive: Header set X-XSS-Protection “1; mode=block”

Preventing Internet Explorer to detect content type
N.B. You must load “headers” module to enable this setting.
Internet Explorer can detect the content type of file but it can differ from the one specified in the HTTP header.
To prevent this, use the directive given below.

File: /etc/apache2/conf.d/security
Directive: Header set X-Content-Type-Options: “nosniff”

HTTP Methods and version

Disable HTTP 1.0
You have to load “rewrite” modules to enable this setting

To disable HTTP 1.0, use the following directives:
File: /etc/apache2/conf.d/security
RewriteEngine On
RewriteCond %{THE_REQUEST} !HTTP/1\.1$
RewriteRule .* – [F]
Restrict the authorized HTTP methods
By default, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT HTTP methods are authorized for HTTP 1.1 protocol. You can restrict the authorized methods to the only one you need using the directive given below. This directive must be defined in a <Directory /> section.

In this example, we authorize only GET, HEAD and POST methods.

File: /etc/apache2/sites-enabled/000-default
<LimitExcept GET POST HEAD>
deny from all

Disable HTTP Trace method
The Trace method should be enable only in debug phases. In regular operation, you should disable it as it can be useful to attackers (DoS attacks and information gathering of your infrastructure).

File: /etc/apache2/conf.d/security
Directive: TraceEnable off


If you are using SSL/TLS for your web site, you should disable some weak encryption algoithms (RC4 for instance) as well as SSL v2 which has some vulnerabilities.

File:/etc/apache2/sites-enabled/000-default (Directory or VirtualHost section)

SSLProtocol –ALL +SSLv3 +TLSv1

Disable search engine indexation for some directories

If you want to avoid the indexation of some parts of your web site by search engines, you can use robots.txt file to give instructions to search engines.
In the following examples, we exclude /docs directory and subdirectories to be indexed by search engines.

File: robots.txt (save it at the root of your web site)
User-agent: *
Disallow: /docs/

Configure the logs

You can define different log format:

File: /etc/apache2/apache2.conf


LogFormat “%v:%p %h %l %u %t \”%r\” %>s %b %O %T \”%{Referer}i\” \”%{User-Agent}i\”” vhost_combined
LogFormat “%h %l %u %t \”%r\” %>s %b %O %T \”%{Referer}i\” \”%{User-Agent}i\”” combined
LogFormat “%h %l %u %t \”%r\” %>s %b %O %T” common
LogFormat “%{Referer}i -> %U” referer
LogFormat “%{User-agent}i” agent

In order to select the log format to use for a given web site as well as its location:
File: /etc/apache2/sites-enabled/000-default
Directives: CustomLog /var/log/httpd/access_log common

The HostnameLookups directive can be used to resolve IPs to hostnames in the logs.
You shouldn’t use it as it will send a lot of DNS reverse lookup requests.

File: /etc/apache2/sites-enabled/000-default
Directives: HostnameLookups Off

Disable directory browsing

Unless you need it in a specific directory, disable it in / and all others.
If you set “Options None” directive as specified above, Directory browsing is already disabled.
If it’s not the case, you can use “Options -Indexes” directive.

File: /etc/apache2/sites-enabled/000-default
Directives: Options None or Options -Indexes

Modules configuration

As usual in security, you should disable all unnecessary modules.
For instance: Server Side Include, CGI (cgi and cgid), Perl should be disabled if you don’t need it.
mod_autoindex (autoindex) and mod_userdir (userdir), mod_status (status) should also be disabled.

To disable a module, you can use the “a2dismod” command:

# a2dismod cgid
Module cgid disabled.
To activate the new configuration, you need to run:
service apache2 restart
Some modules can also be compiled within the Apache binary (static modules).
To see these modules, use the following command:

# apache2 -l
Compiled in modules:

If you want to disable some static modules, you have to recompile Apache.

To list all loaded modules (static and shared), you can use the following command:

# apache2ctl -M
Loaded Modules:
core_module (static)
log_config_module (static)

alias_module (shared)
auth_digest_module (shared)

unique_id_module (shared)
Syntax OK

Web Application firewall: modsecurity

A Web Application Firewall (WAF) can protect your web site against common attacks using some security rules (URL filtering, URL validation …). ModSecurity comes with many predefined rules but you can also add your own rules.
For more information, have a look to
ModSecurity installation:

You need to install the package “libapache2-mod-security” in order to use it with Apache.
The “unique_id” Apache module must be enabled in order to make it work correctly.

You must create a folder that will host the mod-security configuration files. I recommend to create it in the Apache 2 server root (/etc/apache2/modsecurity to create it in the default server root).  The owner should be root and rights set to 600.

The package “libapache2-mod-security” doesn’t come with any predefined rules but you can get core rules from OWASP or from ModSecutiy Web Site.
You can get core rules from ModSecurity Web site:
You can also get OWASP core rules from
N.B. The latest core rules are compatible only with ModSecurity version >= 2.7.0. If you use a previous version of ModSecurity, you must use OWASP core rules version 2.2.5 (get them at

Personally, I’m using core rules from ModSecurity web site as raspbian package is still in 2.6 version.
Download and unpack the ModSecurity rules
#mkdir -p /install/modsecurity/rules ; cd /install/modsecurity/rules
#tar xvf modsecurity-core-rules_2.5-1.6.1.tar.gz
#cp *.conf /etc/apache2/modsecurity/
Enable ModSecurity module

The activation is done with “a2enmod mod-security”.
To adapt the configuration of this module, edit the file “/etc/apache2/mods-enabled/mod-security.conf”. You have to include the configuration files using the “Include” directive:

Include “/etc/apache2/modsecurity/*.conf”
Configure ModSecurity module

Using the ModSecurity core rules, the main configuration file is /etc/apache2/modsecurity_crs_10_config.conf.
You should enable the Rule Engine by setting the option “SecRuleEngine” to On.
If you want to test the rules first without taking the risk to block any request, you can set this option to “DetectionOnly”.

The default behaviour is to log the error without blocking the request. Once you monitored the ModSecurity logs and seen that it doesn’t block legitimate requests, you can enable the blocking mode by removing the comment (#) of the following line:
SecDefaultAction “phase:2,log,deny,status:403,t:lowercase,t:replaceNulls,t:compressWhitespace”
It will log the attack and reject it with a 403 HTTP status.

ModSecurity has 2 log levels: debug log (it duplicates Apache error logs) and Audit Log (ModSecurity events).
The “log” directives enables both logs.
The “no log,audit log” enables only audit logs and “Log,noauditlog” enables only debug log.
If you want to put ModSecurity log files to the same folder as Apache log files, set the following option to this setting:
SecAuditLog ${APACHE_LOG_DIR}/modsec_audit.log
Running ModSecurity
Reload apache in order to take into account these modifications:
#/etc/init.d/apache2 force-reload

ModSecurity will then start to detect and block attacks.
Have a look to /var/log/apache2/modsec_audit.log file in order to see if it’s working properly.

If you have some false positives and need to disable some rules, you can comment the rule in the “.conf” file containing the rules or you can create a whitelist file containing the ID of the rules that you want to disable.
For instance:
File: /etc/apache2/mod-security/modsecurity_crs_99_whitelist.conf
SecRuleRemoveById 960904
SecRuleRemoveById 960017

How to secure an apache 2 Web Server

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.