Banner image of Web server security – Part 2: Harden the web server

Web server security – Part 2: Harden the web server

In the first part of this series, we showed you how to harden your server by configuring your firewall and SSH. In this part, we show you how to secure your web server software.

Always stay in the loop!
Subscribe to our RSS/Atom feed.


  • server configured like we described in part 1
  • web server software (Apache, nginx etc.)
  • SSH client on your computer

Step by step guide for a more secure web server

Last time, we configured a general-purpose operating system. You can use this setup to install your own Nextcloud server, OpenVPN server and more. In the following, we use the setup described in part 1 to install an Apache web server (Apache httpd).

In this series, will use Apache httpd 2.4.25 on Debian 9. You can also use Debian 10 or other operating systems. Keep in mind that some parameters in configuration files or names of files/folders may differ on your operating system.

Step 1: Install Apache and configure Certbot

Web server software processes HTTP and HTTPS requests and sends responses. There are different methods defined in the protocols which we will discuss later. As mentioned before, we use the Apache web server. Nginx is also very common.

Choose the web server you like and install it according to its documentation. On Debian 9, we install Apache: sudo apt update && sudo apt install apache2.

This installs Apache 2.4.25 (on Debian 9) or Apache 2.4.38 (on Debian 10) and several packages needed by Apache. Furthermore, the setup enables several Apache modules by default.

Moreover, we install Certbot which is needed to easily obtain a TLS certificate: sudo apt install python-certbot-apache.

After installing Certbot, we have to configure our firewall “ufw” again. In the first part of this series, we only allowed an IP subnet to connect to port 22 of our server. Common ports for HTTP and HTTPS are port 80 and port 443. Allow all IP addresses to connect to these ports:

  • sudo ufw allow 80 (HTTP)
  • sudo ufw allow 443 (HTTPS)

Then, run Certbot to obtain an RSA certificate from Let’s Encrypt for free:

sudo certbot --apache -d www.[your-domain-name],[your-domain-name] --rsa-key-size 4096

This request tells Certbot to use the Apache installer and authentication module. Furthermore, we tell Certbot to request a 4096 bit RSA certificate. We have to enter the domain name twice (once with “www.” appended, and once without “www.").

As of July 2019, you only get a 4096 bit RSA certificate using Certbot. You can also manually request an ECDSA certificate. It is actually recommended to use ECDSA certificates nowadays. We will show request and setup of ECDSA certificates in an upcoming article of this series.

Then, you have to enter a valid e-mail address that allows Let’s Encrypt to contact you. For instance, they will send you a reminder if your certificate is about to expire. Follow the instructions on your screen and read the official Certbot documentation, if needed. Since Certbot and the way of requesting certificates change from time to time, we won’t list every single step here.

If you need to enter your “webroot”, it is likely “/var/www/html/” on Debian. Certbot tries to get the certificate and offers to configure HTTPS-only: “2: Secure - Make all requests redirect to secure HTTPS access”. You can either tell Certbot to configure HTTPS-only or you can configure it manually (see below).

After the setup, open the web browser on your client and enter your domain name. If everything worked, you should be automatically redirected to your HTTPS-only demo website of Apache. We still have to configure either a “www to non-www” or “non-www to www” redirect in the next step.

Step 2: Configure apache2.conf

HTTPS is only one of many security-related topics when you set up and run your own web server. Let’s continue with other important settings. You find your “apache2.conf” file in “/etc/apache2/apache2.conf” on Debian 9. This file contains all basic settings for Apache.

In order to enable HTTP/2 over TLS, you have to enable the HTTP/2 module of Apache first: sudo a2enmod http2.

Then, apply the settings below (or change them according to your needs):

# Global configuration

# Enable HTTP/2 over TLS and HTTP/1.1
Protocols h2 http/1.1


# Timeout: The number of seconds before receives and sends time out.
# (Changed from 300 to 60)
Timeout 60


<Directory /var/www/>
        # clients can't directly access folder contents anymore
        Options -Indexes
        # disable HTTP entity tags (ETags) which can be used to track users
        # and expose sensitive server information
        FileETag None
        # add the following if you want to deploy only static content and
        # users can't post anything. This setting disables all HTTP methods
        # except GET and HEAD.
        <LimitExcept GET>
                deny from all

        # default values
        AllowOverride None
        Require all granted

<Directory /var/www/html>
        # Redirect HTTP to HTTPS (this could already be configured by Certbot)
        RewriteEngine On
        RewriteCond %{HTTPS} !=on
        RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]

        # Redirect www requests to non www (or change this according to your needs)
        RewriteCond %{HTTP_HOST} ^www\.(.*)
        RewriteRule ^.*$ https://%1/$1 [R=301,L]

