Search code examples
apache.htaccessmod-rewriteurl-rewriting

Rewrite URL without Redirect in .htaccess


I would like to rewrite some of my paths on my website. I don't want to redirect, just simply modify the URLS. This is what I have attempted so far based on this answer:

RewriteRule ^thankyou.html /thankyou/$1 [L]

However, all this is doing is redirecting to my homepage. I have several paths I would like to rewrite globally. But I figured I would test it first on my /thankyou.html page to get it working. So in this example, I am just trying to rewrite example.com/thankyou.html to example.com/thankyou.

Here is the full .htaccess file:

RewriteEngine On

RewriteCond %{HTTP_HOST} !^www.example\.com [NC]
RewriteRule ^ https://www.example.com/$1 [L,R=301]

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]

RewriteRule ^thankyou.html /thankyou/$1 [L]


<IfModule mod_expires.c>
  ExpiresActive On

 # Images
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/gif "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"
  ExpiresByType image/x-icon "access plus 1 year"

  # Video
  ExpiresByType video/webm "access plus 1 year"
  ExpiresByType video/mp4 "access plus 1 year"
  ExpiresByType video/mpeg "access plus 1 year"

  # Fonts
  ExpiresByType font/ttf "access plus 1 year"
  ExpiresByType font/otf "access plus 1 year"
  ExpiresByType font/woff "access plus 1 year"
  ExpiresByType font/woff2 "access plus 1 year"
  ExpiresByType application/font-woff "access plus 1 year"

  # CSS, JavaScript
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType text/javascript "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"

  # Others
  ExpiresByType application/pdf "access plus 1 year"
  ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
</IfModule>

I've done this in the past on AWS Amplify using JSON which looks like this:

[
    {
        "source": "https://www.example.com/thankyou.html",
        "target": "https://www.example.com/thankyou",
        "status": "301",
        "condition": null
    }
]

But unfortunately, this web app is not hosted on amplify and I am struggling to find an equivalent.


Solution

  • RewriteRule ^thankyou.html /thankyou/$1 [L]
    

    If the underlying file is thankyou.html then you have the rewrite the wrong way round. You should be rewriting the request from /thankyou/ (which I assume is the intended canonical URL) to /thankyou.html. And consequently you should be requesting (linking to) the URL /thankyou/ in your HTML source.

    Aside: The $1 backreference in the substitution string is superfluous. It is always empty in this example.

    In other words:

    RewriteRule ^thankyou/$ thankyou.html [L]
    

    The slash prefix on the substitution string is not required for internal rewrites (and best omitted).

    Note that since the URL-path also matches the file basename, you need to ensure that MultiViews (part of mod_negotiation) is also disabled, otherwise your rule is essentially bypassed (which could result in problems later). At the top of the .htaccess file you should add:

    Options -MultiViews
    

    UPDATE:

    It sounds like you are expecting the URLs to magically change in the HTML source by doing the above. This is not the case and not the purpose of .htaccess. To change the URLs your users see (ie. the canonical URL), you must actually change the URLs you are linking to in the HTML source - there is no shortcut to this if this is an otherwise static site.

    If the "old" URLs (ie. /thankyou.html) are established and indexed by search engines and/or linked to by external third parties then you can also include an external 301 redirect from /thankyou.html to /thankyou in order to preserve SEO. But note that this is not essential for your site to function, since you should have already changed the URLs in the underlying HTML source. It is necessary for SEO.

    If you don't change the URL in the HTML source (and still implement the "redirect") then users can still "see" the old URL on the page (when they hover over or "copy" the link) and every time they click the link they are externally redirected (doubling the number of requests to the server and potentially slowing your users).

    For example:

    Options -MultiViews
    
    # Redirect from "/thankyou.html" to "/thankyou" for SEO
    RewriteRule ^thankyou\.html$ /thankyou [R=301,L]
    
    # Rewrite from "/thankyou" to "/thankyou.html"
    RewriteRule ^thankyou$ thankyou.html [END]
    

    Note the addition of the END flag on the second (rewrite) rule.

    Note also that I have removed the trailing slash on the URL. So, /thankyou is the URL you should be linking to and /thankyou.html is the underlying file that handles the request.