Force HTTPS/HTTP with .htaccess

Hi

I’m a mod_rewrite newbie. I want to force HTTPS for certain directories and HTTP for the rest of the site. I can get HTTPS working but as the site links are all relative, when in a secure section the whole site is served via HTTPS. Hope that makes sense.

Here is what I’ve got so far:

RewriteEngine On
# Ensure correct host
RewriteCond %{HTTP_HOST} www.example.org.uk
RewriteRule (.*) http://www.example.org/$1 [R=301,L]

# SSL here
RewriteCond %{SERVER_PORT} !^443
RewriteRule ^members(.*) https://%{HTTP_HOST}/members$1 [R,L]
RewriteCond %{SERVER_PORT} !^443
RewriteRule ^store(.*) https://%{HTTP_HOST}/store$1 [R,L]

# not anywhere else
RewriteCond %{SERVER_PORT} ^443
RewriteCond !(^members/.*)$ [NC]
RewriteCond !(^store/.*)$ [NC]
RewriteRule (.*) http://www.example.org/$1 [R]

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|^members/forum/.*|^media_assets/.*|^js/.*|^files/.*)$ index.php [NC]

As you can see I redirect everything to a PHP file which handles the URL. If I force http:// I tend to get index.php at the end of the URL instead of the rewritten URL.

Thanks in advance

pod,

<FILES *.php>
Order Allow, Deny
Deny from ALL
</Files>

… is what you’re after then.

Regards,

DK

Thanks for your help but when I add that I get an internal server error message. Could you help with where this should go? I’ve tried a few positions but no joy.

Just to clarify what I’m trying to achieve:

  • force /members/ and /store/ into HTTPS

  • force the rest of the site into HTTP

but I want to direct all URL requests (for both HTTPS adn HTTP) to index.php

If I add a back reference into line two of this block:

# not anywhere else
RewriteCond %{SERVER_PORT} ^443
RewriteCond !(^members/.*|^store/.*)$ [NC]
RewriteRule (.*) http://www.wamt.org/$1 [R]

like so:

RewriteCond $1 !(^members/.|^store/.)$ [NC]

It forces HTTP but the URL fragment is lost and index.php is added instead.

Thanks

bd,

What you’d had in your code (WAY) above almost made sense - at least, the middle two sections did (the first should cause a loop and the fourth … well, I just don’t like redirecting everything to one file like that so you can label that a personal problem).

If you’re NOT using Apache 2.x, your regex needs a / after the Start anchor.

If you’re so keen on keeping “the URL fragment,” why not capture it in an atom and feed it to index.php in a query string?

DELETE the code in red.

[COLOR="Blue"]RewriteEngine On
# Ensure correct host 
RewriteCond &#37;{HTTP_HOST} www.example.org.uk[/COLOR]
[COLOR="Red"]RewriteRule (.*) http://www.example.org/$1 [R=301,L][/COLOR]

# SSL here 
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^(members|store)(.*) https://%{HTTP_HOST}/$1$2 [R,L]
[COLOR="Red"]RewriteCond %{SERVER_PORT} !^443
RewriteRule ^store(.*) https://%{HTTP_HOST}/store$1 [R,L]
[/COLOR]
# not anywhere else
RewriteCond %{SERVER_PORT} ^443$
RewriteCond !^(members|store)/ [NC]
[COLOR="Red"]RewriteCond !(^store/.*)$ [NC][/COLOR]
RewriteRule .? http://www.example.org%{REQUEST_URI} [R[COLOR="Blue"],L[/COLOR]] 

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|[COLOR="Red"]^[/COLOR]members/forum/.*|[COLOR="Red"]^[/COLOR]media_assets/.*|[COLOR="Red"]^[/COLOR]js/.*|[COLOR="Red"]^[/COLOR]files/.*)$ index.php [NC,L]

You canNOT have multiple Start anchors!

Regards,

DK

Hi dklynn

I really appreciate your help with this.

I tried your posted code:

RewriteEngine On
# Ensure correct host
RewriteCond %{HTTP_HOST} www.example.org.uk

# SSL here
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(members|store)(.*) https://%{HTTP_HOST}/$1$2 [R,L]

# not anywhere else
RewriteCond %{SERVER_PORT} ^443$
RewriteCond !^/(members|store) [NC]
RewriteRule .? http://www.example.org%{REQUEST_URI} [R,L]

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|members/forum/.*|media_assets/.*|js/.*|files/.*)$ index.php [NC,L]

but it doesn’t seemt to work:

  • the org.uk is not rediredcted .org
  • HTTPS is only served under the org.uk address
  • HTTPS is served for the whole site when in a secure section (ie links to non-secure areas are stilled served via HTTPS rather than HTTP)

