Photo by Domenico Loia on Unsplash
Apache 2.4 access control
How to optimise Apache configuration by understanding the default configurations.
A customer has an AWS EC2 server running two websites on Apache 2.4: a static public HTML for corporate website and a Ruby on Rails app meant for internal use. These two are configured using Apache VirtualHost
with the RoR running using Passenger.
There are two issues that the customer would like us to fix:
- The static public HTML site has directory listing enabled although they had not enabled it in the
VirtualHost
directive. - The RoR app is accessible from public and they would like to restrict it to certain IP ranges.
This was the original configuration in the conf.d/vhost.conf
file:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName app.example.com
DocumentRoot /var/www/railsapp/public
PassengerRuby /usr/bin/ruby
<Directory /var/www/railsapp/public>
Allow from all
Options -MultiViews
Require all granted
RailsEnv production
</Directory>
...
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /var/www/static
<Directory "/var/www/static">
AllowOverride All
Require all granted
</Directory>
...
</VirtualHost>
</IfModule>
Why directory listing was enabled
According to documentation the default for Options
is FollowSymlinks
if the directive is not set, and the directory listing should not be enabled.
On checking, I found that the customer has edited conf/httpd.conf
as below:
#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "/var/www/static"
#
# Relax access to content within /var/www/static.
#
<Directory "/var/www/static">
AllowOverride None
# Allow open access:
Require all granted
</Directory>
# Further relax access to the default document root:
<Directory "/var/www/static">
#
# Possible values for the Options directive are "None", "All",
# or any combination of:
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
# The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs/2.4/mod/core.html#options
# for more information.
#
Options Indexes FollowSymLinks
#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
# Options FileInfo AuthConfig Limit
#
AllowOverride None
#
# Controls who can get stuff from this server.
#
Require all granted
</Directory>
Thus the problem is that Options
was actually specified in conf/httpd.conf
. This comes from the default configuration when installing Apache. The customer had merely edited the Directory
path. This could be an easy fix by just commenting the Options
line but I find the entire chunk above necessary. This is because both VirtualHost
directives are already using wildcard (*) IP matching which means it will definitely match one of them. As per the documentation, the match will be the first listed virtual host if there are no matching ServerName
or ServerAlias
. Hence I removed the entire chunk in conf/httpd.conf
and moved the VirtualHost
section of static website above the RoR instead.
Apache 2.2 versus 2.4 access control
I also reviewed the directives in the VirtualHost configurations and found that there are some unnecessary directives:
- The first is that
Allow from all
is from Apache 2.2 and deprecated in Apache 2.4. The replacement isRequire all granted
. - Next is the line
Options -MultiViews
. It is unnecessary because theOptions
directive default is set toFollowSymLinks
from 2.3.11 onwards. FurthermoreMultiViews
must be explicitly enabled. There is no need to disable it if it wasn't enabled anywhere. - Lastly I removed
AllowOverride All
since there is no.htaccess
file in the static website.
Restricting Ruby on Rails access by IP
To limit access to RoR by IP addresses, I used the AllowOverrideList
as it is more specific. The directive AllowOverride
is set to None
by default in version 2.3.9 onwards and therefore not necessary to include in the configuration.
The edited conf.d/vhost.conf
is as below:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /var/www/static
<Directory "/var/www/static">
Require all granted
</Directory>
...
</VirtualHost>
<VirtualHost *:443>
ServerName app.example.com
DocumentRoot /var/www/railsapp/public
PassengerRuby /usr/bin/ruby
<Directory /var/www/railsapp/public>
AllowOverrideList Require
Require all granted
RailsEnv production
</Directory>
...
</VirtualHost>
</IfModule>
And all that is needed now is .htaccess
to be placed in the public
folder of the RoR app:
Require ip x.y.z.0/24