Configure Apache HTTP/2 with performance optimization and modern security headers

Intermediate 25 min Apr 07, 2026 75 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Enable HTTP/2 protocol in Apache with SSL/TLS encryption, implement advanced performance optimization settings including compression and caching, and configure modern security headers for production deployments.

Prerequisites

  • Root or sudo access
  • Basic Apache knowledge
  • SSL certificate or ability to generate one

What this solves

HTTP/2 provides significant performance improvements over HTTP/1.1 through multiplexing, server push, and header compression. This tutorial configures Apache with HTTP/2 support, SSL/TLS encryption, performance optimization settings, and modern security headers for production environments.

Step-by-step configuration

Update system packages and install Apache

Start by updating your system and installing Apache with SSL support.

sudo apt update && sudo apt upgrade -y
sudo apt install -y apache2 apache2-utils ssl-cert
sudo dnf update -y
sudo dnf install -y httpd mod_ssl openssl

Enable HTTP/2 and SSL modules

Enable the required modules for HTTP/2, SSL, and performance optimization.

sudo a2enmod ssl
sudo a2enmod http2
sudo a2enmod rewrite
sudo a2enmod deflate
sudo a2enmod expires
sudo a2enmod headers
sudo a2enmod cache
sudo a2enmod cache_disk
sudo sed -i 's/#LoadModule ssl_module/LoadModule ssl_module/' /etc/httpd/conf.modules.d/00-ssl.conf
echo "LoadModule http2_module modules/mod_http2.so" | sudo tee /etc/httpd/conf.modules.d/10-http2.conf
echo "LoadModule rewrite_module modules/mod_rewrite.so" | sudo tee -a /etc/httpd/conf.modules.d/00-base.conf

Generate SSL certificate

Create a self-signed SSL certificate for testing. Replace with a proper certificate from Let's Encrypt or your CA in production.

sudo mkdir -p /etc/ssl/private
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/ssl/private/apache-selfsigned.key \
  -out /etc/ssl/certs/apache-selfsigned.crt \
  -subj "/C=US/ST=State/L=City/O=Organization/CN=example.com"

Configure Apache main settings

Set up the main Apache configuration with HTTP/2 support and performance optimizations.

# HTTP/2 Configuration
Protocols h2 h2c http/1.1
H2Direct on
H2Upgrade on
H2StreamMaxMemSize 512000
H2MaxSessionStreams 100
H2InitialWindowSize 65536
H2MaxWorkerIdleSeconds 600

Performance Optimizations

ServerTokens Prod ServerSignature Off KeepAlive On KeepAliveTimeout 5 MaxKeepAliveRequests 100 Timeout 300

Compression Settings

DeflateCompressionLevel 6 SetEnvIfNoCase Request_URI \ \.(?:gif|jpe?g|png|webp|ico|svg)$ no-gzip dont-vary SetEnvIfNoCase Request_URI \ \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
# HTTP/2 Configuration
Protocols h2 h2c http/1.1
H2Direct on
H2Upgrade on
H2StreamMaxMemSize 512000
H2MaxSessionStreams 100
H2InitialWindowSize 65536
H2MaxWorkerIdleSeconds 600

Performance Optimizations

ServerTokens Prod ServerSignature Off KeepAlive On KeepAliveTimeout 5 MaxKeepAliveRequests 100 Timeout 300

Compression Settings

DeflateCompressionLevel 6 SetEnvIfNoCase Request_URI \ \.(?:gif|jpe?g|png|webp|ico|svg)$ no-gzip dont-vary SetEnvIfNoCase Request_URI \ \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary

Configure SSL virtual host with HTTP/2

