I am rebuilding my website in Drupal 8. Is it correct that HTTPS rewriting is not included in the default .htaccess file?

Comments

VM’s picture

incorrect. https is indeed included in the D8 .htaccess file. perform search in the .htaccess file for https and insure you read the comments for the two sections that its discussed.

BobNL’s picture

I've read the full .htaccess file and see some SSL/HTTPS, but don't understand what to change for HTTPS enforcing.

For now, I pasted my own code, but I would like to use the original.

VM’s picture

Insure the lines below are uncommented:

  # 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]

Then remove the # from one of the two directives in:

  # 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]
  #
  # 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]
BobNL’s picture

Thank you. Step 1: they are uncommented by default. I did not change anything.

Step 2: my website is on a sub domain, so I should use the second option, don't I? I uncommented the last two rules.

This doesn't enforce me to HTTPS yet.

VM’s picture

neither of the options are subdomain specific. Merely, whether you want www. or not.

are you sure you have an active SSL cert on the site?

Perhaps reviewing the already existing discussions and documentation page will aid.

https://www.youtube.com/watch?v=rj-21p1nNJQ

https://www.fastcomet.com/tutorials/drupal8/enable-ssl

BobNL’s picture

OK, well, I don't want www. on a subdomain so I unmarked the second option.

Yes, I'm sure there is an SSL certificate. This code in .htaccess makes it working. I'm OK with that of course, but most like to use the original code from Drupal.

mdrescher’s picture

#
# Rewrite http://www.example.com to https://www.example.com
#
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Make sure the www. redirect examples mentioned before are all commented out, and paste the snippet either before or after into your .htaccess.

The code you refer to is spread all over the internet, and while it effectively does the same, it includes a regexp that is slightly more expensive to evaluate than the one I pasted (I took the actual RewriteCond from the Apache manual).

mdrescher’s picture

Your first quite is the correct quote from .htaccess in Drupal, but it DOES NOT ENFORCE a redirect to https. All this snippet does is to set a flag in case the site has been accessed via https

The second snippet - depending which one you uncomment - enforces redirecting to either www.example.org or to example.org while respecting the original request's http or https status.

Depending on what is required - enforcing HTTPS without redirects, or enforcing HTTPS with redirects - the actual .htaccess code will look different.

A) Just enforce HTTPS

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

B) Enforce HTTPS with host rewrites

This is a more complicated situation, and requires deciding which type of redirection you want. The following example is based on redirection to www.example.org.

The  following decision table illustrates the cases .htaccess needs to consider. The cell values indicate the Apache Rewrite clauses given further below

Protocol \ Host example.org www.example.org
http 1 2
https 1 n/a

B.1) Rewrite clause 1
This clause covers both cases of redirecting to www.example.org and to enforce https: Regardless of being accessed via http or https, a redirect is always necessary. Hence:

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

B.2) Rewrite clause 2
This snippet is in fact the same as for case A) when placed after clause 1, because at this point in interpreting .htaccess the HTTP request includes the www. particle, and the only thing to do is a https rewrite.

Complete code (for redirecting to www.example.org scenario):

