Master the art of optimizing Apache web server performance by implementing precompressed static files with gzip compression.

Apache Precompressed Static Files

Why Precompress Static Files?

Precompressing static files offers several advantages:

  • Reduced server CPU usage
  • Faster response times
  • Lower bandwidth consumption
  • Improved scalability
  • Better user experience

Implementation Guide

1. Apache Configuration

# Enable mod_rewrite
RewriteEngine on

# Check for gzip support
RewriteCond %{HTTP:Accept-encoding} gzip

# Check for precompressed file
RewriteCond %{REQUEST_FILENAME}.gz -s
RewriteRule ^(.+)\.(js|css|html|xml|txt)$ $1.$2.gz [QSA,L]

# Set proper content encoding
<FilesMatch "\.js\.gz$">
    ForceType application/javascript
    Header set Content-Encoding gzip
</FilesMatch>

<FilesMatch "\.css\.gz$">
    ForceType text/css
    Header set Content-Encoding gzip
</FilesMatch>

<FilesMatch "\.(html|xml|txt)\.gz$">
    ForceType text/html
    Header set Content-Encoding gzip
</FilesMatch>

2. Compression Script

#!/bin/bash
# compress-static.sh

compress_files() {
    local dir=$1
    local file_types=("js" "css" "html" "xml" "txt")
    
    for type in "${file_types[@]}"; do
        find "$dir" -type f -name "*.$type" | while read -r file; do
            if [ ! -f "${file}.gz" ] || [ "$file" -nt "${file}.gz" ]; then
                gzip -9 -c "$file" > "${file}.gz"
                echo "Compressed: $file"
            fi
        done
    done
}

# Usage
compress_files "/var/www/html/static"

Automation and Monitoring

1. Automated Compression

#!/usr/bin/env python3
# auto_compress.py

import os
import gzip
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class CompressHandler(FileSystemEventHandler):
    def __init__(self, extensions):
        self.extensions = extensions
        
    def on_modified(self, event):
        if not event.is_directory:
            file_path = event.src_path
            ext = os.path.splitext(file_path)[1][1:]
            
            if ext in self.extensions and not file_path.endswith('.gz'):
                self.compress_file(file_path)
    
    def compress_file(self, file_path):
        gz_path = f"{file_path}.gz"
        with open(file_path, 'rb') as f_in:
            with gzip.open(gz_path, 'wb', compresslevel=9) as f_out:
                f_out.writelines(f_in)
        print(f"Compressed: {file_path}")

def main():
    path = "/var/www/html/static"
    extensions = {'js', 'css', 'html', 'xml', 'txt'}
    
    event_handler = CompressHandler(extensions)
    observer = Observer()
    observer.schedule(event_handler, path, recursive=True)
    observer.start()
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

if __name__ == "__main__":
    main()

2. Performance Monitoring

#!/usr/bin/env python3
# monitor_compression.py

import os
import requests
import time
from datetime import datetime

def check_compression(url):
    # Check with and without gzip support
    headers_nogzip = {'Accept-Encoding': ''}
    headers_gzip = {'Accept-Encoding': 'gzip'}
    
    # Make requests
    resp_nogzip = requests.get(url, headers=headers_nogzip)
    resp_gzip = requests.get(url, headers=headers_gzip)
    
    # Calculate savings
    original_size = len(resp_nogzip.content)
    compressed_size = len(resp_gzip.content)
    savings = ((original_size - compressed_size) / original_size) * 100
    
    return {
        'url': url,
        'original_size': original_size,
        'compressed_size': compressed_size,
        'savings_percent': savings,
        'time': datetime.now()
    }

def log_results(results):
    with open('compression_stats.log', 'a') as f:
        f.write(f"{results['time']}: {results['url']} - "
                f"Savings: {results['savings_percent']:.2f}%\n")

Performance Optimization

1. Compression Levels

# Test different compression levels
for level in {1..9}; do
    echo "Testing compression level $level"
    time gzip -$level -c large.js > large.js.gz
    ls -lh large.js.gz
done

2. Cache Configuration

# Set cache headers for compressed files
<FilesMatch "\.(js|css|html|xml|txt)\.gz$">
    Header set Cache-Control "max-age=31536000, public"
    Header unset ETag
    FileETag None
</FilesMatch>

Implementation Scripts

1. Initial Setup

#!/bin/bash
# setup-compression.sh

# Enable required modules
a2enmod rewrite
a2enmod headers

# Create compression directory structure
mkdir -p /var/www/html/static/{js,css,html}

# Set permissions
chown -R www-data:www-data /var/www/html/static
chmod -R 755 /var/www/html/static

# Initial compression
find /var/www/html/static -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) \
    -exec gzip -9 -c {} > {}.gz \;

2. Maintenance Script

#!/bin/bash
# maintain-compression.sh

# Remove outdated compressed files
find /var/www/html/static -type f -name "*.gz" | while read -r gz_file; do
    original="${gz_file%.gz}"
    if [ ! -f "$original" ]; then
        rm "$gz_file"
        echo "Removed orphaned: $gz_file"
    fi
done

# Update stale compressed files
find /var/www/html/static -type f ! -name "*.gz" | while read -r file; do
    if [ ! -f "${file}.gz" ] || [ "$file" -nt "${file}.gz" ]; then
        gzip -9 -c "$file" > "${file}.gz"
        echo "Updated: ${file}.gz"
    fi
done

Best Practices

  1. File Selection

    • Compress text-based files
    • Skip already compressed formats
    • Consider file size thresholds
  2. Performance Monitoring

    • Track compression ratios
    • Monitor server load
    • Measure response times
  3. Maintenance

    • Regular compression updates
    • Clean up orphaned files
    • Monitor disk usage

Remember to test thoroughly in a staging environment before implementing in production, and monitor server performance to ensure the compression configuration is providing optimal benefits.