Your file should still have the .html
extension on the server, otherwise the server/browser won't interpret it as html but text instead (which is the reason you see the code in your browser). So rename the files on your server using ftp again.
In order to let your server serve the file /test.html
when the url /test
is accessed, you want to rewrite that internally, i.e.:
RewriteRule ^test[^/]$ test.html
The ^
is to match the start of the string, the $
matches the end, so this will only rewrite if the url exactly matches test
. It will rewrite that request to test.html
. The rewrite is internal, this means it won't redirect the browser (the url in the address bar doesn't change). There is also the external rewrite ([R]
appended to the rule), which redirects the browser.
This rule also only matches urls that don't end with a trailing slash ([^/]
means "not slash"). We will handle urls with a trailing slash later.
You could create a custom RewriteRule
for each page that you want to rewrite:
RewriteRule ^foo[^/]$ foo.html
RewriteRule ^bar[^/]$ bar.html
This is a lot of work if you have many pages, so you may want to rewrite all urls, e.g. foo
or bar
should be rewritten to foo.html
/ bar.html
, and foo/bar
should be rewritten to foo/bar.html
.
You can also use a regular expression to match all requests. But you should first check if foo
isn't actually a directory (which could contain a index.html
and be a sub-directory you want to serve). Also you want to check if foo
isn't really a file on your server's file system. There are two rewrite conditions to check that (see the RewriteCond
directive):
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
Now you can add a rewrite rule for all requests:
RewriteRule ^(.+[^/])$ $1.html
$1
is the content of the first capture group, a capture group in a regex is an expression placed in ()
brackets. .
matches any character, the +
modifier means "one or more".
Note that this would cause a rewrite loop resulting in a 500 error (see this answer), so you need to also add a rewrite condition to check if the <request>.html
file actually exists on the file system:
RewriteCond %{REQUEST_FILENAME}.html -f
Also you might not want to rewrite urls that already have a .html
extension. I don't think it's necessary, as you already have the rule above which would in that case check for <file>.html.html
which probably shouldn't exist. But if you have to deal with that, you could add another condition:
RewriteCond %{REQUEST_FILENAME} !^.+\.html$
So putting it altogether your rewrite rule looks like this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !^.+\.html$ # not really necessary
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+[^/])$ $1.html
The only thing that you need to handle now are urls that have a trailing slash. For that we just add a simple external rewrite rule that removes the trailing slash if the url doesn't actually match a directory:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R,L]
This rule matches only urls that end with /
(regex /$
) and captures everything before the trailing slash as a group (regex (.+)
), then redirects to the group (which doesn't contain the slash). Notice the R
and L
flags behind the rule. R
is for redirect, which redirects the browser (url in address bar changes). L
is for last, meaning no other rules will be applied after this one, though rules will be applied again after the rewrite, and this is where the other rule gets applied.
TL;DR
RewriteBase /
# handle trailing slashes (if not a directory)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R,L]
# rewrite rule that internally adds the .html extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+[^/])$ $1.html