What Is .htaccess?
An .htaccess file (hypertext access) is an Apache web server configuration file placed in a directory. It applies configuration rules to that directory and all subdirectories without requiring a restart of the server. This makes it popular with shared hosting environments where you don't have access to the main server config.
Despite being convenient, .htaccess has a performance cost: Apache reads and processes every .htaccess file on every request, traversing the entire directory tree from root to the requested file. On high-traffic sites, moving rules into the main server config (httpd.conf or a VirtualHost block) is faster. But for most small to mid-size sites and shared hosting, .htaccess is practical.
Enabling mod_rewrite
Most .htaccess magic requires mod_rewrite. Start with:
Options -Indexes RewriteEngine On
Options -Indexes prevents Apache from showing a directory listing when no index file exists — a common security issue on misconfigured servers.
Forcing HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]This redirects all HTTP traffic to HTTPS. The R=301 makes it a permanent redirect (cached by browsers), L stops processing further rules.
www to non-www (or vice versa)
RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]Replace www\\.(.+)$ with ^(?!www\\.)(.+)$ and swap %1 to redirect the other way. Pick one canonical form and redirect consistently — mixed www/non-www creates duplicate content issues for SEO.
Custom Error Pages
ErrorDocument 404 /404.html ErrorDocument 500 /500.html
Serve a friendly error page instead of Apache's default. The path must be relative to the document root.
Browser Caching
<IfModule mod_expires.c> ExpiresActive On ExpiresByType image/jpeg "access plus 1 year" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" </IfModule>
Setting far-future expiry headers for static assets tells browsers to cache them locally, reducing repeat-visit load times significantly.
Security Headers
Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Requires mod_headers. These headers protect against clickjacking, MIME sniffing, and information leakage.
Blocking Common Attack Patterns
RewriteCond %{QUERY_STRING} (../|%2e%2e%2f) [NC,OR]
RewriteCond %{QUERY_STRING} (union|select|insert|drop|delete) [NC]
RewriteRule .* - [F,L]Blocks path traversal attempts and common SQL injection patterns in query strings. This is a defence-in-depth measure — it doesn't replace parameterised queries or server-side input validation.
Protecting Sensitive Files
<FilesMatch "(^.env|composer.(json|lock)|package.json)"> Order Allow,Deny Deny from all </FilesMatch>
Prevents direct access to configuration and dependency files that might expose credentials or internal structure.
Testing Your .htaccess
After editing, test by making a request from a browser or curl. Check the response status code and headers with curl -I. Apache logs are in /var/log/apache2/error.log — if a rewrite isn't working as expected, temporarily add RewriteLog to trace rule processing (Apache 2.2) or use LogLevel alert rewrite:trace3 (Apache 2.4).