Last updated 16 August 2017. Created on 11 November 2009.
Edited by Joel MMCC, ddavidd, hansfn, marcus7777. Log in to edit this page.

HTTPS is a protocol which encrypts HTTP requests and their responses. This ensures that if someone were able to compromise the network between your computer and the server you are requesting from, they would not be able to listen in or tamper with the communications.

When you visit a site via HTTPS, the URL looks like this: https://drupal.org/user/login. When you visit a site via plain (unencrypted) HTTP, it looks like this: http://drupal.org/user/login.

Why is it important to you (and when)

HTTPS is typically used in situations where a user would send sensitive information to a website and interception of that information would be a problem. Commonly, this information includes:

  • Credit cards
  • Sensitive cookies such as PHP session cookies
  • Passwords and Usernames
  • Identifiable information (Social Security number, State ID numbers, etc)
  • Confidential content

Especially in situations where you, as the administrator, are sending your Drupal password or the FTP password for your server, you should use HTTPS whenever possible to reduce the risk of compromising your web site.

Moreover, HTTPS is now required for HTML5 Geolocation to work in nearly all modern browsers for privacy reasons! This is at the JavaScript implementation level, so the module used to supply this (e.g. GeoField [“Lat/Long” Widget] or IP Geolocation Views & Maps [“Set my location” Block] among others) cannot override it. If you attempt to use this over HTTP in any such browser (the only exceptions these days are dangerously outdated browsers such as on old Android devices and maybe some computers still running Windows XP or a PowerPC version of Mac OS X), it will not work and you will not get an error message explaining why (except perhaps in the browser’s Developer Tools Error Console) — the underlying JavaScript function calls simply won’t execute over HTTP. So if your web application needs to know where the visitor is without requiring typing in an address or manual Lat/Long coordinates, you must use HTTPS.

HTTPS can also prevent eavesdroppers from obtaining your authenticated session key, which is a cookie sent from your browser with each request to the site, and using it to impersonate you. For example, an attacker may gain administrative access to the site if you are a site administrator accessing the site via HTTP rather than HTTPS. This is known as session hijacking and can be accomplished with tools such as Firesheep.

Security is a balance. Serving HTTPS traffic costs more in resources than HTTP requests (both for the server and web browser) and because of this you may wish to use mixed HTTP/HTTPS where the site owner can decide which pages or users should use HTTPS. Though, with improved SSL/TLS efficiency and faster hardware, the overhead is less than it once was. Many security experts are now urging that all web-related traffic should go over HTTPS, and that the benefits far outweigh the cost (especially given the relatively new existence of Let’s Encrypt [see below]).

How to enable HTTPS support in Drupal

Web server configuration

  1. Get a certificate. Many hosting providers set these up for you — either automatically or for a fee. You can also use Let’s Encrypt which is free, automated, and open Certificate Authority. If you want to secure a test site, you could instead generate a self-signed certificate.
  2. Configure your web server. A few helpful links:

    Chances are, your webhost can do this for you if you are using shared or managed hosting.

Note: Clean URLs If you're using Apache for HTTP and HTTPS:

You will probably have two different VirtualHost buckets.

  1. A bucket for port :80 http
  2. A bucket for port :443 https

Each of these VirtualHost containers or buckets require that a specific Apache directive be added within them if you're using Clean URLs. This is because Drupal makes extensive use of .htaccess and mod_rewrite to provide friendly URLs.

Ensure you have the following within the directive, which is a child under the VirtualHost container: See Apache Documentation for AllowOverride

 <Directory "/path/to/yoursite">
AllowOverride All
 </Directory>

This means that your .htaccess takes precedence and that the Apache configuration will allow it to run as you would expect for Drupal.

Troubleshooting:
If you enabled HTTPS and it only works on the homepage and your sub links are broken, it's because the VirtualHost:443 bucket needs AllowOverride All enabled so URLs can be rewritten while in HTTPS mode.