I’m running Apache 1.3 and have tried the / and without. I did read that / don’t work with .htaccess. Is this true or have I put it in the wrong place?

I’ve put the:

RewriteRule (.*) http://www.wamt.org/$1 [R,L]

which fixes the .org.uk to .org redirect but I still can’t get non-secure sections to be served via HTTP.

Many thanks

It seems this line:

RewriteCond !^(members|store) [NC]

isn’t being matched. If I comment it out I get an HTTPS/HTTP loop for the store and members sections. But if I type https:// for another section it is redirected to serve it as http:// so the rest of that code block works.

It’s weird as it is wokring in the code block for forcing HTTPS.

Any thoughts anyone?

Thanks

bd,

Let me modify slightly rather than trying to comment on your code:

RewriteEngine on
# SSL here
# Ensure correct host
RewriteCond %{HTTP_HOST} www.example.org.uk [COLOR="Blue"][NC][/COLOR]
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(members|store)(.*) https://%{HTTP_HOST}/$1$2 [R,L]

# not anywhere else [COLOR="Red"]AND redirect to .org[/COLOR]
[COLOR="Blue"]RewriteCond %{HTTP_HOST} www.example.org.uk [NC][/COLOR]
RewriteCond %{SERVER_PORT} ^443$
RewriteCond !^/(members|store) [NC]
RewriteRule .? http://www.example.org%{REQUEST_URI} [R,L]

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|members/forum/.*|media_assets/.*|js/.*|files/.*)$ index.php [NC,L]

That’s nonsense! A1.x REQUIRES the / after the start anchor (in DocumentRoot while A2.x believes it’s already there - “^/?” handles both servers nicely.

See comment above about A1.x vs A2.x.

Regards,

DK

Hi dklynn

Thanks again for your help. For whatever reason I can’t get your code to work. It looks like it should but despite various re-jigs, it doesn’t work for me.

This code:


RewriteEngine On

# Ensure correct host
RewriteCond %{HTTP_HOST} www.example.org.uk
RewriteRule (.*) http://www.example.org/$1 [R=301]

# SSL here
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(members|store)(.*) https://%{HTTP_HOST}/$1$2 [R,L]

# not anywhere else
RewriteCond %{SERVER_PORT} ^443$
RewriteCond !^/?(members|store)(.*) [NC]
RewriteRule .? http://www.example.org%{REQUEST_URI} [R,L]

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|members/forum/.*|media_assets/.*|js/.*|files/.*)$ index.php [NC,L]

does everyhting* I want EXCEPT force HTTP where required.

It seems that the last rule is overriding the force HTTP code block. When I comment it out I can see HTTPS forced to HTTP but obviously the site stops working as the CMS works off the URL fragment.

Any ideas how to overcome this?

Thanks again.

  • redirect all .org.uk requests to .org
  • force HTTPS for the areas I want

bd,

Everything EXCEPT forcing http?

RewriteEngine on

# Ensure correct host 
RewriteCond &#37;{HTTP_HOST} www.example.org.uk
RewriteRule (.*) http://www.example.org/$1 [R=301] 

# SSL here 
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(members|store)(.*) https://%{HTTP_HOST}/$1$2 [R,L]

# not anywhere else
[COLOR="Red"]# RewriteCond %{SERVER_PORT} ^443$[/COLOR]
RewriteCond %{SERVER_PORT} !^80$
RewriteCond [COLOR="Blue"]%{REQUEST_URI}[/COLOR] !^/?(members|store)(.*) [COLOR="Red"]#[NC][/COLOR]
RewriteRule .? http://www.example.org%{REQUEST_URI} [R,L]

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|members/forum/.*|media_assets/.*|js/.*|files/.*)$ index.php [NC,L]

Actually, I’d expect your last block to rewrite to the index.php IN THE REQUESTED DIRECTORY LEVEL which is, probably, NOT the desired effect. Add the R=301 flag to the last RewriteRule to see where it’s sending you (GREAT testing technique). If you change index.php to /index.php, you’ll UNDO all the https redirects above so do NOT do that![indent]Gawd! I hate these CMS redirects![/indent]

Regards,

DK

Thanks but no joy again.

If I comment out this line:


# not anywhere else
RewriteCond &#37;{SERVER_PORT} !^80$
# RewriteCond !^/?(members|store)(.*) [NC]
RewriteRule .? http://www.wamt.org%{REQUEST_URI} [R,L]

I get a loop between HTTPS and HTTP in the ‘secure’ sections. So either this line isn’t being matched (odd, as it is matched in the preceding block) or another rule is overriding it.

