Apache服务器HTTPS/WWW重定向自动添加.php后缀问题求助
解决Apache2+Cloudflare环境下重定向自动添加.php后缀问题
问题背景
服务器环境为Apache2 + PHP,部署在Cloudflare代理之后。根目录下的.htaccess用于强制所有请求跳转到https://www.前缀的URL,正常跳转逻辑如下:
http://example.com→https://www.example.comhttps://example.com→https://www.example.comhttp://www.example.com→https://www.example.com
但出现异常:请求不带www的URL时,重定向后会自动添加.php后缀:
http://example.com/page→https://www.example.com/page.phphttps://example.com/page→https://www.example.com/page.php
而带www的请求无此问题:
http://www.example.com/page→https://www.example.com/page
现有配置
根目录.htaccess文件
<IfModule mod_rewrite.c> RewriteCond %{HTTPS} off [OR] RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteCond %{HTTP_HOST} ^(.*)$ [NC] RewriteRule (.*) https://www.%1/$1 [R=301,L] </IfModule>
Apache虚拟主机配置文件(.conf)
<IfModule mod_ssl.c> <VirtualHost *:443> ServerName {domain.com} ServerAlias www.{domain.com} ServerAdmin webmaster@{domain.com} DocumentRoot /var/www/{domain.com}/public_html <Directory /var/www/{domain.com}/public_html> Options -Indexes +FollowSymLinks AllowOverride All </Directory> # Cloudflare真实IP配置 RemoteIPHeader CF-Connecting-IP ErrorLog ${APACHE_LOG_DIR}/{domain.com}-error.log CustomLog ${APACHE_LOG_DIR}/{domain.com}-access.log combined RewriteEngine on # 注释掉的重定向规则(避免循环) # RewriteCond %{SERVER_NAME} ={domain.com} [OR] # RewriteCond %{SERVER_NAME} =www.{domain.com} # RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] Include /etc/letsencrypt/options-ssl-apache.conf SSLCertificateFile /etc/letsencrypt/live/{domain.com}/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/{domain.com}/privkey.pem AllowEncodedSlashes On SSLProxyEngine on <Location "/blog"> # 代理到博客子目录 ProxyPass https://{blog-domain}/blog </Location> </VirtualHost> </IfModule>
问题原因
- Cloudflare代理下的HTTPS判断错误:原
.htaccess使用%{HTTPS}判断是否为HTTPS请求,但Cloudflare与服务器之间默认使用HTTP通信,导致服务器始终认为请求是HTTP,触发不必要的重定向逻辑。 - 请求路径被提前修改:Apache的
mod_dir模块会在执行重写规则前,尝试为不存在的路径添加.php后缀,捕获到的$1已经是修改后的路径,最终导致重定向URL带.php。 - 规则执行顺序问题:原规则使用捕获组
(.*)获取路径,未优先保留原始请求路径。
解决方案
修改.htaccess文件,调整以下几点:
- 使用Cloudflare提供的
X-Forwarded-Proto头判断HTTPS状态,确保准确识别客户端真实请求协议。 - 直接使用
%{REQUEST_URI}获取原始请求路径,避免Apache提前修改路径。 - 关闭
MultiViews(防止内容协商自动添加后缀)。
修改后的.htaccess代码:
<IfModule mod_rewrite.c> # 关闭MultiViews,防止自动添加文件后缀 Options -MultiViews RewriteEngine On # 匹配非HTTPS请求 或 非www域名的请求 RewriteCond %{HTTP:X-Forwarded-Proto} !https [OR] RewriteCond %{HTTP_HOST} !^www\. [NC] # 获取原始域名(不带www) RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC] # 重定向到https://www.域名 + 原始请求路径 RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE] </IfModule>
关键说明
%{HTTP:X-Forwarded-Proto}:Cloudflare会将客户端真实请求协议(http/https)放在这个头中,确保服务器能准确判断HTTPS状态。%{REQUEST_URI}:直接引用客户端发送的原始请求路径,不会被Apache的自动后缀添加逻辑修改。NE标记:防止URL中的特殊字符被转义,保证路径的准确性。Options -MultiViews:关闭内容协商功能,避免Apache自动为不存在的路径添加.php等后缀。
验证
修改后测试以下场景:
http://example.com/page→https://www.example.com/pagehttps://example.com/page→https://www.example.com/pagehttp://www.example.com/page→https://www.example.com/page
所有请求均应正确跳转到不带.php后缀的目标URL。
内容的提问来源于stack exchange,提问作者Lucas Roquilly
相关产品推荐
相关产品推荐