Drupal configuration

  • On Drupal 7, if you want to support mixed-mode HTTPS and HTTP sessions, open up sites/default/settings.php and add $conf['https'] = TRUE;. This enables you use the same session over both HTTP and HTTPS -- but with two cookies where the HTTPS cookie is sent over HTTPS only. You will need to use contributed modules like securepages to do anything useful with this mode, like submitting forms over HTTPS. While your HTTP cookie is still vulnerable to all usual attacks. A hijacked insecure session cookie can only be used to gain authenticated access to the HTTP site, and it will not be valid on the HTTPS site. Whether this is a problem or not depends on the needs of your site and the various module configurations. For example, if all forms are set to go through HTTPS and your visitors can see the same information as logged in users, this is not a problem.

    Note that in Drupal 8, mixed-mode support has been removed #2342593: Remove mixed SSL support from core.

  • For even better security, send all authenticated traffic through HTTPS and use HTTP for anonymous sessions. On Drupal 8, install Secure Login module which resolves mixed-content warnings. On Drupal 7, leave $conf['https'] at the default value (FALSE) and install Secure Login. Drupal 7 and 8 automatically enable the session.cookie_secure PHP configuration on HTTPS sites, which causes SSL-only secure session cookies to be issued to the browser. On Drupal 6, see contributed modules 443 Session and Secure Login.

  • For best possible security, set up your site to only use HTTPS, and respond to all HTTP requests with a redirect to your HTTPS site. Drupal 7's $conf['https'] can be left at its default value (FALSE) on pure-HTTPS sites. Even then, HTTPS is vulnerable to man-in-the-middle attacks if the connection starts out as a HTTP connection before being redirected to HTTPS. Use the HSTS module or Security Kit module, or set the Strict-Transport-Security header in your webserver, and add your domain to the browser HSTS preload list, to help prevent users from accessing the site without HTTPS.

    You may want to redirect all traffic from http://example.com and http://www.example.com to https://example.com. You can do this by adding the code below to your server configuration file, i.e., the VirtualHost definitions:

    <VirtualHost *:80>
        ServerName www.example.com
        Redirect "/" "https://www.example.com/"
    </VirtualHost>
    
    <VirtualHost *:443>
        ServerName www.example.com
        # ... SSL configuration goes here
    </VirtualHost>

    The use of RewriteRule would be appropriate if you don't have access to the main server configuration file, and are obliged to perform this task in a .htaccess file instead:

    RewriteCond %{HTTPS} off [OR]
    RewriteCond %{HTTP_HOST} ^www\.example\.com*
    RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]

    There are existing comments in .htaccess that explain how to redirect http://example.com to http://www.example.com (and vice versa), but this code here redirects both of those to https://example.com.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

sstedman’s picture

Acquia Cloud users, please note the use of {HTTP:X-Forwarded-Proto} in your .htaccess to achieve redirects. Took me an age to find this info, so reposting from acquia to here:

# Redirect to HTTPS
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
bjdeliduka’s picture

As the subject says.... the Joys.

A client of mine has numerous customers with Drupal 7 sites. We are moving all of them behind CloudFlare (www.cloudflare.com) we they offer FREE SSL Certs, web caching, and ddos protection/mitigation. We then firewall the servers to only accept connections from the CF Caches and make sure that the actual HTTP Server is not listed in DNS (client/browsers should connect to the CF Servers which will then fetch pages from the actual server). The Drupal Server (apache 2.4 on centos) also use SSL to encrypt the connection between CF and the server (might as well keep everything out of plain text )

While the above looks and feels like a great solution to insuring all connections are encrypted we encountered a problem with some pages that have IFRAMES that load encrypted content. (web browsers throw an error when this occurs and often refuse to load the content without user intervention).

Options included 1) setting up a proxy and encrypting the insecure content. While technically possible it gives the user the impression the session is secure while some of the content is in plain text (though not to/from the client). 2) drop the content until it's available via a secure connection (client/customer did not like this option) 3) force pages that contain this content to be unencrypted (http) connections while the rest of the site is encrypted.

We chose option 3.

The sites had been previously configured to redirect connections to https using a rewrite rule in the .htaccess file (will probably move these into the vhost config files for performance reasons but only if we can agree on disabling the .htaccess files) As such every http connection becomes an https connection.

Normally a rewriterule could be created in the form:

RewriteCond %{REQUEST_URI} ^Streaming-Page.* [NC]
ReWriteRule ^/?(.*) http://%SERVER_NAME}$1 [R,L]
ReWriteRule ^/?(.*) https://%SERVER_NAME}$1 [R,L]

to catch connections to the page with the insecure iframe. (rewrite matching to http and non-matching to https)

