.htaccess (分散式配置檔) 允許在特定目錄覆蓋 Apache 主配置,作用於該目錄及所有子目錄。適用於無 root 權限的虛擬主機環境、需要動態調整規則的場景。
/.htaccess → /var/www/.htaccess → /var/www/site/.htaccess → /var/www/site/app/.htaccessstat(),即使檔案不存在AllowOverride All 啟用時效能影響最大<Directory> 可直接設定的規則,不要 放在 .htaccess| 類別 | 常用指令 | AllowOverride 需求 |
|---|---|---|
| URL 重寫 | RewriteEngine, RewriteRule, RewriteCond, RewriteBase | FileInfo |
| 存取控制 | Require, Allow, Deny, Order (2.4 棄用) | AuthConfig / Limit |
| 認證授權 | AuthType, AuthName, AuthUserFile, AuthGroupFile | AuthConfig |
| MIME 類型 | AddType, AddHandler, ForceType | FileInfo |
| 目錄索引 | DirectoryIndex, Options +Indexes | Indexes |
| CGI/腳本 | Options +ExecCGI, AddHandler cgi-script, SetHandler | Options / FileInfo |
| PHP 設定 | php_value, php_flag, php_admin_value | Options (需 mod_php) |
| 快取控制 | ExpiresActive, ExpiresByType, Header set Cache-Control | FileInfo |
| 壓縮傳輸 | SetOutputFilter DEFLATE, AddOutputFilterByType | FileInfo |
| 安全標頭 | Header set X-Frame-Options, Header set CSP | FileInfo |
# .htaccess (專案根目錄)
RewriteEngine On
# 靜態檔案直接服務
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 其餘導向 index.php
RewriteRule ^ index.php [L,QSA]
# 保護敏感檔案
RewriteRule ^\.env$ - [F,L]
RewriteRule ^composer\.(json|lock)$ - [F,L]
RewriteRule ^storage/ - [F,L]
RewriteRule ^vendor/ - [F,L]
RewriteEngine On
# 強制 HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# 統一 WWW (二選一)
# 方案 A: 強制 www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# 方案 B: 移除 www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1%{REQUEST_URI} [L,R=301]
# 啟用壓縮 (需 mod_deflate)AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json application/xml # 瀏覽器快取 (需 mod_expires)BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html ExpiresActive On ExpiresByType image/jpg "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ExpiresDefault "access plus 2 days"
# 防點擊劫持 Header always set X-Frame-Options "SAMEORIGIN" # XSS 保護 Header always set X-XSS-Protection "1; mode=block" # 禁止 MIME 嗅探 Header always set X-Content-Type-Options "nosniff" # 內容安全政策 (CSP) - 根據專案調整 Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' fonts.gstatic.com;" # Referrer 政策 Header always set Referrer-Policy "strict-origin-when-cross-origin" # HSTS (僅 HTTPS 環境) Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# 上傳限制 php_value upload_max_filesize 50M php_value post_max_size 60M php_value max_execution_time 300 php_value max_input_time 300 # 錯誤顯示 (開發環境) php_flag display_errors On php_value error_reporting 32767 # Session 設定 php_value session.gc_maxlifetime 7200 php_value session.cookie_httponly 1 php_value session.cookie_secure 1 php_value session.use_strict_mode 1
# /var/www/.htaccess Options +ExecCGI # /var/www/subdir/.htaccess Options +Includes # 結果: subdir 只有 Includes,ExecCGI 被覆蓋 (非累加) # 正確累加寫法: Options +ExecCGI +Includes # 或 Options +ExecCGI Options +Includes
AllowOverride 是否包含所需類別 (預設 None)error.logRewriteRule 導向自身 → 加入 RewriteCond %{REQUEST_FILENAME} !-f 排除實體檔案<Directory>mod_php 支援 php_value,PHP-FPM 需用 .user.ini 或池配置# httpd.conf / apache2.conf# 將 .htaccess 規則移至此處 AllowOverride None # 完全禁用 .htaccess,提升效能 RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [L] # 安全標頭、壓縮、快取等同樣設定 Header always set X-Frame-Options "SAMEORIGIN" # ...