Upgrading old Apache 2.2 configurations to httpd 2.4
Apache httpd 2.2 is end-of-life: its final release, 2.2.34, came out in July 2017 and gets no more security fixes. Most 2.2 configuration files run on 2.4 after a handful of edits, and nearly all of them are in one place: access control, where Order, Allow and Deny give way to Require.
- 2.2.34final 2.2 release (July 2017)
- 2.4.69current 2.4 release, October 1, 2026 (as of November 2026)
Plan the move
Few people compile a new 2.4 over a running 2.2. A typical upgrade means an old server is being replaced by a current distribution that ships 2.4, and its configuration has to come along. Before you copy anything, record what the old server actually does:
# build settings, MPM, default paths (on old Debian: apache2ctl -V)
httpd -V
# loaded modules
httpd -M
# virtual hosts and which config file defines each one
httpd -S
Then work through the changes below on a test machine or a second virtual host. Third-party modules compiled for 2.2 must be rebuilt for 2.4 before they will load. Many work unchanged once recompiled, but some need code changes, so get each one from your distribution or its project in a 2.4 build.
A clean approach: start from the 2.4 default configuration your package installs, then port your virtual hosts and custom settings into it one at a time. You avoid dragging along 2.2 defaults that no longer exist.
Access control: Order, Allow, Deny
In 2.2, host-based access used Order, Allow and Deny (module mod_authz_host, called mod_access before 2.2), and Satisfy combined them with password checks. In 2.4 the same checks are authorization providers of the Require directive (modules mod_authz_core and mod_authz_host). The old directives survive only in mod_access_compat, which is marked deprecated.
| 2.2 | 2.4 |
|---|---|
Order deny,allowDeny from all | Require all denied |
Order allow,denyAllow from all | Require all granted |
Order Deny,AllowDeny from allAllow from example.org | Require host example.org |
Allow from 192.168.1 | Require ip 192.168.1 |
Allow from 10.0.0.0/8 | Require ip 10.0.0.0/8 |
Allow from 127.0.0.1 ::1 | Require local (127.0.0.0/8, ::1, or same address as the server) |
To block a few addresses and let everyone else in, combine rules in a <RequireAll> block. Several Require lines with no container around them act like <RequireAny>: one match is enough.
<Directory "/var/www/example">
<RequireAll>
Require all granted
Require not ip 198.51.100.0/24
</RequireAll>
</Directory>
Passwords plus addresses (Satisfy)
Where 2.2 used Order allow,deny + Allow from all only to switch host checks off before a password prompt, just delete those lines. Where both checks really mattered, translate Satisfy:
# 2.2 "Satisfy All": a valid password AND an office address
AuthType Basic
AuthName "Staff only"
AuthBasicProvider file
AuthUserFile "/etc/apache2/.htpasswd"
<RequireAll>
Require valid-user
Require ip 192.0.2.0/24
</RequireAll>
# 2.2 "Satisfy Any": a valid password OR an office address
AuthType Basic
AuthName "Staff only"
AuthBasicProvider file
AuthUserFile "/etc/apache2/.htpasswd"
Require valid-user
Require ip 192.0.2.0/24
On RHEL and Fedora the password file would normally live under /etc/httpd/. The Authz*Authoritative directives were removed; RequireAll, RequireAny and RequireNone replace them. If you used mod_authz_dbm, write Require dbm-group instead of Require group.
Do not mix old and new
Debian and Ubuntu enable mod_access_compat on a fresh install, and Fedora/RHEL load it in /etc/httpd/conf.modules.d/00-base.conf. That is why an unconverted 2.2 file often starts without errors. The trap comes when old and new directives meet in the merge order. The 2.4 upgrade notes show a case where Deny from all on <Directory "/"> overrides Require local on /server-status: you get a 403, and error_log logs AH01797 ("client denied by server configuration").
Convert everything in one pass. Find the old lines:
grep -rniE '^\s*(order|allow from|deny from|satisfy)\b' /etc/apache2 # Debian/Ubuntu
grep -rniE '^\s*(order|allow from|deny from|satisfy)\b' /etc/httpd # RHEL/Fedora
Remember .htaccess files under your document roots too. When grep finds nothing, unload the module so stray old lines fail loudly at startup instead of half-working:
sudo a2dismod access_compat # Debian/Ubuntu
# RHEL/Fedora: comment out the access_compat LoadModule line in
# /etc/httpd/conf.modules.d/00-base.conf
More examples are in the access control guide.
Removed and renamed directives
| 2.2 directive | In 2.4 |
|---|---|
NameVirtualHost | No effect; prints warning AH00548. Delete it: any address/port used by several virtual hosts is name-based automatically. |
MaxClients | Renamed MaxRequestWorkers (old name still accepted). |
MaxRequestsPerChild | Renamed MaxConnectionsPerChild (old name still accepted). |
DefaultType | Only a warning (AH00117) unless set to none. Delete it; set types with AddType or ForceType. |
AcceptMutex, LockFile, RewriteLock, SSLMutex, SSLStaplingMutex, WatchdogMutexPath | Replaced by one Mutex directive. Often you can just delete them. |
RewriteLog, RewriteLogLevel | Removed. Use LogLevel alert rewrite:trace3; output goes to error_log. |
KeepAlive 5 or similar | Only On or Off is accepted now. |
| mod_mem_cache | Removed; use mod_cache_disk. |
AuthnProviderAlias (mod_authn_alias) | Moved into mod_authn_core. |
AddOutputFilterByType | Moved from the core to mod_filter, which must be loaded. |
DumpIOLogLevel | Removed; mod_dumpio logs at LogLevel trace7. |
Lines that are now invalid stop the server with Invalid command 'RewriteLog', perhaps misspelled or defined by a module not included in the server configuration. That is useful: configtest finds them all for you, one per run.
Defaults that changed
- AllowOverride now defaults to None. If your site relied on
.htaccessfiles without saying so, they are silently ignored in 2.4. SetAllowOverrideexplicitly where you need them (see .htaccess files). - EnableSendfile defaults to Off.
- FileETag defaults to "MTime Size" (the inode is no longer part of ETags).
- Piped logs run directly, not through
/bin/sh -c. ACustomLog "|..."line that used shell features needs rewriting. - htpasswd uses MD5 by default; since 2.4.4 it also supports bcrypt (
htpasswd -B). - mod_reqtimeout sets default timeouts once loaded.
- SSI conditions in mod_include use the new expression parser.
SSILegacyExprParser onrestores the 2.2 syntax for a directory; this matters for 2.2's multi-language error pages. - mod_cache:
CacheIgnoreURLSessionIdentifiersnow matches exactly, andCacheEnablewith/no longer covers forward-proxy content. - Header-to-variable translation is stricter: request header names containing underscores or other invalid characters are no longer passed to CGI, SSI and similar modules.
MPM changes
In 2.4 the MPM (the module that decides how processes and threads handle connections) can be a loadable module, so you change it with LoadModule instead of recompiling. The event MPM, experimental in 2.2, is fully supported, and it is the default on fresh Debian installs and on current Fedora and RHEL packages. It hands idle keep-alive connections to a listener thread, so worker threads are not tied up waiting for them.
# Debian/Ubuntu: switch from prefork to event
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
# RHEL/Fedora: uncomment exactly one LoadModule line in
# /etc/httpd/conf.modules.d/00-mpm.conf
With a threaded MPM (event or worker), CGI runs through mod_cgid instead of mod_cgi; see CGI and SSI. Re-size MaxRequestWorkers, ThreadsPerChild and ServerLimit for the new MPM rather than copying 2.2 prefork numbers (performance tuning).
mod_ssl changes
- SSLv2 is gone. Since 2.4.17 the
SSLProtocoldefault isall -SSLv3. A TLS 1.3 server needs httpd 2.4.43 or newer with OpenSSL 1.1.1 or newer. SSLCertificateChainFilehas been obsolete since 2.4.8: put the intermediate certificates in the file named bySSLCertificateFile, after the server certificate (Let's Encrypt'sfullchain.pemis already in that form).SSLSessionCache shmcb:...needs mod_socache_shmcb loaded. Debian'sa2enmod sslpulls it in.SSLMutexis replaced byMutex;SSLCompressiondefaults tooff.- CRL checking must be switched on explicitly with
SSLCARevocationCheck. SSLProxyCheckPeerCNandSSLProxyCheckPeerExpiredefault toOn: proxying to an HTTPS backend with a bad or expired certificate now returns 502 Bad Gateway.- The default format of the
*_DNvariables changed;SSLOptions +LegacyDNStringFormatbrings back the old one.
A minimal 2.4 HTTPS virtual host:
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot "/var/www/example"
SSLEngine on
SSLCertificateFile "/etc/letsencrypt/live/www.example.com/fullchain.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/www.example.com/privkey.pem"
SSLProtocol -all +TLSv1.2 +TLSv1.3
</VirtualHost>
Cipher and header recommendations are in HTTPS and TLS.
Debian and Ubuntu specifics
On Debian-based systems the Include lines in apache2.conf only read files ending in .conf. A 2.2-era site file named /etc/apache2/sites-available/example is ignored until you rename it:
sudo mv /etc/apache2/sites-available/example /etc/apache2/sites-available/example.conf
sudo a2ensite example
sudo apache2ctl -t && sudo systemctl reload apache2
mod_disk_cache from 2.2 is called mod_cache_disk in 2.4. In 2.4, an Include with a wildcard that matches no file is an error; use IncludeOptional for directories that may be empty.
Configs from Apache 1.3 or 2.0
Very old files need the 2.2 changes above plus earlier ones. Work through them in order:
- From 1.3:
PortandBindAddressare gone; useListen, and put the port inServerName www.example.com:80for self-referencing URLs.ServerTypeis gone (there is no inetd mode).AccessConfigandResourceConfigare gone;Includethe oldsrm.confandaccess.confif you still have them, or better, merge them.AddModuleandClearModuleListare gone. TheFancyIndexingdirective becameIndexOptions FancyIndexing.AgentLog,RefererLogandRefererIgnoreare gone; useCustomLog. Proxy access control moved from<Directory proxy:>to<Proxy>.ErrorDocumenttext messages need a closing quote:ErrorDocument 403 "Some message". - From 2.0: mod_access became mod_authz_host; mod_auth was split into mod_auth_basic, mod_authn_file, mod_authz_user and mod_authz_groupfile; mod_auth_ldap became mod_authnz_ldap; mod_imap became mod_imagemap.
AuthDigestFilemerged intoAuthUserFile.UseCanonicalNamedefaults toOff.apachectl startsslno longer exists; enable mod_ssl in the config and use a normal start.
1.3 modules do not work on 2.x at all: the module API changed completely in 2.0.
Test, then switch
Run the config test after each batch of edits, and only reload when it says Syntax OK:
sudo apache2ctl -t && sudo systemctl reload apache2 # Debian/Ubuntu
sudo apachectl configtest && sudo systemctl reload httpd # RHEL/Fedora
sudo apachectl -S # check that every vhost landed where you expect
| Message | Fix |
|---|---|
Invalid command 'Order' (or 'Allow', 'Deny') | Convert to Require, or temporarily load mod_access_compat. |
Invalid command 'Require' | Load mod_authz_core and mod_authz_host. |
Invalid command 'User' | Load mod_unixd (compiled in on Debian packages). |
Invalid command 'AddOutputFilterByType' | Load mod_filter. |
configuration error: couldn't check user | Load mod_authn_core. |
.htaccess rules do nothing | Set AllowOverride for that directory. |
| 403 with AH01630 or AH01797 in error_log | A Require rule (AH01630) or an old Deny (AH01797) refused the request; check the merge order of your sections. |
Finally, compare responses between old and new servers for your important URLs (curl -I https://www.example.com/path) before moving DNS or the IP address.
Sources
- Upgrading to 2.4 from 2.2, Apache HTTP Server documentation
- Overview of new features in Apache HTTP Server 2.4
- mod_access_compat, Apache HTTP Server 2.4 documentation
- mod_authz_host, Apache HTTP Server 2.4 documentation
- mod_ssl, Apache HTTP Server 2.4 documentation
- event MPM, Apache HTTP Server 2.4 documentation
- Core features (Include, IncludeOptional), Apache HTTP Server 2.4 documentation
- Upgrading to 2.2 from 2.0, Apache HTTP Server documentation
- Upgrading to 2.0 from 1.3, Apache HTTP Server documentation
- Apache HTTP Server Project home page (2.4.69 release, 2.2 end-of-life)
- Debian apache2 README.Debian (.conf suffix rule)
- Debian apache2 postinst (default MPM and modules)
- Fedora httpd package spec (default MPM)