# Enable rewrite engine Options -MultiViews RewriteEngine On # Set the base directory for rewrite rules RewriteBase / # Force HTTPS and www RewriteCond %{HTTPS} off [OR] RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC] RewriteRule ^ https://www.%1%{REQUEST_URI} [L,NE,R=301] # Enable GZIP compression for faster page load AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript AddOutputFilterByType DEFLATE application/x-font-ttf AddOutputFilterByType DEFLATE image/svg+xml AddOutputFilterByType DEFLATE image/x-icon # Expose which rewrite handled a request for debugging (safe to keep; no PII) Header set X-Route "%{ROUTE}e" env=ROUTE # Enable browser caching ExpiresActive On ExpiresByType image/jpg "access plus 1 year" ExpiresByType image/jpeg "access plus 1 year" ExpiresByType image/gif "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType image/webp "access plus 1 year" ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType text/css "access plus 1 month" ExpiresByType application/pdf "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ExpiresByType application/x-javascript "access plus 1 month" ExpiresByType application/x-shockwave-flash "access plus 1 month" ExpiresByType image/x-icon "access plus 1 year" ExpiresDefault "access plus 2 days" # Security Headers # Protect against XSS attacks Header set X-XSS-Protection "1; mode=block" Header always append X-Frame-Options SAMEORIGIN Header set X-Content-Type-Options nosniff # Enable HSTS (uncomment when SSL is configured) # Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" # Set Referrer-Policy Header set Referrer-Policy "strict-origin-when-cross-origin" # Set Content Security Policy (CSP) - Update with your specific needs # Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com;" # Disable directory browsing Options -Indexes # Block access to sensitive files Order allow,deny Deny from all # Prevent access to .htaccess and .htpasswd Order allow,deny Deny from all Satisfy All # Redirect old URLs to new SEO-friendly URLs (301 redirects for SEO) - Do this FIRST # Only redirect if it's a direct access to city-service.php (not from rewrite) RewriteCond %{THE_REQUEST} \s/+city-service\.php\?city=([a-z-]+)&service=([a-z-]+) [NC] RewriteRule ^city-service\.php$ %1/%2/? [R=301,L] # Redirect city-services.php?city={city}[&...] to /city-services/{city}/ # Match even when additional query params exist (e.g., &v=...) RewriteCond %{THE_REQUEST} \s+/city-services\.php\?[^\s]*city=([a-z-]+)[^\s]* [NC] RewriteRule ^city-services\.php$ city-services/%1/? [R=301,L] # Canonical: Redirect bare city-services.php (no city/service params) to /city-services RewriteCond %{THE_REQUEST} \s+/city-services\.php(?:\s|\?) [NC] RewriteCond %{QUERY_STRING} !(^|&)city= [NC] RewriteCond %{QUERY_STRING} !(^|&)service= [NC] RewriteRule ^city-services\.php$ city-services [R=301,L] # Handle city-services.php with both city and service - DISABLED to allow direct access # This MUST come first to match before the single parameter rules # RewriteCond %{THE_REQUEST} \s+/city-services\.php\?.*city=([a-z-]+).*&.*service=([a-z-]+) # RewriteRule ^city-services\.php$ %1/%2/? [R=301,L] # RewriteCond %{THE_REQUEST} \s+/city-services\.php\?.*service=([a-z-]+).*&.*city=([a-z-]+) # RewriteRule ^city-services\.php$ %2/%1/? [R=301,L] # Handle city-services.php with only city parameter - DISABLED to allow direct access # RewriteCond %{THE_REQUEST} \s+/city-services\.php\?.*city=([a-z-]+) # RewriteCond %{QUERY_STRING} !service= # RewriteRule ^city-services\.php$ services-in-%1/? [R=301,L] # Handle city-services.php with only service parameter - DISABLED to allow direct access # RewriteCond %{THE_REQUEST} \s+/city-services\.php\?.*service=([a-z-]+) # RewriteCond %{QUERY_STRING} !city= # RewriteRule ^city-services\.php$ %1-services/? [R=301,L] # SEO-Friendly URLs for City-Service Pages # First, handle the explicit city-services routes so they don't get caught by the generic two-segment rule # City services overview: /services-in-city/ -> city-services.php?city=city RewriteRule ^services-in-([a-z-]+)/?$ city-services.php?city=$1 [L,QSA,E=ROUTE:services-in-city] # City services overview (preferred): /city-services/{city}/[services.php optional] -> city-services.php?city=city # Force rewrite even if a real directory named "city-services" exists RewriteRule ^city-services/([a-z-]+)/(?:services\.php)?$ city-services.php?city=$1 [L,QSA,E=ROUTE:city-services] # City-services index: /city-services/ -> city-services.php (no params) RewriteRule ^city-services/?$ city-services.php [L,QSA,E=ROUTE:city-services-index] # Handle /city-services/ with trailing slash RewriteRule ^city-services/$ city-services.php [L,QSA,E=ROUTE:city-services-index] # Handle city/service pattern: /city/service/ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([a-z-]+)/([a-z-]+)/?$ city-service.php?city=$1&service=$2 [L,QSA,E=ROUTE:city-service] # Alternative pattern: /service-in-city/ -> city-service.php?city=city&service=service RewriteRule ^([a-z-]+)-in-([a-z-]+)/?$ city-service.php?city=$2&service=$1 [L,QSA,E=ROUTE:service-in-city] # Defensive case handled above via optional services.php segment (internal rewrite) # Service overview: /service-services/ -> city-services.php?service=service RewriteRule ^([a-z-]+)-services/?$ city-services.php?service=$1 [L,QSA,E=ROUTE:service-services] # City overview: /city/ -> city-services.php?city=city (but exclude existing files/directories) RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # Exclude requests for static assets and key directories from this catch-all RewriteCond %{REQUEST_URI} !\.(php|css|js|jpg|jpeg|png|gif|svg)$ [NC] RewriteCond %{REQUEST_URI} !^/(admin|assets|includes|services)(/|$) [NC] RewriteRule ^([a-z-]+)/?$ city-services.php?city=$1 [L,QSA,E=ROUTE:city-overview] # Remove trailing slash (do this LAST to avoid conflicts) RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} (.+)/$ RewriteRule ^ %1 [R=301,L] # Security: Block access to sensitive files Order allow,deny Deny from all Order allow,deny Deny from all # Block access to admin directory from unauthorized users (optional) # # AuthType Basic # AuthName "Admin Area" # AuthUserFile /path/to/.htpasswd # Require valid-user # # Compression for better performance AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript # Browser caching for better performance ExpiresActive on ExpiresByType text/css "access plus 1 year" ExpiresByType application/javascript "access plus 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" # Custom error pages (optional) # ErrorDocument 404 /404.php # ErrorDocument 500 /500.php