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
VirtualHostdirective. - 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 allis 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 theOptionsdirective default is set toFollowSymLinksfrom 2.3.11 onwards. FurthermoreMultiViewsmust be explicitly enabled. There is no need to disable it if it wasn't enabled anywhere. - Lastly I removed
AllowOverride Allsince there is no.htaccessfile 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