#
# Rewrite http(s)://example.com to https://www.example.com
#
RewriteCond "%{HTTP_HOST}" "!^www\." [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#
# Rewrite http://www.example.com to https://www.example.com
#
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

To use this snippet, ensure that the original redirect example in .htaccess are commented out (i.e. kept in their original state), and paste this snippet before or after it. It will redirect any domain served by the Apache host to https://www.your.tld

The code for rewriting to https://example.org is similar but needs deriving from the second part of the quoted .htaccess code.

I just tested this on my server and it works like a charm.

sopranos’s picture

what about code for drupal 7?

I have ome serious issues going on with google....my htaccess code works....but something is preventing google to index it properly or I dont know what is going on.....

Google comes to my site (i see google bot indexing my site) but I get no traffic.....

before HTTPS switch I got like 80 visitory per day....now 0.....this has been going on now for 2 weeks.....

Is there something wrong with the code i use?

# Various rewrite rules.
<IfModule mod_rewrite.c>
  RewriteEngine on
  
     RewriteCond %{HTTPS} off
   RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
   RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [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.
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
  RewriteRule ^ - [E=protossl]
  RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
  RewriteRule ^ - [E=protossl:s]

mdrescher’s picture

Drupal relies on Apache for web service and HTTP/HTTPS handling, hence the config code we are discussing is Apache, not Drupal. However, D7 may give you a different default .htaccess than D8.

I had a look at your .htaccess and I remember having had the same problem on my cpanel hosting with LetsEncrypt. Without knowing more about your hosting environment I think the problem is convoluted as follows:

  • You want to enforce HTTPS traffic
  • You need to allow LetsEncrypt to make HTTP requests to the .well-known subdirectories to auto-renew and validate the issued certificates

Your .htaccess has three Rewrite blocks that are interpreted in order for each request. All three blocks mess with the request if it is NOT targeting the LetsEncrypt stuff in .well-known (that is important)

Removing the LetsEncrypt-specific lines (dealing with that later) your config looks like this:

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

#
# Block 2
#
RewriteRule ^ - [E=protossl]

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

In itself this doesn't look bad, but blocks 2 and 3 are superfluous because all they do is to set a flag, not cause an actual HTTP redirect. Only block 1 causes a redirect to HTTPS if the request came in using HTTP.

Without knowing what is going on in the rest of your .htaccess file (especially the remainder of the rewrite statements) my suspicion is that the LetsEncrypt situation is the culprit.

Can you check your .htaccess file and see whether it has the following line in it? If it does, where is it? Before your code you posted, or after?

RewriteRule "/\.|^\.(?!well-known/)" - [F]

If that line is present and uncommented, then it is most likely contributing to the situation.

Can you check and see whether the domain your D7 is serving actually has valid certificates? If it doesn't then people will get warnings about your site and be directed away - and so will Google.

My general advice would be to talk to your provider and reconfigure how LetsEncrypt is validating your certificate(s) - a HTTP challenge is only one way to do so, but LetsEncrypt can also do a DNS challenge, which requires you to modify your DNS Zone accordingly - your hosting support should be able to help you with that. Once reconfigured, you can ditch all the complicated .well-known exceptions you have in your .htaccess file - they never really worked for me and I resolved to have DNS challenges for LetsEncrypt. Then your HTTPS enforcing could be as simple as this:

#
# Deny access to all "dot" files and directories such as .htaccess or .well-known/
#
RewriteRule "/\.|^\.(?!well-known/)" - [F]

#
# Force a permanent (R=301) redirect from HTTP to HTTPS
#
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

HTH,
Michel

sopranos’s picture

Sorry I have no clue.....I updated my .htaccess code before....and it seems to work, all I want that search bots can normally crawl my site..... can you check and see if this htaccess is any good?

Bluehost is totally horrible host....support has no idea how to help....they always tell me to get developer....

few years back they always helped.....now not anymore....

#
# Apache/PHP/Drupal settings:
#

# Protect files and directories from prying eyes.
<FilesMatch "\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock))$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig\.save)$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
</IfModule>
</FilesMatch>

# Don't show directory listings for URLs which map to a directory.
Options -Indexes

# Follow symbolic links in this directory.
# For security reasons, Option followsymlinks cannot be overridden.
#Options +FollowSymLinks
Options +SymLinksIfOwnerMatch

# Make Drupal handle any 404 errors.
ErrorDocument 404 /index.php

# Set the default handler.
DirectoryIndex index.php index.html index.htm

# Override PHP settings that cannot be changed at runtime. See
# sites/default/default.settings.php and drupal_environment_initialize() in
# includes/bootstrap.inc for settings that can be changed at runtime.

# PHP 5, Apache 1 and 2.
<IfModule mod_php5.c>
php_flag magic_quotes_gpc off
php_flag magic_quotes_sybase off
php_flag register_globals off
php_flag session.auto_start off
php_value mbstring.http_input pass
php_value mbstring.http_output pass
php_flag mbstring.encoding_translation off
</IfModule>

# Requires mod_expires to be enabled.
<IfModule mod_expires.c>
# Enable expirations.
ExpiresActive On

# Cache all files for 2 weeks after access (A).
ExpiresDefault A1209600

<FilesMatch \.php$>
# Do not allow PHP scripts to be cached unless they explicitly send cache
# headers themselves.
Otherwise all scripts would have to overwrite the
# headers set by mod_expires if they want another caching behavior. This may
# fail if an error occurs early in the bootstrap process, and it may cause
# problems if a non-Drupal PHP file is installed in a subdirectory.
ExpiresActive Off
</FilesMatch>
</IfModule>

# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
 
#
# Rewrite http(s)://example.com to https://www.example.com
#
RewriteCond "%{HTTP_HOST}" "!^www\." [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#
# Rewrite http://www.example.com to https://www.example.com
#
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Make sure Authorization HTTP header is available to PHP
# even when running as CGI or FastCGI.
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
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.
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
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]
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^ http%{ENV:protossl}://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]

# 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 /

# Pass all requests not referring directly to files in the filesystem to
# index.php. Clean URLs are handled in drupal_environment_initialize().
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^ index.php [L]

# Rules to correctly serve gzip compressed CSS and JS files.
# Requires both mod_rewrite and mod_headers to be enabled.
<IfModule mod_headers.c>
#
Serve gzip compressed CSS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]

# Serve gzip compressed JS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]

# Serve correct content types, and prevent mod_deflate double gzip.
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1]
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1]