If I add R=301 to the last rewrite rule, I get redirected to the index.php file in my root directory which is what I’d expect and want.

I guess I’ll just have to leave visitors on HTTPS which I’d rather not but I can’t see a way round this.

Thanks again for your help.

Cheers

bd,

I must’ve been rushing and didn’t check that RewriteCond - it was DEAD wrong and I have no valid excuse! Mea culpa! Please give the updated code a try (delete the red bits, too).

Regards,

DK

Hi dklynn

Sorry for the delay in replying. I’ve tried the revised code and it nearly works. The problem is the secure sections now redirect to:

http://www.example.org/index.php

If I manually type https:// for a non-secure area it is redirected to http:// which is great.

It seems it is so nearly there!

Thanks again

RewriteEngine on

# Ensure correct host 
RewriteCond &#37;{HTTP_HOST} www.example.org.uk
RewriteRule (.*) http://www.example.org/$1 [R=301] 

# SSL here 
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(members|store)(.*) https://%{HTTP_HOST}/$1$2 [R,L]

# not anywhere else
RewriteCond %{SERVER_PORT} !^80$
RewriteCond %{REQUEST_URI} !^/?(members|store)(.*)
RewriteRule .? http://www.example.org%{REQUEST_URI} [R,L]

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|members/forum/.*|media_assets/.*|js/.*|files/.*)$ index.php [NC,L]

bd,

That’s what the last RewriteRule is doing. Add the exclusion RewriteCond %{SERVER_PORT} !^443$ before the last RewriteRule and the https will not get redirected to index.php. I’d thought that was weird but I don’t know exactly what you’re trying to do (nor why you’re doing it that way).

Regards,

DK

Hi dklynn

If I do that I get a 404 error for the secure sections.

To explain how my system works:

x. ALL page requests (secure and non-secure) are handled by index.php, so everything needs to end up there

x. the system uses clean URLs and loads the required classes based on what the URL fragment contains:
– /store/ (load the store class)
– /members/ (load the members class)
– /photos/ (load the photo gallery class)
– /section/page-title (load the normal content class)

x. so the URL is something like:
http://www.example.org/section/page-title
and never
http://www.example.org/index.php

x. this works extremely well normally (on many sites) but it seems whatever .htaccess rule forces https to http (where https isn’t required) is overridden.

x. I want to ensure:
http://www.example.org/section/
https://www.example.org/store/

but when in the store section, ensure the relative links which all become https:// are forced to http:// unless it is a specified secure section.

x. so what I think I need is both of these rules below to work together at the same time, which has been the issue the whole way through:

RewriteRule .? http://www.example.org%{REQUEST_URI} [R,L]

RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|members/forum/.*|media_assets/.*|js/.*|files/.*)$ index.php [NC,L]

how can I force https and http and redirect all requests to index.php?

If there is a simpler rule (or rules for each instance) or way of doing this, that will ensure all requests are eventually handled by index.php I’d be happy to try it out.

Thanks once again for your help.

bd,

Good explanation.

Sort {HTTPS} by requested directory (on = store and members - all others null) then redirect to index.php (which becomes the exclusion, not {HTTPS}).[indent]HTTPS is on with $_SERVER[‘SERVER_PORT’] 443 but does not exist (null) with :80.[/indent]

RewriteEngine on

# Ensure correct host
RewriteCond %{HTTP_HOST} www.example.org.uk
RewriteRule (.*) http://www.example.org/$1 [R=301]

# SSL here
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(members|store)(.*) https://%{HTTP_HOST}/$1$2 [R,L]

# not anywhere else
RewriteCond %{SERVER_PORT} !^80$
RewriteCond %{REQUEST_URI} !^/?(members|store)(.*)
[COLOR="Blue"]RewriteCond %{REQUEST_URI} !^/?index\\.php$[/COLOR]
RewriteRule .? http://www.example.org%{REQUEST_URI} [R,L]

# Redirect everything to index.php for processing
RewriteRule !(\\.gif|\\.jpe?g|\\.png|\\.css|.ico|\\.php|\\.pdf|\\.doc|\\.html|[COLOR="Red"]members/forum/.*[/COLOR]|media_assets/.*|js/.*|files/.*)$ index.php [NC,L]

I’m not sure what you were doing with the regex in red but the rest looks okay with that exclusion on index.php.

Regards,

DK

Absolutely perfect! Works a treat.

Thanks very much for your time and effort wirth this. It’s very much appreciated.

BTW the regex exclusion is for a forum system that sits in a physical folder /members/forum/. Not pretty but I like to leave it alone.

Thanks again. Apache guru of the year 2008, as well I think!

bd,

THANKS for the feedback! Glad that we finally got you sorted out!

Regards,

DK