Create a virtual host configuration with SSL, HTTP/2, and security headers.


    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html
    
    # SSL Configuration
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt
    SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key
    
    # Modern SSL Configuration
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder off
    SSLSessionTickets off
    SSLUseStapling on
    SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
    
    # HTTP/2 Protocol
    Protocols h2 http/1.1
    
    # Security Headers
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    Header always set X-Frame-Options DENY
    Header always set X-Content-Type-Options nosniff
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    
    # Compression
    
        SetOutputFilter DEFLATE
        SetEnvIfNoCase Request_URI \
            \.(?:gif|jpe?g|png|webp|ico|svg)$ no-gzip dont-vary
        SetEnvIfNoCase Request_URI \
            \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
        DeflateFilterNote Input instream
        DeflateFilterNote Output outstream
        DeflateFilterNote Ratio ratio
    
    
    # Caching
    
        ExpiresActive On
        ExpiresByType text/css "access plus 1 month"
        ExpiresByType application/javascript "access plus 1 month"
        ExpiresByType image/png "access plus 1 year"
        ExpiresByType image/jpg "access plus 1 year"
        ExpiresByType image/jpeg "access plus 1 year"
        ExpiresByType image/gif "access plus 1 year"
        ExpiresByType image/webp "access plus 1 year"
        ExpiresByType image/svg+xml "access plus 1 year"
        ExpiresByType application/pdf "access plus 1 month"
        ExpiresByType text/html "access plus 1 hour"
    
    
    # Logging
    LogLevel info ssl:warn http2:info
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html
    
    # SSL Configuration
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt
    SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key
    
    # Modern SSL Configuration
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder off
    SSLSessionTickets off
    SSLUseStapling on
    SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
    
    # HTTP/2 Protocol
    Protocols h2 http/1.1
    
    # Security Headers
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    Header always set X-Frame-Options DENY
    Header always set X-Content-Type-Options nosniff
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    
    # Compression
    
        SetOutputFilter DEFLATE
        SetEnvIfNoCase Request_URI \
            \.(?:gif|jpe?g|png|webp|ico|svg)$ no-gzip dont-vary
        SetEnvIfNoCase Request_URI \
            \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
        DeflateFilterNote Input instream
        DeflateFilterNote Output outstream
        DeflateFilterNote Ratio ratio
    
    
    # Caching
    
        ExpiresActive On
        ExpiresByType text/css "access plus 1 month"
        ExpiresByType application/javascript "access plus 1 month"
        ExpiresByType image/png "access plus 1 year"
        ExpiresByType image/jpg "access plus 1 year"
        ExpiresByType image/jpeg "access plus 1 year"
        ExpiresByType image/gif "access plus 1 year"
        ExpiresByType image/webp "access plus 1 year"
        ExpiresByType image/svg+xml "access plus 1 year"
        ExpiresByType application/pdf "access plus 1 month"
        ExpiresByType text/html "access plus 1 hour"
    
    
    # Logging
    LogLevel info ssl:warn http2:info
    ErrorLog /var/log/httpd/error.log
    CustomLog /var/log/httpd/access.log combined

Configure HTTP to HTTPS redirect

Set up automatic redirection from HTTP to HTTPS for security.


    ServerName example.com
    ServerAlias www.example.com
    
    # Security Headers for HTTP
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    
    # Redirect to HTTPS
    Redirect permanent / https://example.com/
    
    # Logging
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    ServerName example.com
    ServerAlias www.example.com
    
    # Security Headers for HTTP
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    
    # Redirect to HTTPS
    Redirect permanent / https://example.com/
    
    # Logging
    ErrorLog /var/log/httpd/error.log
    CustomLog /var/log/httpd/access.log combined

Configure MPM for HTTP/2 optimization

Tune the Multi-Processing Module settings for optimal HTTP/2 performance.

sudo a2dismod mpm_prefork
sudo a2enmod mpm_event

    StartServers             3
    MinSpareThreads         75
    MaxSpareThreads        250
    ThreadsPerChild         25
    MaxRequestWorkers      400
    MaxConnectionsPerChild   0
    AsyncRequestWorkerFactor 2
# Comment out prefork module
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so

Enable event module

LoadModule mpm_event_module modules/mod_mpm_event.so

    StartServers             3
    MinSpareThreads         75
    MaxSpareThreads        250
    ThreadsPerChild         25
    MaxRequestWorkers      400
    MaxConnectionsPerChild   0
    AsyncRequestWorkerFactor 2

Enable sites and restart Apache

Enable the configurations and restart Apache to apply changes.