<FilesMatch "(\.js\.gz|\.css\.gz)$">
# Serve correct encoding type.
Header set Content-Encoding
gzip
# Force proxies to cache gzipped & non-gzipped css/js files separately.
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
</IfModule>

sopranos’s picture

my site works fine...google crawled it with HTTPS

if i do site:mysite  I see all the new urls crawled....

but google stopped all the traffic..for some reason....and it comes back every 2 days crawling the site again and again.....

Or maybe my traffic counter is wrong...and is not showing any hits because of HTTPS redirect?

My other site that is build in WP works just fine....all the traffic was back after 3 days....but Drupal takes so long....

mdrescher’s picture

Hi,

I've clean it up a bit, and reordered some rules. Without more info I am afraid I can't really help -  I am not a D7 guy...

HTH,
Michel

#
# Apache/PHP/Drupal settings:
#
# Protect files and directories from prying eyes.
<FilesMatch "\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock))$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig\.save)$">
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
  <IfModule !mod_authz_core.c>
    Order allow,deny
  </IfModule>
</FilesMatch>

# Don't show directory listings for URLs which map to a directory.
Options -Indexes

# Follow symbolic links in this directory.
# For security reasons, Option followsymlinks cannot be overridden.
#Options +FollowSymLinks
Options +SymLinksIfOwnerMatch

# Make Drupal handle any 404 errors.
ErrorDocument 404 /index.php

# Set the default handler.
DirectoryIndex index.php index.html index.htm

# Override PHP settings that cannot be changed at runtime. See
# sites/default/default.settings.php and drupal_environment_initialize() in
# includes/bootstrap.inc for settings that can be changed at runtime.

# PHP 5, Apache 1 and 2.
<IfModule mod_php5.c>
  php_flag magic_quotes_gpc                 off
  php_flag magic_quotes_sybase              off
  php_flag register_globals                 off
  php_flag session.auto_start               off
  php_value mbstring.http_input             pass
  php_value mbstring.http_output            pass
  php_flag mbstring.encoding_translation    off
</IfModule>

# Requires mod_expires to be enabled.
<IfModule mod_expires.c>
  # Enable expirations.
  ExpiresActive On

  # Cache all files for 2 weeks after access (A).
  ExpiresDefault A1209600

  <FilesMatch \.php$>
    # Do not allow PHP scripts to be cached unless they explicitly send cache
    # headers themselves. Otherwise all scripts would have to overwrite the
    # headers set by mod_expires if they want another caching behavior. This may
    # fail if an error occurs early in the bootstrap process, and it may cause
    # problems if a non-Drupal PHP file is installed in a subdirectory.
    ExpiresActive Off
  </FilesMatch>
</IfModule>

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

  # Make sure Authorization HTTP header is available to PHP
  # even when running as CGI or FastCGI.
  RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  #
  # Note: I moved this up to be the first Rewrite rule so that any authorisation 
  #       happening with LetsEncrypt is respected.

  #
  # Rule 1: Rewrite HTTP to HTTPS except for LetsEncrypt stuff
  #
  RewriteCond %{HTTPS} off
  RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
  RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
  RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  #
  # Note: After this rule, we can safely ignore LetsEncrypt requests because the always use HTTP!
  #
  
  #
  # Rule 2: Rewrite https://example.com to https://www.example.com
  #         
  #
  RewriteCond "%{HTTP_HOST}" "!^www\." [NC]
  RewriteCond "%{HTTP_HOST}" "!^$"
  RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [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 /

  # Pass all requests not referring directly to files in the filesystem to
  # index.php. Clean URLs are handled in drupal_environment_initialize().
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteRule ^ index.php [L]

  # Rules to correctly serve gzip compressed CSS and JS files.
  # Requires both mod_rewrite and mod_headers to be enabled.
  <IfModule mod_headers.c>
    # Serve gzip compressed CSS files if they exist and the client accepts gzip.
    RewriteCond %{HTTP:Accept-encoding} gzip
    RewriteCond %{REQUEST_FILENAME}\.gz -s
    RewriteRule ^(.*)\.css $1\.css\.gz [QSA]

    # Serve gzip compressed JS files if they exist and the client accepts gzip.
    RewriteCond %{HTTP:Accept-encoding} gzip
    RewriteCond %{REQUEST_FILENAME}\.gz -s
    RewriteRule ^(.*)\.js $1\.js\.gz [QSA]

    # Serve correct content types, and prevent mod_deflate double gzip.
    RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1]
    RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1]

    <FilesMatch "(\.js\.gz|\.css\.gz)$">
      # Serve correct encoding type.
      Header set Content-Encoding gzip
      # Force proxies to cache gzipped & non-gzipped css/js files separately.
      Header append Vary Accept-Encoding
    </FilesMatch>
  </IfModule>
</IfModule>
sopranos’s picture

