I have inherited a web app. It's running fine. But it's using HTTP, not HTTPS. This is the .HTACCESS file:

Options +FollowSymLinks

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L] </IfModule>

HTACCESS files are not my area of expertise. What I think this is doing is, "if there is NO specific file name, redirect to INDEX.PHP including any query string, then stop processing rewrite rules.

We need the page to default to index.php as it does, but if other links are specified, do not redirect to index.php.

What I need to do is this:

  1. If no page is specified, default to HTTPS://example.com/index.php (with query string if any)

  2. If a page IS specified, redirect it to HTTPS if it is NOT already on HTTPS.

In other words, the entry point should redirect to index.php over HTTPS, and every specified page should redirect over HTTPS (including query strings).

Something so simple, but I can't figure this out.

  • You have a stray </IfModule> - can you clarify whether you have anything else in the file, eg. a corresponding opening <IfModule> tag perhaps? Can you clarify what you mean by "page"? Is this any URL-path? Or a URL that maps to an actual file? – MrWhite Apr 11 '18 at 14:07
  • Typo. "We need the application to default to HTTPS://example.com/index.php (with query string if any), or to redirect any specified other pages to HTTPS. Yes, I saw the stray Ifmodule. that was there before I arrived. just cleaned that part up. – CSBDev Apr 11 '18 at 14:36
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L] </IfModule>

What this says is... for all requests (^) that do not map to an actual file (%{REQUEST_FILENAME} !-f) then internally rewrite the request to index.php (ie. the "front-controller").

The QSA (Query String Append) flag is not actually required here, since you aren't specifying a query string on the substitution (it's just index.php). The query string on the request will be available by default.

The stray </IfModule> on the end of the line will simply be ignored in this instance. But yes, that should be removed, which I believe you have done already.

Providing this already routes your URLs as required within your application then there is nothing else you need to change with your existing code.

The HTTP to HTTPS external redirect is a separate thing and should go before the existing directives. As a general rule, external redirects always go before internal rewrites.

By the sounds of it, you just need a standard "redirect everything to HTTPS". The specific code you need to use can depend on how the SSL cert is managed for your site (eg. whether a front-end proxy is being used etc.), but otherwise, if the SSL cert is installed directly on your application server then it's just a standard HTTP to HTTPS redirect, for example:

RewriteCond %{HTTPS} !on
RewriteRule (.*) https://example.com/$1 [R=301,L]

You might also consider canonicalising the www/non-www at the same time.

  • That is working, but now the URL displays index.php on all urls. What used to be example.com/login is now being redirected using https to example.com/index.php/login. Is there a way to hide the index.php from view so that it's just example.com/login. (I dont' know why this commenting system is removing the HTTPS prtion of the url i'm typing in. the https redirect is working. but now it's dispalying index.php in all urls where before, it only displays if the example.com url is typed in. otherwise, it would display the domain/route (it's a laravel app) – CSBDev Apr 11 '18 at 18:24
  • so if i typed in example.com it use to redirect to example.com/index.php which would then transform to example.com/login (a laravel app route). but it now shows example.com/index.php/routename on all urls. basically, i do have all pages with what you put going over https, but it's inserting index.php visibly in the urls. How do I hide index.php and just show example.com/route – CSBDev Apr 11 '18 at 18:35
  • It looks like you might have the directives in the wrong order? As mentioned above, the HTTP to HTTPS redirect must go before your existing directives, otherwise, this will indeed expose index.php since the request is first rewritten to index.php before then triggering an external redirect to index.php (which would probably break your Laravel routing?) If you want to include code/URL in a comment then surround it in backticks (``). – MrWhite Apr 11 '18 at 21:27
  • Also, make sure you clear your browser cache. Any erroneous 301 redirects will have been cached hard by the browser. It can often be easier to first test with 302 (temporary) redirects for this reason. (Or make sure caching is disabled whilst testing.) – MrWhite Apr 11 '18 at 21:30
  • If you were seeing a redirect to example.com/index.php/routename it looks like you were seeing a cached response from the code in @deltavin's answer. (?) – MrWhite Apr 11 '18 at 21:54

This is what worked:

RewriteEngine On 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule ^ index.php [QSA] 
RewriteCond %{HTTPS} !=on 
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Removed the L from the first rewrite rule so that the second also would work. The first directs any unspecified page to index.php, the second rewrite rule redirects to use https.

Thanks for the help folks.

  • These directives are in the wrong order. An external redirect (the 2nd rule block) triggers an entirely separate request from the client - the earlier rewrite is effectively lost, until the second request is processed and the request is rewritten to index.php again. Except on the second request, the redirect does not occur (because you are now on HTTPS) so it "works". – MrWhite Apr 11 '18 at 21:40
  • So I should simply swap the rules? – CSBDev Apr 12 '18 at 20:33
  • Yes, just swap the rules - so the external redirect is first. It will still work as before, except a little bit more efficiently. As mentioned in my answer, the QSA flag is not required on that RewriteRule. You can add the L flag back if you wish (it is implied anyway if it is the last RewriteRule directive in the file). However, if you don't include the L flag now and later add more directives then you might get problems. – MrWhite Apr 12 '18 at 23:45

You are right on your assumption

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f   --> if the f(ile) doesn't exists, 
RewriteRule ^ index.php [QSA,L] </IfModule> --> redirect to index.php

For the rules you want, try this and let us know:

//redirect all pages to /index.php
RedirectMatch 301 /*(.*) /index.php/$1  [EDIT: don't use this. Use your first rule + this http->https rule below]

//Rewrite to https
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Also consider this boilerplate that explains and implements all relevant concepts needed to run a contemporary website. It includes security, XSS prevention, caching among other things. I am suggesting this because the htaccess you've inherited is very minimal. URL: https://github.com/h5bp/html5-boilerplate/blob/master/dist/.htaccess

  • If I use that, I get a loop repeating redirection to index.php. – CSBDev Apr 11 '18 at 18:56
  • I think I know why that's happening. The first rule is redirecting all traffic to index.php. So, let's remove that and use the following: //redirect all pages to /index.php RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [QSA,L] </IfModule> //Rewrite to https RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] Difficult to format the code in a comment box. What I mean is, use your rule followed by the second rule I suggested. Ignore the first rule from my two rules. – deltavin Apr 11 '18 at 19:19
  • Lastly, htaccess config needs some trial and error. Try rules from this generator where you can formulate your own rules: htaccessredirect.net – deltavin Apr 11 '18 at 19:22
  • @deltavin Please edit your answer, rather trying to stuff code blocks in a comment. (Certainly trying to 301 redirect to index.php, passing the URL-path as PATH_INFO is very wrong! Advisable to never mix mod_rewrite and mod_alias directives in the same context - the mod_rewrite directives still execute first, despite the apparent order in .htaccess.) – MrWhite Apr 11 '18 at 21:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.