try this with clean url's enabled and you never get the unencrypted page because every page request submitted to drupal does a final pass through the rewrite engine on /index.php.

I'm unsure of the exact reason but secure_pages were not considered a viable option.

The end result solution is a series of 13 rewriterule/rewritecond lines that can effectively replace the secure_pages module for forcing all but a select few (1 or more) pages to https connections.

RewriteCond %{REQUEST_URI} /index.php
RewriteRule ^ - [S=6]
RewriteCond %{REQUEST_URI} !^/Streaming-Page.* [NC]
RewriteCond %{REQUEST_URI} !^/$ [NC]
RewriteRule ^ - [S=4]
RewriteCond %{HTTPS} on
RewriteRule ^/?(.*) http://%{SERVER_NAME}/$1 [R,L]
RewriteRule ^ - [S=3]
RewriteCond %{HTTPS} on
RewriteRule ^ - [S=1]
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
RewriteCond %{HTTPS} !on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]

/Streaming-Page and the root page of the site are HTTP the rest of the site is HTTPS. Additional pages can be excluded from HTTPS by adding additional likes under the /Streaming-Page line following it's format.

The only known side affect of this code is that editing unencrypted pages is more complicated as the admin_menu drops on the unencrypted pages. Version 1.1 will include a method of disabling the http side from a clients browser (resulting in the browser errors that developers will deal with as needed while editing the pages) I'll also look an more detailed instructions on putting this into .htaccess files and removing unwanted/unneeded code for things like www. stripping (or pre-pending) etc

selinav’s picture

What should I do with following lines (D7) to set all my site in https ?

# Various rewrite rules.
<IfModule mod_rewrite.c>
  RewriteEngine on

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
   RewriteRule ^ - [E=protossl]
   RewriteCond %{HTTPS} on
   RewriteRule ^ - [E=protossl:s]

Is it compatible with

RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com*
RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]

Where should I add other redirections (with or without www, other domains) in the htaccess file ?

<IfModule mod_rewrite.c>
  RewriteEngine on

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
   RewriteRule ^ - [E=protossl]
   RewriteCond %{HTTPS} on
   RewriteRule ^ - [E=protossl:s]

  RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com*
RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]

  # Make sure Authorization HTTP header is available to PHP
  # even when running as CGI or FastCGI.
  RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  # Block access to "hidden" directories whose names begin with a period. This
  # includes directories used by version control systems such as Subversion or
  # Git to store control files. Files whose names begin with a period, as well
  # as the control files used by CVS, are protected by the FilesMatch directive
  # above.
  #
  # NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
  # not possible to block access to entire directories from .htaccess, because
  # <DirectoryMatch> is not allowed here.
  #
  # If you do not have mod_rewrite installed, you should remove these
  # directories from your webroot or otherwise protect them from being
  # downloaded.
  RewriteRule "(^|/)\." - [F]

	#redirection du .fr vers le .com
	RewriteCond %{HTTP_HOST} ^domain.fr$
	RewriteRule ^(.*) https://example.com/$1 [QSA,L,R=301]
	
	#redirection du blog vers le .com
	RewriteCond %{HTTP_HOST} ^blog.example.com$
	RewriteRule ^(.*) https://example.com/$1 [QSA,L,R=301]


  # If your site can be accessed both with and without the 'www.' prefix, you
  # can use one of the following settings to redirect users to your preferred
  # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
  #
  # To redirect all users to access the site WITH the 'www.' prefix,
  # (http://example.com/... will be redirected to http://www.example.com/...)
  # uncomment the following:

   RewriteCond %{HTTP_HOST} .
   RewriteCond %{HTTP_HOST} !^www\. [NC]
  ## RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
	RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
       

  #
  # To redirect all users to access the site WITHOUT the 'www.' prefix,
  # (http://www.example.com/... will be redirected to http://example.com/...)
  # uncomment the following:
  # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
  # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]

	RewriteCond %{HTTP_HOST} ^www.example.fr$
	RewriteRule ^(.*) https://www.example.com/$1 [QSA,L,R=301]
	RewriteCond %{HTTP_HOST} ^example.fr$
	RewriteRule ^(.*) https://www.example.com/$1 [QSA,L,R=301]


  # Modify the RewriteBase if you are using Drupal in a subdirectory or in a
  # VirtualDocumentRoot and the rewrite rules are not working properly.
  # For example if your site is at http://example.com/drupal uncomment and
  # modify the following line:
  # RewriteBase /drupal
  #
  # If your site is running in a VirtualDocumentRoot at http://example.com/,
  # uncomment the following line:
   RewriteBase /