what do you mean by you are not a D7 guy....you never installed d7 before?

mdrescher’s picture

I started with Drupal 8 :-)

junix33’s picture

This might help, I got this from this page https://www.drupal.org/https-information and it works for my site.

Redirect to HTTPS with settings.php

You can also force SSL and redirect to a domain with or without www in settings.php, the benefit is that it won't get overwritten after updating Drupal. Insert this at the top of settings.php, right after <?php:

// Force HTTPS
// PHP_SAPI command line (cli) check prevents drush commands from giving a
// "Drush command terminated abnormally due to an unrecoverable error"
if ( (!array_key_exists('HTTPS', $_SERVER)) && (PHP_SAPI !== 'cli') ) {
  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();
}
Anonymous’s picture

The only thing that worked for me. Thx for sharing!

Binu Varghese’s picture

Just to confirm that this works.. Thanks!

mrlexington’s picture

Worked for me. I appreciate the detailed write up. Thanks!

jptillman’s picture

*DELETED*

camhoward’s picture

The Enabling HTTP Secure (HTTPS) page at https://www.drupal.org/https-information offers two different ways to force https.

One method uses changes to the .htaccess file (recommended by @mdrescher in this forum) and the other method uses changes to settings.php (recommended by @junix33 in this forum).

Are both methods equally secure in Drupal 8 or is one method recommended over the other?

tryitonce’s picture

.... and? Any answers?

mdrescher’s picture

I cannot state whether one way is more secure over the other - I am not a cybersecurity researcher.

What I *can* say is that either works at different levels of the stack, at different processing times: The .htaccess method catches HTTPS enforcement much earlier (pretty much as a first after Apache receives the request) than the settings.php method, which only ever triggers once Drupal (several call stacks past .htaccess) determines which settings.php to process (e.g. serving as a multi-domain environment). In terms of performance, I suspect the .htaccess method being faster (if ever measurable) than settings.php.

An arguably weak argument might be that, in terms of security vulnerabilities in code processing HTTPS enforcement instructions, the Apacke community is by far larger than the Drupal community, and therefore one may deduce that "swarm diligence" on that code might be better in Apache than in Drupal.

As for the argument made earlier that settings.php will not be overridden, that is IMHO *not* the case, at least in the default setting (where the default site serves for the only domain served by the Drupal instance). Likewise, when checking in .htaccess (which I do), you always see that it has changed when you assess upgrading Drupal core (via composer I suggest) and list all git changes. I then quickly merge any changes in .htaccess, if any, and check it in. Done. HTTPS enforcement in source code management.

*I* certainly prefer .htaccess over settings.php.

lennyaspen’s picture

https://www.drupal.org/https-information#settings-php-redirect

this is the correct answer

insert this code right after <?php in settings.php
looks like it won't give any error to drush either but haven't tested it.

non-www sites:
 

// Force HTTPS
// PHP_SAPI command line (cli) check prevents drush commands from giving a
// "Drush command terminated abnormally due to an unrecoverable error"
if ( (!array_key_exists('HTTPS', $_SERVER)) && (PHP_SAPI !== 'cli') ) {
  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();
}

with www sites:
 

if ( (!array_key_exists('HTTPS', $_SERVER)) && (PHP_SAPI !== 'cli') ) {
  if (substr($_SERVER['HTTP_HOST'], 0, 4) <> 'www.') {
    $new_url = 'www.' . $_SERVER['HTTP_HOST'];
  } else {
    $new_url = $_SERVER['HTTP_HOST'];
  }
  $new_url .= $_SERVER['REQUEST_URI'];

  header('HTTP/1.1 301 Moved Permanently');
  header('Location: https://'. $new_url);
  exit();
}
jptillman’s picture

Thanks for posting this option.  It's more maintainable than what I've been doing with .htaccess.  I find it embarrassing that someone would have to ready any docs at all to discover the best way to force HTTPS at this point in Drupal's (and the web's) development.  IMHO, enabling this is a feature that should be baked into the core of Drupal by now.  How hard would it be to put a checkbox somewhere in the main system configuration?  Maybe I'll get to the point I can do something about it myself someday.

hassebasse’s picture

Thanks lennyaspen

You suggestion work great, and the advantage is that it is less that get lost when updating the core and the .htaccess get lost.

I'm on D9.2.6

jhnnsbstnbch’s picture

The only / only solution that worked for me in .htaccess was the one posted by mdrescher (see snippet below).  Simply put, nothing else did the trick.  I commented everything else in .htaccess that supposedly was designed to force to https.  I have been working with Drupal since its inception 19 years ago and lease a UNiX server.

#
# Rewrite http://www.example.com to https://www.example.com
#
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Annelies Van der Wee’s picture

Finally something that works!
Thanks

Slown’s picture

Thank you for sharing :-)