The .htaccess file (Hypertext Access) is a small per-directory configuration file that Apache Web Server reads on every request. It lets website owners adjust server behavior without touching the main httpd.conf — making it the primary customization tool available on shared hosting and DirectAdmin environments.

From URL redirects and forced HTTPS to GZIP compression, browser caching, security headers, and PHP setting overrides, .htaccess handles a wide range of tasks that would otherwise require server-level access. This guide collects the most commonly used .htaccess commands for WordPress sites and PHP web applications, with working examples tested on Apache 2.4.

Understanding How .htaccess Works

Before adding any directives, understanding three core principles will save you from debugging hours later:

Lines beginning with # are comments and have no effect. Using comments generously makes future maintenance much easier, especially when you have multiple rule blocks covering different purposes.

WordPress Permalink Block — The Foundation

WordPress relies on mod_rewrite to route all requests that do not correspond to a real file or directory to index.php, which then handles the WordPress routing logic. WordPress Dashboard generates this block automatically when you save your Permalink settings under Settings > Permalinks. Here is what each line does:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

RewriteBase / sets the base path for relative rules. If WordPress is installed in a subdirectory such as /blog/, change this to RewriteBase /blog/ and update the final rule to RewriteRule . /blog/index.php [L]. The two RewriteCond lines ensure that requests for real files (images, CSS, JS) and real directories bypass WordPress routing and are served directly by Apache. Never remove these conditions — doing so will break static asset delivery.

Redirects — 301 and HTTPS Enforcement

Redirects are among the most common .htaccess tasks. The two most critical for any production site are forcing HTTPS and choosing a canonical domain (www vs non-www). Both should be set up from day one.

Force HTTPS

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Redirect www to non-www (canonical non-www)

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.yourdomain\.com [NC]
RewriteRule ^(.*)$ https://yourdomain.com/$1 [R=301,L]

Combined: force HTTPS + non-www in one pass

Combining both rules prevents a double redirect (two 301s in sequence) which wastes latency and dilutes link equity:

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^(.*)$ https://yourdomain.com/$1 [R=301,L]

The [OR] flag means the rule fires when either condition is true. All four entry points (http/https × www/non-www) are redirected to the canonical URL in a single hop.

GZIP Compression — Smaller Transfers, Faster Pages

GZIP compresses text-based assets before sending them to the browser, typically reducing HTML, CSS, and JavaScript by 60–80%. This is one of the highest-impact performance optimizations available and has zero negative side effects on modern browsers.

<IfModule mod_deflate.c>
  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/json

  # Skip already-compressed formats
  SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|svg|ico|zip|gz|bz2|mp4|mp3)$ no-gzip dont-vary
</IfModule>

Verify that GZIP is active with: curl -H "Accept-Encoding: gzip" -I https://yourdomain.com/. A Content-Encoding: gzip header in the response confirms it is working.

Browser Caching — Reduce Repeat Downloads

Browser caching tells the browser how long to keep static assets locally. A visitor who returns within the cache window skips downloading images, CSS, and fonts entirely, resulting in near-instant page loads and lower bandwidth consumption on your server.

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 month"

  # Images — cache for 1 year
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "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 image/x-icon "access plus 1 year"

  # CSS and JavaScript — cache for 1 month
  ExpiresByType text/css "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"
  ExpiresByType application/x-javascript "access plus 1 month"

  # Web fonts — cache for 1 year
  ExpiresByType font/woff2 "access plus 1 year"
  ExpiresByType font/woff "access plus 1 year"
  ExpiresByType application/font-woff2 "access plus 1 year"

  # HTML — short cache
  ExpiresByType text/html "access plus 1 hour"
  ExpiresByType application/rss+xml "access plus 1 hour"
</IfModule>

<IfModule mod_headers.c>
  Header append Cache-Control "public"
</IfModule>

Cache Busting Tip: Long cache lifetimes are powerful but create a problem when you update a CSS or JS file — users see the old version until their cache expires. Solve this with cache busting: append a version query string to asset URLs, such as style.css?v=20260609. The browser treats the new URL as a different file and downloads the latest version immediately, bypassing the old cache entry entirely.

Security Headers

Security headers are HTTP response headers that instruct the browser on how to handle content, preventing entire classes of vulnerabilities such as clickjacking, MIME sniffing, and cross-site scripting. They are free to add, have no performance cost, and dramatically improve your security posture.

<IfModule mod_headers.c>
  # Prevent framing from other origins (clickjacking protection)
  Header always set X-Frame-Options "SAMEORIGIN"

  # Prevent MIME type sniffing
  Header always set X-Content-Type-Options "nosniff"

  # Legacy XSS protection for older browsers
  Header always set X-XSS-Protection "1; mode=block"

  # Control referrer information sent to third parties
  Header always set Referrer-Policy "strict-origin-when-cross-origin"

  # HTTP Strict Transport Security — set only after HTTPS is confirmed working
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