sudo a2enconf http2
sudo a2ensite https-example
sudo a2ensite http-redirect
sudo apache2ctl configtest
sudo systemctl restart apache2
sudo systemctl enable apache2
sudo httpd -t
sudo systemctl restart httpd
sudo systemctl enable httpd
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Create test content

Create sample content to test HTTP/2 functionality and performance features.

sudo mkdir -p /var/www/html/css /var/www/html/js



    
    
    HTTP/2 Test Page
    
    


    

Apache HTTP/2 Configuration Test

This page tests HTTP/2, compression, and security headers.

body {
    font-family: Arial, sans-serif;
    margin: 40px;
    background-color: #f4f4f4;
}

h1 {
    color: #333;
    border-bottom: 2px solid #007acc;
    padding-bottom: 10px;
}

#protocol-info {
    background: #007acc;
    color: white;
    padding: 20px;
    border-radius: 5px;
    margin-top: 20px;
}
document.addEventListener('DOMContentLoaded', function() {
    const protocolInfo = document.getElementById('protocol-info');
    const protocol = window.location.protocol;
    const host = window.location.host;
    
    protocolInfo.innerHTML = `
        

Connection Information

Protocol: ${protocol}

Host: ${host}

User Agent: ${navigator.userAgent}

`; });

Set correct file permissions

Set proper ownership and permissions for web files. Never use chmod 777 as it gives unnecessary access to all users.

Never use chmod 777. It gives every user on the system full access to your files. Instead, fix ownership with chown and use minimal permissions.
sudo chown -R www-data:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
sudo chown -R apache:apache /var/www/html
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;

Verify your setup

Test your HTTP/2 configuration and performance optimizations.

# Check Apache status and configuration
sudo systemctl status apache2  # or httpd on RHEL-based
sudo apache2ctl configtest     # or httpd -t on RHEL-based

Test HTTP/2 support

curl -I --http2 -k https://example.com/

Check enabled modules

apache2ctl -M | grep -E '(http2|ssl|deflate|headers|expires)' # Ubuntu/Debian httpd -M | grep -E '(http2|ssl|deflate|headers|expires)' # RHEL-based

Test compression

curl -H "Accept-Encoding: gzip,deflate" -k https://example.com/ -v

Check SSL configuration

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -text | grep -A2 "Subject:"

Monitor Apache processes

ps aux | grep apache2 # or httpd

Performance monitoring and optimization

Monitor your Apache HTTP/2 performance and implement additional optimizations. You can integrate with existing monitoring solutions like Prometheus and Grafana for comprehensive metrics collection.

Enable Apache status module

Configure server status monitoring for performance analysis.

sudo a2enmod status

    
        SetHandler server-status
        Require ip 127.0.0.1
        Require ip 203.0.113.0/24
    
    
    
        SetHandler server-info
        Require ip 127.0.0.1
        Require ip 203.0.113.0/24
    
    
    ExtendedStatus On

    
        SetHandler server-status
        Require ip 127.0.0.1
        Require ip 203.0.113.0/24
    
    
    
        SetHandler server-info
        Require ip 127.0.0.1
        Require ip 203.0.113.0/24
    
    
    ExtendedStatus On
Note: For production deployments, consider implementing rate limiting with mod_security and mod_evasive to protect against abuse and DDoS attacks.

Common issues

SymptomCauseFix
HTTP/2 not workingSSL not properly configuredVerify SSL certificate and enable SSL engine
High memory usageMPM settings too aggressiveReduce MaxRequestWorkers and ThreadsPerChild values
Slow response timesCompression not workingCheck mod_deflate is enabled and configured properly
SSL certificate errorsSelf-signed certificate warningsUse proper CA-signed certificate or Let's Encrypt
Headers not appearingmod_headers not enabledEnable mod_headers with a2enmod headers
Configuration test failsSyntax errors in virtual hostCheck configuration with apache2ctl configtest
Permission denied errorsIncorrect file ownershipSet correct ownership with chown www-data:www-data
403 Forbidden errorsDirectory permissions too restrictiveSet directory permissions to 755, files to 644

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.