Thanks in advance

Bairnsfather’s picture

I've been very happy with https://www.drupal.org/project/securepages for a long time. Just load the configuration page and put an asterisk in the field for which pages you want secured, i.e. all. I think the warning at the top of the project page is stale; I've used the module without patches or modifying my .htaccess for the past few 7.x releases. Check your settings.php and make sure the base_url variable contains https, not http.

[edit] But please don't take this as the last word on the currently best method to redirect all traffic to https these days. Based on recent reading, it seems HSTS is where things are headed.

Bairnsfather’s picture

Here's what I did that seems to work for D7 & D8 (specifically as of 7.54 & 8.3.1 on Apache 2.4.5 with php 5.6.30) using the stock .htaccess file with only the modifications mentioned below. In simple terms, the Strict-Transport-Security line will not initially redirect traffic from http to https. (That line is not seen on http requests and older browsers don't understand it.) Thus the interest in redirection with a RewriteRule; however, that leaves open the possibility of a MITM attack. But the hope is with DNSSEC and a modern browser that understands HSTS, in less than a second your browser will remember (for max-age seconds) to only request https resources, even if your site or another site has an http link/resource on it. In other words once your modern web browser loads a page via https from your site, the browser learns it should be strict and only make https requests, even if it encounters a resource or link specifying http.

First, make sure you have your server available via https and your certificate includes all subdomains you use. Max-age is in seconds, customize it for your needs, and be sure to read (at least) https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security (RFC link below.)

Below the lines:

# Various rewrite rules.
<IfModule mod_rewrite.c>
  RewriteEngine on

paste in

  # Take advantage of HSTS if it's available & the request was over https. 
  Header always set Strict-Transport-Security "max-age=3456000; includeSubDomains" env=HTTPS

  # Force all traffic to be https & strip 'www.' prefix. 
  RewriteCond %{HTTP_HOST} ^www\. [NC,OR]
  RewriteCond %{HTTPS} off
  RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
  RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

Then put a # in front of the three lines below to comment them out; it no longer applies since we just forced all traffic to https. The following lines are already in the .htaccess file and just below what you pasted in.

#  RewriteRule ^ - [E=protossl]
#  RewriteCond %{HTTPS} on
#  RewriteRule ^ - [E=protossl:s]

Also note the HSTS module https://www.drupal.org/project/hsts has versions for D7 & D8. Which is good if you run multisite and not all domains have a certificate.

Tip - go here to get free certs: https://LetsEncrypt.org

RFC 6797: https://tools.ietf.org/html/rfc6797

You can test things by opening your terminal application and curl -I your domain in various ways to inspect the header.

selinav’s picture

Finally, after a lot of tests, the code below works.
As Bairnfather says, it is necessary to comment the third first lines

<IfModule mod_rewrite.c>
  RewriteEngine on

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
  # RewriteRule ^ - [E=protossl]
  # RewriteCond %{HTTPS} on
  # RewriteRule ^ - [E=protossl:s]
  RewriteCond %{HTTPS} off
  RewriteCond %{HTTP:X-Forwarded-Proto} !https
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  
  RewriteCond %{HTTP_HOST} ^mydomain.com$
  RewriteRule ^(.*)   https://www.mydomain.com/$1  [QSA,L,R=301]
  

  # Make sure Authorization HTTP header is available to PHP
  # even when running as CGI or FastCGI.
  RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  # Block access to "hidden" directories whose names begin with a period. This
  # includes directories used by version control systems such as Subversion or
  # Git to store control files. Files whose names begin with a period, as well
  # as the control files used by CVS, are protected by the FilesMatch directive
  # above.
  #
  # NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
  # not possible to block access to entire directories from .htaccess, because
  # <DirectoryMatch> is not allowed here.
  #
  # If you do not have mod_rewrite installed, you should remove these
  # directories from your webroot or otherwise protect them from being
  # downloaded.
  RewriteRule "(^|/)\." - [F]

	#redirection du .fr vers le .com
	RewriteCond %{HTTP_HOST} ^mydomain.fr$
	RewriteRule ^(.*) https://mydomain.com/$1 [QSA,L,R=301]
	
	#redirection du blog vers le .com
	RewriteCond %{HTTP_HOST} ^blog.mydomain.com$
	RewriteRule ^(.*) https://mydomain.com/$1 [QSA,L,R=301]

	RewriteCond %{HTTP_HOST} ^www.mydomain.fr$
	RewriteRule ^(.*) https://www.mydomain.com/$1 [QSA,L,R=301]
	RewriteCond %{HTTP_HOST} ^mydomain.fr$
	RewriteRule ^(.*) https://www.mydomain.com/$1 [QSA,L,R=301]

