How To Migrate your Apache Configuration from 2.2 to 2.4 Syntax.
Table of Contents
Introduction #
The Apache web server is currently the most popular web server in the world. It is used to serve web content of all kinds and is a powerful application that is highly customizable.
Many people are familiar with the Apache 2.2 configuration syntax, but some distributions are now shipping with Apache 2.4 by default. An example of this transition is Ubuntu 14.04 LTS coming from Ubuntu 12.04 LTS. While in most cases the syntax is the same, there are some important differences and some common directives have been deprecated.
In this guide, we will discuss some of the new syntax and some of the other changes that you should know about when coming from an Apache 2.2 background. We will use Ubuntu 14.04 as an example of a distribution with Apache 2.4, and compare it against the 2.2 version of Apache that ships with releases like Ubuntu 12.04.
Authorization Changes #
One of the major changes that Apache 2.4 makes is the preferred way of authorizing users.
Authorization refers to the directives that define what an authenticated user can do. It lays out criteria to check to decide if operations or access should be allowed.
This is different from authentication, which must happen first. Authentication procedures define how a user is able to positively identify themselves to the server. Authentication has not changed much from 2.2, while authorization has gotten an overhaul.
First of all, authorization components can now use the Require
syntax that was previously made available for authentication. This creates an easy way to define authorization order rather than relying on complex rule sets. You can instead order them in a logical way, specifying a default and then exceptions.
For instance, you can set a default for accepting traffic, but wish to block a specific malicious user, you can add something like this:
Require all granted
Require not ip 111.111.111.111
This will set a default policy of accepting everybody and then specify a qualifier that the request is not coming from the 111.111.111.111
IP address. To do this, you will need to require both of these to be true, which we will learn how to do momentarily with the RequireAll
directive block.
Authorization can be selected not only based on the user or group itself, but also taking into consideration the other factors by using env
, host
, or ip
, or with the catch-all value all
.
all: This provider matches all traffic. It is useful for setting default values.
env: This tests whether an environmental variable is set.
host: This is used to test the host name of a connecting client.
ip: This is used to test the IP address of the connecting user.
These can be controlled based on the order that they are specified. You will usually see them inside of one of these special blocks:
RequireAll: All of the authorization requirements in the block must be fulfilled to allow access.
RequireAny: If any of the authorization requirements in this block are met, this block is marked as satisfied.
RequireNone: If any of the requirements listed succeed, the directive will fail.
This let’s you have quite a bit of flexibility in regards to how you set up authorization. You can nest these directive blocks within one another like this:
<RequireAny>
<RequireAll>
Require user root
Require ip 123.123.123.123
</RequireAll>
<RequireAll>
<RequireAny>
Require group sysadmins
Require group useraccounts
Require user anthony
</RequireAny>
<RequireNone>
Require group restrictedadmin
Require host bad.host.com
</RequireNone>
</RequireAll>
</RequireAny>
As you can see, we can define some pretty elaborate authorization paths. The above example will authorize if the user is root and coming from the IP 123.123.123.123
. It will also authorize a user named “anthony” or any members of the groups “sysadmins” or “useraccounts”, but ONLY if they are not also part of the “restrictedadmin” group or coming from a flagged host at bad.host.com
.
These authentication blocks are much easier to understand than the classic directives that were used for access control. In past versions of Apache, you would use the Order
, Allow from
, Deny from
, and Satisfy
directives. These have not been removed, but have been deprecated in favor of the new syntax, which is easier to understand and more consistent.
They have however, been moved to a separate module called mod_access_compat
. Make sure you enable this module if you require the legacy authorization directives. However, I would suggest implementing your conditions in the new syntax, both for future support, and because it is significantly easier to figure out the implications of the policies you are selecting.
Other Changes in Apache #
There are a variety of other changes that you should be aware of that will affect how you build your configuration files.
Some of these may require you to change names or override new defaults. There is a more complete list of the changes here, but we will discuss some of the ones that may trip you up.
Connection and Child Limiting #
A few directives have undergone name changes to better describe their functionality.
MaxConnectionsPerChild: This directive is used to replace the MaxRequestsPerChild
. This change was made in order to better reflect what the directive actually is used for. Since the values actually limit the number of connections, this is a better name for the parameter.
MaxRequestWorkers: This directive was created to replace the MaxClients
option. This is because with asynchronous multi-processing modules, the number of clients should not be assumed to be the same as the number of worker threads. This helps specify exactly the portion of this configuration that is affected by the directive.
AllowOverride Changes #
The AllowOverride
directive that is used to permit directory specific configuration files to alter default settings, has undergone a slight change that might affect your configurations.
By default, the value for this setting is now None
. This will allow you to secure your server more easily by defaulting to a more locked-down state. It is still very simple to specify that .htaccess
files should be read and processed in directories that require it, but you should need fewer global and large-scoped AllowOverride None
declarations in order to achieve this.
The strategy of locking down the server by default and then overriding the security to allow specific instances of directory-based settings is something most users do already. This change will only help ensure that users are not open to attack as easily should they forget to implement these manually.
SendFile Default Changed #
The EnableSendfile
directive that is used to send a file on the server to a client without having to read the contents is now defaulted to Off
.
This is a security measure that is used to ensure that the system in question supports the operation correctly. Incorrect implementation can be a liability or can cause operations to fail. These can be operating system-specific, dependant on specific hardware, or different due to the method of accessing the content (remote filesystems, etc).
Defaulting this directive to disabled allows the administer to verify their system’s compatibility and do some testing to ensure proper functionality prior to enabling.
Implementation Details #
While these are not exactly specific to the Apache 2.4 release, some of the default configuration files that are shipping with distributions have been changed when the transition was made.
One instance of this is in Debian and Ubuntu releases, Apache 2.4’s main configuration file at /etc/apache2/apache2.conf
now handles including additional files slightly differently.
In 2.2, these distributions sourced any files within the conf.d
and sites-enabled
directory to allow additional configuration files, most commonly used for virtualhost specifications. These directives looked like this:
Include conf.d/
Include sites-enabled/
Wildcard matching is a new feature that allows you to include specific file patterns instead of having to pass a whole directory in its entirety. This means that while traditionally, you could get by with something like the above, you could have more flexibility by using:
Include conf.d/*.conf
Include sites-enabled/*.conf
However, this new syntax also can cause some problems if you are expecting it to work exactly like before. The Include
directive, when used with wildcard matching, will fail if no matching file is found, resulting in an error.
To get around this, a new directive called IncludeOptional
was created. This works exactly the same, but will not result in a failure if the wildcard does not match any files.
To take advantage of this, some distributions have begun to include additional directories with:
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf
As you can see, there is an additional implementation tweak that has been added here: the creation of separate conf-enabled
and conf-available
directories to mirror the sites-*
and mods-*
directories. The main takeaway here though is that specific file patterns are now being specified. All valid configuration files are required to end in .conf
with this configuration.
This might take some getting used to if you typically called your virtualhost files things like default
, or site1.com
. However, this provides a greater amount of flexibility, because we can have non-configuration files in the directory, like old versions, tests, and README files.
This means that for testing, you can simply do something like:
cd /etc/apache2/sites-enabled/
cp mainconfig.conf mainconfig.conf.bak
nano mainconfig.conf
While you could go through the a2dissite
and a2ensite
operations, this is an additional method that may be more natural for some people. It also keeps your old working file in the enabled directory, which, while not being exactly semantic, may be easier to find to reimplement if you need to revert to your old version.
Another change that you may notice in your configurations is that some of the directives have been moved around, and some of the default virtualhost directives have changed. These three blocks, which in the past were in the default virtualhost file, are no longer present:
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
The top two blocks are now implemented within the apache2.conf
file in recent versions of Ubuntu, since they should be set in any configuration. They have been updated to use the Require
directives:
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
The cig-bin
directory specification has been removed from the virtualhost file and implemented in the conf-available/serve-cgi-bin.conf
file. This is a more modular approach and leaves the virtualhost file responsible for only the directives that are unique. In fact, the new default virtualhost, with all comments removed, is simply:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
As you can see, this can really help us to pare down our site-specific configuration files.
Conclusion #
By auditing your existing configurations and updating certain procedures to take advantage of the new directives and best practices, migrating to Apache 2.4 is not too difficult. Functionally, it should provide the same capabilities with additional features and do it all with easier to understand syntax.