.htaccess 是 Apache HTTP Server 提供的一种分布式配置文件,作用范围是它所在的目录以及该目录下的所有子目录。与主配置文件 httpd.conf 或 apache2.conf 不同,修改 .htaccess 后不需要重启 Apache,下一次请求到达时就会被读取并应用。这个特性让它特别适合虚拟主机用户、共享主机环境,或者需要频繁调整规则的开发场景。

不过,这种便利也有代价。Apache 在处理每个请求时,会从请求路径的根目录开始逐级向上查找 .htaccess 文件,找到后还需要解析其中的指令。如果站点目录层级较深,或者主配置里允许大量指令覆盖,性能损耗会被放大。因此,理解 .htaccess 的工作机制,比单纯复制规则更重要。
一、启用 .htaccess:AllowOverride 决定规则是否生效
许多配置不生效的原因,不在于语法错误,而是主配置中把 AllowOverride 设成了 None。AllowOverride 指令控制 .htaccess 文件中允许出现哪些类型的指令。它的常见取值有 All、None、AuthConfig、FileInfo、Indexes、Limit 等。例如,如果只允许 URL 重写,可以使用 AllowOverride FileInfo;如果需要密码认证,则需要 AuthConfig。
在 Debian/Ubuntu 系统的 Apache 配置中,默认站点配置通常位于 /etc/apache2/sites-available/000-default.conf,或者通过 /etc/apache2/apache2.conf 中的 <Directory> 块来设置。典型配置如下:
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
需要注意的是,AllowOverride All 虽然方便,但会让 Apache 在每个目录都尝试读取 .htaccess 文件。如果站点没有使用 .htaccess 的需求,更推荐在主配置里直接使用 <Directory> 块编写规则,然后设置 AllowOverride None。这样可以减少磁盘查找,也避免规则分散在多个文件中难以维护。修改主配置后,需要重新加载 Apache 服务,常用的命令是 systemctl reload apache2,而不是等待 .htaccess 自动生效。
二、URL 重写与重定向:RewriteRule 与 RewriteCond 的配合
URL 重写是 .htaccess 最常见的用途之一,依赖 Apache 的 mod_rewrite 模块。在 .htaccess 中使用重写规则,第一步通常是打开引擎:RewriteEngine On。之后通过 RewriteRule 定义匹配规则,RewriteCond 定义条件。例如,把 HTTP 请求强制跳转到 HTTPS,可以这样写:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [L,R=301]
上面规则的含义是:当 HTTPS 环境变量为 off 时,把任意路径重写为相同主机的 HTTPS 地址,并返回 301 永久重定向。[L] 表示如果匹配则停止继续处理后续规则,[R=301] 指定 HTTP 状态码。另一个常见需求是统一带 www 或不带 www 的域名:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule ^(.*)$ https://www.ipipp.com/$1 [L,R=301]
RewriteCond 中的 [NC] 表示不区分大小写。正则表达式里的反斜杠用于转义点号,这在公网教程中经常被写错,导致匹配范围变大。此外,很多 PHP 框架会借助伪静态规则把入口文件 index.php 隐藏掉,典型写法是:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
这段规则先判断请求路径不是真实存在的文件,也不是真实存在的目录,再把路径交给 index.php 处理。注意 .htaccess 中的 RewriteRule 匹配的是相对于当前 .htaccess 所在目录的路径,与主配置中的规则上下文不同。调试时如果规则不生效,除了检查 mod_rewrite 是否启用,还要确认 AllowOverride 是否包含 FileInfo。
三、访问控制与安全防护:认证、IP 限制与防盗链
.htaccess 还能实现基于用户名密码的访问控制。Apache 通常使用 htpasswd 工具生成口令文件,然后在 .htaccess 中指向该文件。一个最小化的 Basic Auth 配置如下:
AuthType Basic AuthName "Restricted Area" AuthUserFile /etc/apache2/.htpasswd Require valid-user
这里 AuthUserFile 最好放在站点目录之外,避免被下载。生成密码文件的命令是 htpasswd -c /etc/apache2/.htpasswd username,之后输入密码即可。对于 Apache 2.4,Require 指令取代了旧版的 Order、Allow 和 Deny,但很多旧教程仍在使用旧语法,容易造成混淆。如果要禁止某个 IP 访问,可以写成:
Require all granted Require not ip 192.168.1.100
另一个常用安全配置是防盗链。通过检查 Referer 请求头,可以阻止其他站点直接引用本站图片。常见规则如下:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ - [NC,F,L]
这段规则允许空 Referer,也允许来自 ipipp.com 的请求,其余来源访问图片时返回 403。与此同时,关闭目录列表也是基础安全操作,使用 Options -Indexes 可以防止没有索引文件时服务器自动列出文件清单。更严格的策略还可以通过 <FilesMatch> 限制敏感文件访问,例如拒绝 .htaccess 本身或 .git 目录被下载。这些规则生效的前提同样是 AllowOverride 中开放了 Limit 或 AuthConfig 权限。
四、错误页、缓存与性能调优:减少 .htaccess 带来的开销
通过 ErrorDocument 指令可以给访问者展示自定义错误页面,而不只是浏览器的默认白屏或服务器错误页。例如:
ErrorDocument 404 /404.html ErrorDocument 500 /500.html
缓存控制也是 .htaccess 的强项。启用 mod_expires 后,可以为图片、CSS、JavaScript 等静态资源设置过期时间,减少重复请求。配合 mod_headers 可以进一步设置 Cache-Control 响应头:
ExpiresActive On
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType text/css "access plus 7 days"
<IfModule mod_headers.c>
Header set Cache-Control "max-age=2592000, public"
</IfModule>
这段配置让 JPEG 图片缓存一个月,CSS 缓存七天,同时通过 Header 指令设置 max-age。MIME 类型必须准确,否则规则不会匹配;可以使用 curl -I 查看响应头确认。类似地,mod_deflate 可以压缩文本类资源,但压缩会消耗 CPU,需要根据服务器负载做取舍。
从性能角度看,如果站点每个目录都有大量 .htaccess 文件,Apache 每处理一个请求都可能产生多次文件系统查找和正则解析。对于静态资源请求密集的场景,建议将这些规则迁移到主配置的 <Directory> 或 <VirtualHost> 块中,然后把 AllowOverride 设为 None。这样规则在 Apache 启动时加载一次,而不是每个请求重复读取。迁移后的规则语法基本相同,只是 RewriteRule 的匹配路径会包含上下文中的目录前缀,需要重新验证。
排查错误时,可以先运行 apachectl configtest 检查主配置语法,但 .htaccess 内的语法错误通常只有在实际请求时才会触发 500 错误。可以查看 Apache 错误日志,路径常见为 /var/log/apache2/error.log。对于复杂的重写问题,可以在主配置中临时设置 LogLevel alert rewrite:trace6,结合日志定位规则在哪一步匹配失败。