Thanks a lot

T65’s picture

Nice work, thank you very much.

Aporie’s picture

Perfect ! Thanks a lot.

Finaly succed to get the url : https://www.mydomain.com

mpark’s picture

Hello, I think I have my .htaccess file correct, but I still do not have a green line here: https://www.wheretostay.tips/
Is not the problem in this case that I have the LetsCrypt certificate which is for free (and bad)?

John Morahan’s picture

No, your certificate is fine. The problem is that you're referencing an insecure resource. See https://www.whynopadlock.com/ for details.

macman911’s picture

Hi Bairnsfather,

Thanks very much for your code, it has helped me a lot and worked on my site. Ideally I would like to force https but not strip 'www.' Do you know how I would modify your code to do this?

IamOnStage’s picture

What would be required to keep the www?

alboyd’s picture

Thanks to @Bairnsfather.
Confirmed that this method worked for me too.
First I set up "Let's Encrypt" in my cPanel.
HINT: Remember to comment out these three lines:
# RewriteRule ^ - [E=protossl]
# RewriteCond %{HTTPS} on
# RewriteRule ^ - [E=protossl:s]

Agiss’s picture

Thanks @Bairnsfather

This worked like a charm on my site - Drupal7.56, PHP5.6.31, Apache2

Aporie’s picture

The best way I found to do this is (to put after rewrite engine on) :

# Force HTTPS and WWW
  RewriteCond %{HTTP:HTTPS} !on
  RewriteRule (.*) https://www.YOURSITEURL.com [QSA,L,R=301]
IamOnStage’s picture

This should be quite a common request, as Google/SEO prefers both https (secure connections) and www (OR not both www. and no-www.)

I have commented out the first three lines as mentioned above and added Aporie's code, but I am still getting an "www.EXAMPLE.co.uk redirected you too many times. Try clearing your cookies. ERR_TOO_MANY_REDIRECTS" error.

<IfModule mod_rewrite.c>
  RewriteEngine on

  # Force HTTPS and WWW
  RewriteCond %{HTTP:HTTPS} !on
  RewriteRule (.*) https://www.EXAMPLE.co.uk [QSA,L,R=301]

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
  # RewriteRule ^ - [E=protossl]
  # RewriteCond %{HTTPS} on
  # RewriteRule ^ - [E=protossl:s]

I have also tried with the below line both commented and un-commented:

  # To redirect all users to access the site WITH the 'www.' prefix,
  # (http://example.com/... will be redirected to http://www.example.com/...)
  # uncomment the following:
  RewriteCond %{HTTP_HOST} .
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

This is starting from a clean Drupal 7.56 .htaccess file with no other amendments.

Is this because I am using a .co.uk domain?

How do I force both www and https?

kevinfunk’s picture

On line 59 add

# Redirect to HTTPS
  RewriteCond %{HTTPS} off
  RewriteCond %{HTTP:X-Forwarded-Proto} !https
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Then uncomment

  RewriteCond %{HTTP_HOST} .
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
IamOnStage’s picture

Should I also comment out the three lines of code that Bairnfather suggests?:

# RewriteRule ^ - [E=protossl]
# RewriteCond %{HTTPS} on
# RewriteRule ^ - [E=protossl:s]
mpark’s picture

Yes, and I think its necessarily.

There is my part of htaccess (Drupal 8) going on Apache server correctly:

RewriteEngine on

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
  RewriteRule ^ - [E=protossl]
  RewriteCond %{HTTPS} on
  RewriteRule ^ - [E=protossl:s]

  # Make sure Authorization HTTP header is available to PHP
  # even when running as CGI or FastCGI.
  RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

  # Block access to "hidden" directories whose names begin with a period. This
  # includes directories used by version control systems such as Subversion or
  # Git to store control files. Files whose names begin with a period, as well
  # as the control files used by CVS, are protected by the FilesMatch directive
  # above.
  #
  # NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
  # not possible to block access to entire directories from .htaccess because
  # <DirectoryMatch> is not allowed here.
  #
  # If you do not have mod_rewrite installed, you should remove these
  # directories from your webroot or otherwise protect them from being
  # downloaded.
  RewriteRule "/\.|^\.(?!well-known/)" - [F]

  # If your site can be accessed both with and without the 'www.' prefix, you
  # can use one of the following settings to redirect users to your preferred
  # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
  #
  # To redirect all users to access the site WITH the 'www.' prefix,
  # (http://example.com/foo will be redirected to http://www.example.com/foo)
  # uncomment the following:
  RewriteCond %{HTTP_HOST} .
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

  # you need this for redirecting from all non-secured to secured pages
  RewriteCond %{HTTPS} !=on
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  
  #
  # To redirect all users to access the site WITHOUT the 'www.' prefix,
  # (http://www.example.com/foo will be redirected to http://example.com/foo)
  # uncomment the following:
  # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
  # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
BrianLP’s picture

As mpark says, add these three lines

# you need this for redirecting from all non-secured to secured pages
  RewriteCond %{HTTPS} !=on
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

in your htaccess (D7) after this:

  RewriteCond %{HTTP_HOST} .
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Of all solutions here, this is the one that does not lead to "too many redirects" in the browser.

IamOnStage’s picture

Looks great, thanks. But I am still getting "www.website.co.uk redirected you too many times. Try clearing your cookies. ERR_TOO_MANY_REDIRECTS"

  RewriteEngine on

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
  # RewriteRule ^ - [E=protossl]
  # RewriteCond %{HTTPS} on
  # RewriteRule ^ - [E=protossl:s]

  # Make sure Authorization HTTP header is available to PHP
  # even when running as CGI or FastCGI.
  RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

  # Block access to "hidden" directories whose names begin with a period. This
  # includes directories used by version control systems such as Subversion or
  # Git to store control files. Files whose names begin with a period, as well
  # as the control files used by CVS, are protected by the FilesMatch directive
  # above.
  #
  # NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
  # not possible to block access to entire directories from .htaccess, because
  # <DirectoryMatch> is not allowed here.
  #
  # If you do not have mod_rewrite installed, you should remove these
  # directories from your webroot or otherwise protect them from being
  # downloaded.
  RewriteRule "/\.|^\.(?!well-known/)" - [F]

  # If your site can be accessed both with and without the 'www.' prefix, you
  # can use one of the following settings to redirect users to your preferred
  # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
  #
  # To redirect all users to access the site WITH the 'www.' prefix,
  # (http://example.com/... will be redirected to http://www.example.com/...)
  # uncomment the following:
  RewriteCond %{HTTP_HOST} .
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  
  # you need this for redirecting from all non-secured to secured pages
  RewriteCond %{HTTPS} !=on
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

  # To redirect all users to access the site WITHOUT the 'www.' prefix,
  # (http://www.example.com/... will be redirected to http://example.com/...)
  # uncomment the following:
  # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
  # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
mpark’s picture

Hello buddy. You are right, there are still too many redirects and its not good for SEO of our webpages. I put my site to SEO tool Moz (Moz.com) and it wrote to me an issue about too many 301 redirects:
1) from non-www to www and 2) from non-https and non-www to https://www and 3) non-https and www to https://www

We need to find a better "oneline" solution, maybe something with one structured condition, with OR operators??? I'm not specialist to apache server and its conditions.

IamOnStage’s picture

On the clean Drupal 7.56 .htaccess file, line 59 is before the 'RewriteEngine on'
I would assume this should be after?

kevinfunk’s picture

You are correct. The code should be added after "RewriteEngine on."

Aporie’s picture

You should just let my line and comment all other lines :

<IfModule mod_rewrite.c>
  RewriteEngine on

  # Force HTTPS and WWW
  RewriteCond %{HTTP:HTTPS} !on
  RewriteRule (.*) https://www.EXAMPLE.co.uk [QSA,L,R=301]

 # To redirect all users to access the site WITH the 'www.' prefix,
  # (http://example.com/... will be redirected to http://www.example.com/...)
  # uncomment the following:
  # RewriteCond %{HTTP_HOST} .
  # RewriteCond %{HTTP_HOST} !^www\. [NC]
  # RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