Save “apache2.conf” and restart the web server: sudo systemctl restart apache2. Fix any errors. Check the status of Apache to see whether there are any problems: systemctl status apache2.

Step 3: Configure security.conf

Most of your configuration files are located in “/etc/apache2/conf-enabled/.” This folder contains files of enabled modules.

In order to manipulate HTTP headers, you have to enable the headers module of Apache first: sudo a2enmod headers.

Open your “security.conf” file and apply the following settings (or change them according to your needs):

# Send only necessary header responses
ServerTokens Prod


# Reduces server signature which exposes your OS and web server information
# like "Apache/2.4.25 (Debian) Server" to "Apache"
ServerSignature Off


# Add security-related HTTP headers
# The following settings are fine for static websites but have to be modified
# for Wordpress etc.

# Enable Content Security Policy (Level 2)
Header always set Content-Security-Policy "default-src 'none'; img-src 'self'; style-src 'self'; font-src 'self'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'"

# Disable Referrer which isn't needed when you don't use authentication
Header always set Referrer-Policy "no-referrer"

# Enable HSTS
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS

# Enforce MIME types for script and style elements
Header always set X-Content-Type-Options "nosniff"

# Enable OCSP stapling
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/apache2/ocsp(128000)

# Legacy HTTP response headers
# (Set these only if you want to support really old web browsers!)

# Enable Clickjacking protection
# (Uncomment, if needed. Only necessary, if you support old web browsers that
# don't support the CSP Level 2 directive "frame-ancestors".)
# Header always set X-Frame-Options "DENY"

# Enable XSS protection
# (Uncomment, if needed. Only necessary, if you support old web browsers that
# don't support the Content Security Policy header.)
# Header always set X-Xss-Protection "1; mode=block"


We discuss all of these settings in part 3 of our series.

Save “security.conf” and restart the web server: sudo systemctl restart apache2. Again, fix any errors and use systemctl status apache2 to check for errors.

Step 4: Configure security2.conf

In step 3, we reduced the server signature to “Apache”. To completely disable the signature, we have to install ModSecurity. ModSecurity is an open-source web application firewall which we discuss in part 4 of our guide.

Install ModSecurity sudo apt install libapache2-modsecurity and open the “security2.conf” file in “/etc/apache2/mods-enabled/.” Apply the following setting:

        # Disable the server signature
        SecServerSignature " "

Save “security2.conf” and restart the web server: sudo systemctl restart apache2. Please note that removing your server signature doesn’t protect your server from fingerprinting. There are still ways to identify the web server software running on your server. However, this may block some automated attacks that look for the signature.

Step 5: Validate your configuration

After configuring, it is important to test whether the configuration was successfully applied. We wrote an article dedicated to online assessment tools for web server security. Use these tools to check your configuration. You don’t have to achieve 100% ratings everywhere. Some settings may be irrelevant for you. Don’t try to achieve 100% by blindly following any guides on the internet.

Keep in mind that we didn’t configure TLS, cipher suites and OCSP Must-Staple so far. We will do this in the next part.

Step 6: Back up your configuration

Finally, we want to back up our configuration. This is really useful in case of errors or lockout since you can reinstall your server and web server without configuring everything from scratch.

We use a small bash script for this:

mkdir apache
sudo scp -i ~/.ssh/[ssh-id] -r [remote-user]@[ip-address-of-your-server]:/etc/apache2/* apache/
mkdir letsencrypt
sudo scp -i ~/.ssh/[ssh-id] -r [remote-user]@[ip-address-of-your-server]:/etc/letsencrypt/* letsencrypt/

DATE=$(date +"%F_%H:%M:%S")
zip -r "$" apache/ letsencrypt/

sudo rm -rf apache/
sudo rm -rf letsencrypt/

Save this to a file on your local computer, modify it and execute it after configuration changes. This script creates a local copy of your Apache and Let’s Encrypt configuration.

This article is part of the Web server security series.
Read other articles of this series.


You can start to place your website in “/var/www/html.” We installed Apache and hardened its configuration. However, this isn’t all about web server security. In the next part, we discuss certificates, TLS, OCSP and other security-related headers in detail.

Remember: Your web server is publicly accessible and just another computer. This means that you have to regularly check for updates and keep your server software up to date!


  • Jul 27, 2019: Added information about legacy HTTP response headers (X-Xss-Protection and X-Frame-Options).
  • Jul 14, 2019: Rewrote several sections due to the release of Debian 10 and part 0 of this series.

Read also