Blocking xmlrpc.php (WordPress)

WordPress's xmlrpc.php is a legacy remote publishing interface that attackers routinely use for brute-force password attacks and amplification DDoS. If you do not use Jetpack or any XML-RPC client, block it entirely:

<Files xmlrpc.php>
  Order Deny,Allow
  Deny from all
</Files>

Block PHP Execution in /uploads/ (WordPress)

Even if a file upload vulnerability allows an attacker to place a PHP file inside the uploads directory, this rule prevents Apache from executing it. Create a separate .htaccess file inside wp-content/uploads/:

<FilesMatch "\.php$">
  Order Allow,Deny
  Deny from all
</FilesMatch>

PHP Setting Overrides

On shared hosting where you cannot edit the global php.ini directly, you can override many PHP settings per-directory through .htaccess using php_value and php_flag directives. AsiaGB DirectAdmin Hosting supports this.

# Increase memory limit for WordPress or heavy PHP apps
php_value memory_limit 256M

# Increase file upload limits
php_value upload_max_filesize 64M
php_value post_max_size 64M

# Increase maximum script execution time (seconds)
php_value max_execution_time 300

# Hide PHP errors from public view (use on production)
php_flag display_errors Off

# Log errors to error_log instead of displaying them
php_flag log_errors On

# Set timezone for date/time functions
php_value date.timezone "Asia/Bangkok"

# Session security hardening
php_value session.cookie_httponly 1
php_value session.cookie_secure 1

If adding php_value directives causes a 500 error, the hosting environment does not allow PHP overrides through .htaccess. In that case, try placing a php.ini or user.ini file in the same directory — many shared hosting setups support one of these alternatives.

Hotlink Protection and Access Control

Hotlinking occurs when another website embeds your images using your server's URL, consuming your bandwidth without serving your visitors. You can block this using the HTTP Referer header:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?yourdomain\.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp|svg)$ - [F,NC]
</IfModule>

The first condition allows empty referers (direct access, curl, RSS readers). The second allows requests from your own domain. The [F] flag returns a 403 Forbidden response instead of serving the image. Replace yourdomain.com with your actual domain.

Quick-Reference Table

Use this table as a fast lookup when you need a specific directive category:

Category Key Directive Apache Module Purpose
Redirect Redirect 301 mod_alias Permanent URL moves, preserves SEO
Rewrite RewriteRule / RewriteCond mod_rewrite URL pattern transformation, WordPress routing
GZIP AddOutputFilterByType DEFLATE mod_deflate Compress responses, reduce bandwidth
Cache ExpiresByType mod_expires Set browser cache lifetime per file type
Headers Header always set mod_headers Security headers, HSTS, CORS
PHP php_value / php_flag mod_php Override php.ini settings per directory
Access Order Deny,Allow / <Files> mod_access Block files, IPs, or user agents
Error ErrorDocument core Serve custom error pages for 4xx/5xx

Best Practices and Common Pitfalls

These guidelines will prevent the most common mistakes when working with .htaccess:

Frequently Asked Questions

Does .htaccess work on all types of web hosting?

.htaccess only works on Apache-based web servers, which covers most shared hosting and VPS environments including AsiaGB DirectAdmin Hosting. If your server runs Nginx, you must configure directives in nginx.conf instead. LiteSpeed servers support nearly all Apache .htaccess directives as well.

My site shows 500 Internal Server Error after editing .htaccess — what do I do?

A 500 error from .htaccess is almost always caused by a syntax mistake: a misspelled directive, missing square brackets around a flag like [L], or mod_rewrite not being loaded. Check your error log in DirectAdmin (Logs > Error Log) to see the exact message. You can also run curl -I https://yourdomain.com to inspect the HTTP response. Always keep a backup of the original .htaccess before making changes.

What special .htaccess configuration does WordPress require?

WordPress requires a mod_rewrite block to route all requests through index.php, which WordPress Dashboard generates automatically when you save your Permalink settings. Beyond that, it is common practice to add GZIP compression to reduce file size, browser caching to improve repeat-visit speed, block access to xmlrpc.php to prevent brute-force attacks, and block PHP execution inside the /uploads/ directory to prevent malware execution.

How do multiple .htaccess files in subdirectories interact?

Apache merges .htaccess files from the document root down to the requested directory. Each file along the path is processed in order, with deeper files overriding parent files for the same directives. For WordPress, keep the root .htaccess focused on WordPress Permalink routing, and place a separate .htaccess in wp-content/uploads/ solely to block PHP execution. This separation makes maintenance easier and reduces the risk of rule conflicts.

Full-Featured DirectAdmin Hosting by AsiaGB

AsiaGB Hosting supports DirectAdmin, PHP 8.3, MySQL, and full .htaccess access. Plans start from 500 THB/year with 99% uptime.

View Hosting Plans

View all cheap Thailand web hosting plans →