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
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
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
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
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
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
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
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.
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 {} \;
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
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| HTTP/2 not working | SSL not properly configured | Verify SSL certificate and enable SSL engine |
| High memory usage | MPM settings too aggressive | Reduce MaxRequestWorkers and ThreadsPerChild values |
| Slow response times | Compression not working | Check mod_deflate is enabled and configured properly |
| SSL certificate errors | Self-signed certificate warnings | Use proper CA-signed certificate or Let's Encrypt |
| Headers not appearing | mod_headers not enabled | Enable mod_headers with a2enmod headers |
| Configuration test fails | Syntax errors in virtual host | Check configuration with apache2ctl configtest |
| Permission denied errors | Incorrect file ownership | Set correct ownership with chown www-data:www-data |
| 403 Forbidden errors | Directory permissions too restrictive | Set directory permissions to 755, files to 644 |
Next steps
- Configure Apache rate limiting and DDoS protection with mod_security and mod_evasive
- Set up Prometheus and Grafana monitoring stack with Docker compose
- Configure Apache web server with virtual hosts and SSL certificates
- Implement Apache load balancing with SSL termination and health checks
- Configure Apache reverse proxy with caching for microservices
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Default values
DOMAIN="${1:-example.com}"
EMAIL="${2:-admin@${DOMAIN}}"
# Usage message
usage() {
echo "Usage: $0 [domain] [email]"
echo "Example: $0 mydomain.com admin@mydomain.com"
exit 1
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Check if running as root
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
# Auto-detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
APACHE_SERVICE="apache2"
APACHE_CONF_DIR="/etc/apache2"
APACHE_SITES_DIR="/etc/apache2/sites-available"
APACHE_MODS_DIR="/etc/apache2/mods-available"
APACHE_DOC_ROOT="/var/www/html"
FIREWALL_CMD="ufw"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
APACHE_SERVICE="httpd"
APACHE_CONF_DIR="/etc/httpd"
APACHE_SITES_DIR="/etc/httpd/conf.d"
APACHE_MODS_DIR="/etc/httpd/conf.modules.d"
APACHE_DOC_ROOT="/var/www/html"
FIREWALL_CMD="firewall-cmd"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
APACHE_SERVICE="httpd"
APACHE_CONF_DIR="/etc/httpd"
APACHE_SITES_DIR="/etc/httpd/conf.d"
APACHE_MODS_DIR="/etc/httpd/conf.modules.d"
APACHE_DOC_ROOT="/var/www/html"
FIREWALL_CMD="firewall-cmd"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution"
exit 1
fi
# Cleanup function
cleanup() {
log_error "Installation failed. Cleaning up..."
systemctl stop $APACHE_SERVICE 2>/dev/null || true
systemctl disable $APACHE_SERVICE 2>/dev/null || true
}
trap cleanup ERR
log_info "[1/8] Updating system packages..."
$PKG_UPDATE
log_info "[2/8] Installing Apache and SSL packages..."
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
$PKG_INSTALL apache2 apache2-utils ssl-cert openssl
else
$PKG_INSTALL httpd mod_ssl openssl mod_http2
fi
log_info "[3/8] Enabling Apache modules..."
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
a2enmod ssl http2 rewrite deflate expires headers cache cache_disk
else
# Enable modules for RHEL-based systems
sed -i 's/#LoadModule rewrite_module/LoadModule rewrite_module/' ${APACHE_MODS_DIR}/00-base.conf 2>/dev/null || true
echo "LoadModule http2_module modules/mod_http2.so" > ${APACHE_MODS_DIR}/10-http2.conf
fi
log_info "[4/8] Generating SSL certificate..."
mkdir -p /etc/ssl/private
chmod 700 /etc/ssl/private
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=${DOMAIN}"
chmod 600 /etc/ssl/private/apache-selfsigned.key
chmod 644 /etc/ssl/certs/apache-selfsigned.crt
log_info "[5/8] Configuring Apache main settings..."
cat > ${APACHE_CONF_DIR}/conf-available/http2-performance.conf << 'EOF' || cat > ${APACHE_CONF_DIR}/conf.d/http2-performance.conf << 'EOF'
# 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
<IfModule mod_deflate.c>
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
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
</IfModule>
# Cache Settings
<IfModule mod_expires.c>
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"
</IfModule>
EOF
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
a2enconf http2-performance
fi
log_info "[6/8] Creating SSL virtual host..."
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
VHOST_FILE="${APACHE_SITES_DIR}/${DOMAIN}-ssl.conf"
else
VHOST_FILE="${APACHE_SITES_DIR}/${DOMAIN}-ssl.conf"
fi
cat > "$VHOST_FILE" << EOF
<VirtualHost *:443>
ServerName ${DOMAIN}
ServerAlias www.${DOMAIN}
DocumentRoot ${APACHE_DOC_ROOT}
# 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
# 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 Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
ErrorLog \${APACHE_LOG_DIR}/${DOMAIN}_ssl_error.log
CustomLog \${APACHE_LOG_DIR}/${DOMAIN}_ssl_access.log combined
</VirtualHost>
<VirtualHost *:80>
ServerName ${DOMAIN}
ServerAlias www.${DOMAIN}
Redirect permanent / https://${DOMAIN}/
</VirtualHost>
EOF
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
a2ensite ${DOMAIN}-ssl
fi
log_info "[7/8] Configuring firewall..."
if command -v ufw &> /dev/null; then
ufw --force enable
ufw allow 'Apache Full'
elif command -v firewall-cmd &> /dev/null; then
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
fi
log_info "[8/8] Starting and enabling Apache..."
systemctl enable $APACHE_SERVICE
systemctl restart $APACHE_SERVICE
# Verification checks
log_info "Verifying installation..."
if systemctl is-active --quiet $APACHE_SERVICE; then
log_info "✓ Apache is running"
else
log_error "✗ Apache is not running"
exit 1
fi
if ss -tlnp | grep -q ':443'; then
log_info "✓ SSL port 443 is listening"
else
log_warn "✗ SSL port 443 is not listening"
fi
if $APACHE_SERVICE -M 2>/dev/null | grep -q http2 || httpd -M 2>/dev/null | grep -q http2; then
log_info "✓ HTTP/2 module is loaded"
else
log_warn "✗ HTTP/2 module may not be loaded"
fi
log_info ""
log_info "Apache HTTP/2 configuration completed successfully!"
log_info "Domain: ${DOMAIN}"
log_info "SSL Certificate: Self-signed (replace with proper certificate for production)"
log_info "Configuration files:"
log_info " - Main config: ${APACHE_CONF_DIR}/"
log_info " - Virtual host: ${VHOST_FILE}"
log_info ""
log_warn "Next steps:"
log_warn "1. Replace self-signed certificate with a proper SSL certificate"
log_warn "2. Update DocumentRoot and add your website content"
log_warn "3. Test HTTP/2 functionality with: curl -I --http2 https://${DOMAIN}/"
Review the script before running. Execute with: bash install.sh