So each request is redirected to the URL you set without conflict with other RewriteRule.

IamOnStage’s picture

What about

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
  RewriteRule ^ - [E=protossl]
  RewriteCond %{HTTPS} on
  RewriteRule ^ - [E=protossl:s]

Does this need commenting out as well?

Aporie’s picture

Yes,

It was already commented in your last post so I didn't say anything about it.

You keep in mind that you want to redirect every URL requests to the one you want : https://www.yourwebsite.com. So you just need ONE rule saying to rewrite every entered URL by the user to fit your format. No other "RewriteRule" which will just make conflict between your rules.

mpark’s picture

This your directive:

  # Force HTTPS and WWW
  RewriteCond %{HTTP:HTTPS} !on
  RewriteRule (.*) https://www.EXAMPLE.co.uk [QSA,L,R=301]

call me an error with: ERR_TOO_MANY_REDIRECTS

Still working but not ideal is this:

#RewriteRule ^ - [E=protossl]
#RewriteCond %{HTTPS} on
#RewriteRule ^ - [E=protossl:s]

RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Aporie’s picture

It seems that my solutions was great for D7 but not for D8. I have now this configuration under D8 :


########### Add those lines ###############
# Force HTTPS for the whole website :
  RewriteCond %{HTTP:HTTPS} !on
  RewriteRule (.*) https://%{SERVER_NAME}/$1 [QSA,L,R=301]


########### Comments those lines ###############
 # Set "protossl" to "s" if we were accessed via https://.  This is used later
 # if you enable "www." stripping or enforcement, in order to ensure that
 # you don't bounce between http and https.
 # RewriteRule ^ - [E=protossl]
 # RewriteCond %{HTTPS} on
 # RewriteRule ^ - [E=protossl:s]

########### Uncomments those lines ###############
# To redirect all users to access the site WITH the 'www.' prefix,
# (http://example.com/foo will be redirected to http://www.example.com/foo)
# uncomment the following:
 RewriteCond %{HTTP_HOST} .
 RewriteCond %{HTTP_HOST} !^www\. [NC]
 RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
mpark’s picture

Hello,
thank you for that. Is your solution better than existing:

RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

or its another alternative?

bramvandenbulcke’s picture

I have many websites on shared hosting, some rather small, so I prefer using a settings.php solution. Main reason: easier updating.

The article doesn't show best practices for a settings.php solution.

My main goal is requiring https and www. The shared hosting has a Let's Encrypt SSL certificate and HTTPS is forced in the settings of the hosting dashboard.

I have this snippet in settings.php (at the top, just below the opening php tag):

// Require www
if ($_SERVER['HTTP_HOST'] == 'example.com') {
  header('HTTP/1.0 301 Moved Permanently');
  header('Location: //www.example.com'. $_SERVER['REQUEST_URI']);
  exit();
}

I have tested this snippet and it's working fine. But advice is appreciated. Is this a good solution?

ressa’s picture

I also prefer a settings.php solution, for better maintainability. Are arrivals from http://www.example.com redirected to https://www.example.com by the setting in the hosting dashboard? Is it by any chance cpanel, if yes, how did you set that?


Try Drupal 8 at simplytest.me
bramvandenbulcke’s picture

I don't use cPanel for clients websites but I'm using legacy dashboards from local hosters.

