# UK Data Services - Advanced .htaccess Configuration
# Enhanced Security, Performance & SEO Optimizations
# ==================================================================
# SECURITY HEADERS & PROTECTION
# ==================================================================
# Security Headers
# Prevent MIME type sniffing
Header always set X-Content-Type-Options "nosniff"
# Prevent page from being displayed in frames (clickjacking protection)
Header always set X-Frame-Options "DENY"
# Enable XSS protection
Header always set X-XSS-Protection "1; mode=block"
# Force HTTPS (HSTS)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Referrer Policy
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Permissions Policy (formerly Feature Policy)
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), screen-wake-lock=()"
# Content Security Policy
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com https://analytics.google.com https://www.clarity.ms https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https: blob:; connect-src 'self' https://www.google-analytics.com https://analytics.google.com https://www.clarity.ms; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'"
# Remove Server Information
Header always unset Server
Header always unset X-Powered-By
# Cache Control for Static Assets
Header set Cache-Control "public, max-age=31536000, immutable"
Header set Expires "Thu, 31 Dec 2025 23:59:59 GMT"
# Cache Control for HTML files
Header set Cache-Control "private, max-age=0, no-cache, no-store, must-revalidate"
Header set Expires "0"
# ==================================================================
# RATE LIMITING & DDOS PROTECTION
# ==================================================================
DOSHashTableSize 3000
DOSPageCount 5
DOSPageInterval 1
DOSSiteCount 100
DOSSiteInterval 1
DOSBlockingPeriod 3600
DOSLogDir "/var/log/apache2/dos_logs"
DOSEmailNotify security@ukdataservices.co.uk
# Limit request size (10MB)
LimitRequestBody 10485760
# ==================================================================
# PERFORMANCE OPTIMIZATIONS
# ==================================================================
# Enable Compression
# Compress HTML, CSS, JavaScript, Text, XML and fonts
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
# Remove browser bugs (only needed for very old browsers)
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Header append Vary User-Agent
# Enable Brotli Compression (if available)
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript
AddOutputFilterByType BROTLI_COMPRESS application/javascript application/json application/xml
AddOutputFilterByType BROTLI_COMPRESS application/rss+xml application/atom+xml
AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
# Enable Expires Headers
ExpiresActive On
# Default expiration: 1 hour after request
ExpiresDefault "access plus 1 hour"
# CSS and JavaScript: 1 year
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
# Images: 1 year
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/svg+xml "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/avif "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
# Fonts: 1 year
ExpiresByType font/woff "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType font/ttf "access plus 1 year"
ExpiresByType font/otf "access plus 1 year"
ExpiresByType application/font-woff "access plus 1 year"
ExpiresByType application/font-woff2 "access plus 1 year"
# Documents: 1 week
ExpiresByType application/pdf "access plus 1 week"
# Data: 1 day
ExpiresByType application/json "access plus 1 day"
ExpiresByType application/xml "access plus 1 day"
ExpiresByType text/xml "access plus 1 day"
# HTML: 1 hour
ExpiresByType text/html "access plus 1 hour"
# ==================================================================
# SEO OPTIMIZATIONS
# ==================================================================
# Remove trailing slashes from URLs (except directories)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} /+[^\s]*?/{2,}[?\s] [OR]
RewriteCond %{THE_REQUEST} /+[^\s]*?/[?\s]
RewriteRule ^(.*)$ https://ukdataservices.co.uk/$1 [R=301,L]
# Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Force www (optional - uncomment if you want to enforce www)
# RewriteCond %{HTTP_HOST} ^ukdataservices\.co\.uk [NC]
# RewriteRule ^(.*)$ https://www.ukdataservices.co.uk/$1 [L,R=301]
# PHP Extensions Hidden
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
# Custom Error Pages
ErrorDocument 400 /400.php
ErrorDocument 401 /401.php
ErrorDocument 403 /403.php
ErrorDocument 404 /404.php
ErrorDocument 500 /500.php
ErrorDocument 503 /503.php
# ==================================================================
# SECURITY RESTRICTIONS
# ==================================================================
# Block access to sensitive files
Require all denied
# Block access to .htaccess
Require all denied
# Block access to sensitive directories
Require all denied
# Block WordPress attack patterns
RewriteCond %{QUERY_STRING} \.\./\.\. [OR]
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
RewriteCond %{QUERY_STRING} base64_(en|de)code\(.*\) [OR]
RewriteCond %{QUERY_STRING} ^.*(\[|\]|\(|\)|<|>|ê|"|;|\?|\*|=$).* [NC]
RewriteRule ^(.*)$ - [F,L]
# Block SQL injection attempts
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ index.php [F,L]
# Block common exploit attempts
RewriteCond %{REQUEST_URI} ^/(wp-admin|wp-includes|wp-content)/.*$ [OR]
RewriteCond %{REQUEST_URI} ^.*(\.php/|config\.php|phpinfo\.php|php\.ini).*$ [OR]
RewriteCond %{REQUEST_URI} ^.*/(xmlrpc\.php|wp-config\.php|install\.php).*$
RewriteRule ^(.*)$ - [F,L]
# ==================================================================
# LOGGING & MONITORING
# ==================================================================
# Custom log format for security monitoring
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %D" ukds_combined
# Block common bot patterns (optional)
RewriteCond %{HTTP_USER_AGENT} ^$ [OR]
RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget|libwww-perl|python|nikto|scan|winhttp|HTTrack|clshttp|loader|email|harvest|extract|grab|miner) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|scan|winhttp|clshttp|loader).*$ [NC]
RewriteRule .* - [F,L]
# ==================================================================
# ADDITIONAL MIME TYPES
# ==================================================================
# Web fonts
AddType application/font-woff .woff
AddType application/font-woff2 .woff2
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf
# Modern image formats
AddType image/webp .webp
AddType image/avif .avif
# Manifest files
AddType application/manifest+json .webmanifest
AddType application/json .json
# Video formats
AddType video/mp4 .mp4
AddType video/webm .webm
# ==================================================================
# HOTLINK PROTECTION (optional)
# ==================================================================
# RewriteCond %{HTTP_REFERER} !^$
# RewriteCond %{HTTP_REFERER} !^https?://(www\.)?ukdataservices\.co\.uk [NC]
# RewriteRule \.(jpg|jpeg|png|gif|svg|css|js)$ - [F,L]
# ==================================================================
# MAINTENANCE MODE (uncomment when needed)
# ==================================================================
# RewriteCond %{REQUEST_URI} !/maintenance.html$
# RewriteCond %{REMOTE_ADDR} !^123\.456\.789\.012$ # Your IP address
# RewriteRule $ /maintenance.html [R=302,L]