Skip to content

偽靜態規則 ​

程式只有 index.php 一個入口,所有頁面都靠它路由。不配偽靜態,除了首頁什麼都打不開。

Docker 安裝不需要配,映像裡已經寫好了。

下面三份規則語義完全一致:既做偽靜態轉發,也順手把不該被訪問的檔案擋在外面(日誌、資料庫備份、配置、.env、composer.json 等)。建議整段複製,不要只抄最後那條 location /。

Nginx ​

aaPanel(寶塔)使用者:Website(網站)→ 點你的網站 → URL rewrite(偽靜態),整段貼進去儲存。

nginx
# 只放行唯一入口 index.php,其餘 .php 一律不執行
if ($uri ~* "^/(?!(?-i:index\.php)(/|$)).*\.php(/|$)")             { return 404; }

location ~* ^/(runtime|kernel|config|vendor)/                { return 404; }
location ~  (^|/)(runtime|\.acgcache)(/|$)                   { return 404; }
location ~  /\.(?!well-known)                                { return 404; }
location ~* \.(log|sql|sqlite|db|db-wal|db-shm|bak|old|save|orig|swp|swo|tmp|ini|lock|key|pem|crt|cer|der|p12|pfx|p8|keystore|jks|asc|gpg|ppk|env|secret)$  { return 404; }
location ~* (~|composer\.(json|lock)|package(-lock)?\.json)$ { return 404; }
location / {
    try_files $uri $uri/ /index.php?s=$uri&$args;
}

第一條 if 為什麼不寫成 location:aaPanel 的配置模板裡,PHP 的 include enable-php-XX.conf 排在偽靜態之前,而 nginx 的正則 location 是按出現順序匹配、首個命中即止 —— 寫成 location ~ \.php$ 永遠輪不到它執行,會靜默失效。if 跑在更早的 rewrite 階段,不受順序影響。

第一條必須用 ~*(大小寫不敏感)

別只寫 location ~ \.php$;整段照抄,其餘幾條也別刪。

Apache ​

不用配。 程式根目錄的 .htaccess 已經寫好了,確認它沒被上傳工具漏掉即可。

只要確認 Apache 開了 mod_rewrite,並且站點配置裡 AllowOverride 不是 None。

IIS ​

Windows + IIS 需要裝 URL Rewrite 2.0 模組,然後把下面這段放進站點根目錄的 web.config:

xml
<rules>
	<!-- ① 程式目錄 -->
	<rule name="acg_deny_dir" stopProcessing="true">
		<match url="^(runtime|kernel|config|vendor)(/|$)"/>
		<action type="CustomResponse" statusCode="404" subStatusCode="0" statusReason="Not Found" statusDescription="Not Found"/>
	</rule>

	<rule name="acg_deny_runtime_nested" stopProcessing="true">
		<match url="(^|/)(runtime|\.acgcache)(/|$)"/>
		<action type="CustomResponse" statusCode="404" subStatusCode="0" statusReason="Not Found" statusDescription="Not Found"/>
	</rule>

	<!-- ② 點檔案 / 點目錄(放行 ACME 憑證校驗) -->
	<rule name="acg_deny_dotfile" stopProcessing="true">
		<match url="(^|/)\.(?!well-known)"/>
		<action type="CustomResponse" statusCode="404" subStatusCode="0" statusReason="Not Found" statusDescription="Not Found"/>
	</rule>

	<!-- ③ 敏感字尾 -->
	<rule name="acg_deny_ext" stopProcessing="true">
		<match url="\.(log|sql|sqlite|db|db-wal|db-shm|bak|old|save|orig|swp|swo|tmp|ini|lock|key|pem|crt|cer|der|p12|pfx|p8|keystore|jks|asc|gpg|ppk|env|secret)$"/>
		<action type="CustomResponse" statusCode="404" subStatusCode="0" statusReason="Not Found" statusDescription="Not Found"/>
	</rule>

	<!-- ④ 備份副本與依賴清單 -->
	<rule name="acg_deny_file" stopProcessing="true">
		<match url="(~|composer\.(json|lock)|package(-lock)?\.json)$"/>
		<action type="CustomResponse" statusCode="404" subStatusCode="0" statusReason="Not Found" statusDescription="Not Found"/>
	</rule>

	<!-- ⑤ 只放行唯一入口 index.php -->
	<rule name="acg_deny_php" stopProcessing="true">
		<match url="^(?!(?-i:index\.php)(/|$)).*\.php(/|$)"/>
		<action type="CustomResponse" statusCode="404" subStatusCode="0" statusReason="Not Found" statusDescription="Not Found"/>
	</rule>

	<!-- ⑥ 偽靜態 -->
	<rule name="acg_rewrite" stopProcessing="true">
		<match url="^(.*)$"/>
		<conditions logicalGrouping="MatchAll">
			<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
			<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
		</conditions>
		<action type="Rewrite" url="index.php?s={R:1}" appendQueryString="true"/>
	</rule>
</rules>

用的是 URL Rewrite 1.x 的話不支援 CustomResponse,把它換成 <action type="AbortRequest"/>,代價是響應體為空。

不要改用 requestFiltering 的 hiddenSegments。 它是任意層級匹配的,會把 /admin/config/... 後臺配置頁和外掛自帶的 assets/vendor/、assets/.../config/ 靜態資源一起 404 掉。

站點根目錄下放了別的 PHP 程式? ​

上面三份規則都只放行 index.php 一個入口。如果你在網站根目錄裡還放了 phpMyAdmin、adminer 之類的 PHP 工具,它們會被一起擋掉 —— 把這類工具挪到獨立站點即可。

驗證配好沒有 ​

訪問下面幾個地址,都應該是 404:

你的域名/composer.json
你的域名/runtime.log
你的域名/config/database.php

然後隨便點開一個商品頁面,能正常開啟就說明偽靜態生效了。

基於 MIT 協議開源