Apache2 – Website Configuration

I use different configurations for each site I host on my server, but most of them are nearly identical. Here I want to share the basic version I use.

For this, you must enable 2 mods in Apache2:

MODCommand
mod_rewritesudo a2enmod rewrite
mod_sslsudo a2enmod ssl
mod_headerssudo a2enmode headers

Do not forget to reload/restart Apache2. Your terminal should let you know anyways if this is necessary.

Non-SSL Configuration

This configuration is only there to redirect clients from http to https.

The example you see below is used for my (currently discontinued) project on https://auth.calucon.de:

<VirtualHost *:80>
	ServerAdmin simon@calucon.de
	ServerName auth.calucon.de
	DocumentRoot /var/www/auth/html

	ErrorLog ${APACHE_LOG_DIR}/auth_error.log
	CustomLog ${APACHE_LOG_DIR}/auth_access.log combined

	# Here we send the redirect header to https
	RewriteEngine on
	RewriteCond %{SERVER_NAME} =auth.calucon.de [NC]
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [NC,END,QSA,R=permanent]

	# Security Related Headers
	Header always set X-Frame-Options "SAMEORIGIN"
	Header always set X-Content-Type-Options "nosniff"
	Header always set X-XSS-Protection "1; mode=block"
	Header always set Referrer-Policy "strict-origin-when-cross-origin"

	# Cache Control Header 
	# only 1d for testing purposes
	Header always set Cache-Control "max-age=86400"

</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

SSL Configuration

Now we get to the interesting part, the actual configuration. This configuration file will be applied to basically all visitors on your site. (An exception might be clients that do not follow the redirect to the https site and that case is mere non-existent)

So let’s have a look at the configuration file:

<IfModule mod_ssl.c>
<VirtualHost *:443>
	ServerAdmin simon@calucon.de
	ServerName auth.calucon.de
	DocumentRoot /var/www/auth/html

	<Directory "/var/www/auth/html">
		# General rules to e.g. disallow clients to view the folder structure
        Options -Indexes +FollowSymLinks +MultiViews
        AllowOverride None

        # Showing an Error-Page if any of these errors occur
        ErrorDocument 401 /error
        ErrorDocument 402 /error
        ErrorDocument 403 /error
        ErrorDocument 404 /error
        ErrorDocument 500 /error

        # Collection of Rewrite Rules to make the URL pretty
        # Put them in the config, it's more efficent than using a .htaccess file
        RewriteEngine on
        RewriteRule ^index(\/*)(.*)$ index.php [NC,QSA]
        RewriteRule ^error(?:\/*)$ index.php?s=error [NC,QSA]
        RewriteRule ^about(?:\/*)$ index.php?s=about [NC,QSA]
		RewriteRule ^docs(?:\/*)$ index.php?s=documentation [NC,QSA]
        RewriteRule ^login(?:\/*)$ index.php?s=account/login [NC,QSA]
        RewriteRule ^logout(?:\/*)$ index.php?s=account/logout [NC,QSA]
        RewriteRule ^register(?:\/*)$ index.php?s=account/register [NC,QSA]
        RewriteRule ^verify\/([a-zA-Z0-9\-]*)$ index.php?s=account/verify&token=$1 [NC,QSA]
        RewriteRule ^reset\/password(?:\/*)$ index.php?s=account/reset/password_reset [NC,QSA]
        RewriteRule ^reset\/password\/([a-zA-Z0-9\-]*)(?:\/*)$ index.php?s=account/reset/password_reset_token&resetToken=$1 [NC,QSA]
        RewriteRule ^change\/(mail|username|password)(?:\/*)$ index.php?s=account/change/$1 [NC,QSA]
        RewriteRule ^validate\/mail(?:\/*)$ index.php?s=account/validate/mail [NC,QSA]
        RewriteRule ^profile(?:\/*)$ index.php?s=account/profile [NC,QSA]

        RewriteRule ^app\/(view|used|create)(?:\/*)$ index.php?s=app/$1 [NC,QSA]
        RewriteRule ^app\/(edit|login|revoke)\/(.{32})(?:\/*)$ index.php?s=app/$1&token=$2 [NC,QSA]

        RewriteRule ^api\/(.+)(?:\/*)$ apix.php?s=$1 [NC,QSA]
        #RewriteRule ^profile\/((?:(?!\/).)*?(?:\s|%2520)*?)$ index.php?s=account/profile&u=$1 [NC,QSA]
	</Directory>

	ErrorLog ${APACHE_LOG_DIR}/auth_error.log
	CustomLog ${APACHE_LOG_DIR}/auth_access.log combined

	# Add Let'sEncrypt Certificate and apply ssl seciruty rules provied by Let'sEncrypt
	SSLCertificateFile /etc/letsencrypt/live/auth.calucon.de/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/auth.calucon.de/privkey.pem
	Include /etc/letsencrypt/options-ssl-apache.conf

	# CSP not enforced here as this header gets set by my PHP application!
	#Header always set Content-Security-Policy "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; font-src 'self' data:; frame-ancestors 'self'; base-uri 'self'; form-action 'self'"

	# Security Related Headers
	Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
	Header always set X-Frame-Options "SAMEORIGIN"
	Header always set X-Content-Type-Options "nosniff"
	Header always set X-XSS-Protection "1; mode=block"
	Header always set Referrer-Policy "strict-origin-when-cross-origin"

	#Cache Control Header
	# only 1d for testing purposes
	Header always set Cache-Control "max-age=86400"

</VirtualHost>

# vim: syntax=apache ts=4 sw
</IfModule>

You may have noticed, that I disabled the CSP header which should always be set, especially for security reasons!
This is because some parts of the website require a variable form-action to be set for specific pages.

Basically, there is a form that will redirect the client to a remote site and this form includes a login-token. To transfer this token securely, we can not add it the URL (GET request) as this is unsafe, so we must make a POST request which is best achieved using a Form. The form data is sent to the external URL upon submit and if the external URL is not part of the CSP, we are not allowed to submit the form.

Leave a Comment