They have a setting 'force HTTPS' in their dashboard (you need to have a Let's Encrypt certificate first, of course). This is a vhost setting sending all the traffic over port 80 to port 443.

BTW, I'm using this settings.php snippet (https included) for different websites because I wasn't certain about the double dashes:

// Require www
if ($_SERVER['HTTP_HOST'] == 'example.com') {
  header('HTTP/1.0 301 Moved Permanently');
  header('Location: https://www.example.com'. $_SERVER['REQUEST_URI']);
  exit();
}
ressa’s picture

Perhaps this is a solution? I have tested it on my own web site, and it seems to work ... Insert at the top of settings.php, right after <?php:

// force https
if ($_SERVER['HTTPS'] == '' ) {
  header('HTTP/1.1 301 Moved Permanently');
  header('Location: https://example.org'. $_SERVER['REQUEST_URI']);
}

// remove www
if ($_SERVER['HTTP_HOST'] == 'www.example.org') {
  header('HTTP/1.1 301 Moved Permanently');
  header('Location: https://example.org'. $_SERVER['REQUEST_URI']);
  exit();
}

Test

# http www -> https no-www
$ curl -I http://www.example.org/?TEST60;
HTTP/1.1 301 Moved Permanently
Location: https://example.org/?TEST60
# http no-www -> https no-www
$ curl -I http://example.org/?TEST61;
HTTP/1.1 301 Moved Permanently
Location: https://example.org/?TEST61
# https www -> https no-www
$ curl -I https://www.example.org/?TEST62;
HTTP/1.1 301 Moved Permanently
Location: https://example.org/?TEST62
# https no-www, no redirect
$ curl -I https://example.org/?TEST63;
HTTP/1.1 200 OK

Try Drupal 8 at simplytest.me
ressa’s picture

I was getting warnings like these with the code above:

Notice: Undefined index: HTTPS in include_once() (line 4 of /home/website/public_html/sites/default/settings.php).

Checking if the HTTPS array key exists seems to work better. This example is for a SSL, non-www web site:

$base_url = 'https://example.org';

// Force HTTPS
if (!array_key_exists('HTTPS', $_SERVER)) {
  header('HTTP/1.1 301 Moved Permanently');
  header('Location: https://example.org'. $_SERVER['REQUEST_URI']);
  exit();
}

// Remove www
if ($_SERVER['HTTP_HOST'] == 'www.example.org') {
  header('HTTP/1.0 301 Moved Permanently');
  header('Location: https://example.org'. $_SERVER['REQUEST_URI']);
  exit();
}

To disable SSL, use this:

// Disable HTTPS
if (array_key_exists('HTTPS', $_SERVER) && $_SERVER["HTTPS"] == "on") {
  header('HTTP/1.1 301 Moved Permanently');
  header('Location: http://example.org'. $_SERVER['REQUEST_URI']);
  exit();
}

Try Drupal 8 at simplytest.me
joeuk31’s picture

What works for me in D7 is this, this forces both https and www, I use the typical method of forcing www or non www in htaccess, but before that I add

RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

I usually place this right after

RewriteEngine on

The method in this tutorial always redirects to a /404.shtml page when I try to go to a non-www

karolus’s picture

It's often a good idea to check with your Web host if specific settings are recommended. I had to modify things a bit, but this is working for me:

.htaccess after RewriteEngine on:

RewriteCond %{HTTPS} !on
RewriteCond %{HTTP_HOST} ^www\.yourdomainhere\.com*
RewriteRule ^(.*)$ https://www.yourdomainhere.com/ [L,R=301]

Then, in the settings.php:
$base_url = 'https://www.yourdomainhere.com';

In addition, if you are pulling in external resources, such as Web fonts, it is advisable to change the URLs referencing them from http to https, if possible.

wesleymusgrove’s picture

My site was operating in mixed HTTP/HTTPS mode using secure_pages. After recently converting my site to HTTPS, and disabling the secure_pages module, I overlooked a config variable in settings.php, which kept the site operating in mixed HTTP/HTTPS mode. This resulted in two rows on the sessions table with the same SSID, but different SID. After the two rows existed there was a 50% chance that subsequent reads from sessions would pull back the wrong session data, based alphabetically on the SID.

To fix and verify:

  • I commented out $conf['https'] in settings.php.
  • Stepped through session.inc's _drupal_session_write.
  • Verified that after clearing my cookies and refreshing the home page, only one row was inserted into the sessions table.
  • Verified that after setting a $_SESSION variable and navigating to a new page, _drupal_session_write merged into the existing row instead of inserting a new row with a different SID.
Castor-designs’s picture

Hi guys. I went through this post and tried out several options you guys came up with.

The best I found was this solution:

        RewriteCond %{HTTPS} off [OR]
	RewriteCond %{HTTP_HOST} !^www\.MYSITE\.com*
	RewriteRule ^(.*)$ https://www.MYSITE.com/$1 [L,R=301]

With this I swap from http:// to https://www in one single redirect step.

Unfortunately this does not work for subpages. So http://mysite.com/categorypage will get redirected to https://mysite.com
Any idea how to solve that very last bit?

shaunmilo’s picture

How would one go about forcing both, www and https:// in the web.config file? Unfortunately, .htaccess isn't an option for me.