--- date: 2025-10-30 title: Apache Slash-y description: remove trailing /index.php from URIs with apache web server. preview_image: tags: programming permalink: /blog/27/ --- gahhhhhh this was driving me crazy, putting it here so i don't lose it basically this solves the problem where you have pages like ``` http://example.com/page2/index.php?query=true ``` and you want it to display in the browser as the much nicer ``` http://example.com/page2?query=true ``` and you can't use nginx try_files because you promised yourself you were gonna make this work in apache "for old times' sake" basically: this takes a surprisingly large number of rewrite rules. in order: - remove trailing slashes, `page2/` -> `page2` - remove file extensions, `page2.php` -> `page2` - remove index filenames, `page2/index.php` -> `page2` - oh yeah for EACH of those last three things, I hope you remembered to preserve the query string, so `page2/?query=true` -> `page2?query=true` - okay now you have a nice short URL in the browser. now just undo all that logic to get the actual php file to run on the server. - if `page2` is a directory then serve from `page2/index.php` - if `page2.php` exists then serve from `page2.php` - if none of those things exist then fall back on static file hosting. like, `page2.html` might exist, you can serve that, sure, why not. - oh you wanted to remove the html extension too? okay do all that again bozo. ```sh RewriteEngine On #LogLevel alert rewrite:trace6 # remove trailing slash RewriteRule (\/.*)\/+(\?.*)?$ $1$2 [R] # remove file extensions RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f RewriteRule (.*)\.(php|html)(\?.*)?$ $1$3 [NC,R] # remove index.php index.html etc RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d RewriteRule (.*)\/index(\?.*)?$ $1$2 [NC,R] # serve php file RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f RewriteRule (\?.*)?$ fcgi://php:9000/usr/local/apache2/htdocs/%{REQUEST_URI}.php$1 [P,L] # serve php file with index RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/ -d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.php -f RewriteRule (\?.*)?$ fcgi://php:9000/usr/local/apache2/htdocs/%{REQUEST_URI}/index.php$1 [P,L] # serve html file RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f RewriteRule ([^?]*)(\?.*)?$ $1.html$2 [L] # serve html file with index RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/ -d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.html -f RewriteRule ([^?]*)(\?.*)?$ $1/index.html$2 [L] ``` some useful tricks: - [NC] can be added after any regex rule to make it Non-Case sensitive. - [R] means "in-browser redirect" and is used when you want to fix a URI on the user's side. if you don't do this then it only affects where the server pulls data from. - [P] means "proxy" and it allows you to have the server pull data from another machine or from a program running on a local port. - [L] means "last one" and it skips all remaining rewrite rules, in case you were worried about matching too many of them. all this and more can be found at [the apache2 docs](https://httpd.apache.org/docs/current/mod/mod_rewrite.html). if there's an easy way to do all this then please please tell me, I miss try_files so much, holy cow.