2

With the latest versions of SilverStripe they encourage you to use server side rules for URL re-writing and not Director::forceSSL(); and/or Director::forceWWW(); in your _config.php file as it is considered unreliable.

On an Apache server this would logically seem to suggest that it should be managed via an .htaccess file. Unfortunately the snippets shown below can fire a rewrite independently however chaining or combining in a single file seems to skip either the www or https case.

### SILVERSTRIPE START ###
### TRIMMED ROBOT/ERROR CODE ###

<IfModule mod_rewrite.c>

    # Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
    <IfModule mod_dir.c>
        DirectoryIndex disabled
        DirectorySlash On
    </IfModule>

    SetEnv HTTP_MOD_REWRITE On
    RewriteEngine On
    RewriteBase '/'

    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]


    # Deny access to potentially sensitive files and folders
    RewriteRule ^vendor(/|$) - [F,L,NC]
    RewriteRule ^\.env - [F,L,NC]
    RewriteRule silverstripe-cache(/|$) - [F,L,NC]
    RewriteRule composer\.(json|lock) - [F,L,NC]
    RewriteRule (error|silverstripe|debug)\.log - [F,L,NC]


    # Process through SilverStripe if no file with the requested name exists.
    # Pass through the original path as a query parameter, and retain the existing parameters.
    # Try finding framework in the vendor folder first
    RewriteCond %{REQUEST_URI} ^(.*)$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule .* index.php

</IfModule>
### SILVERSTRIPE END ###

<IfModule mod_rewrite.c>
    ### FORCE TRAILING SLASH ###
    ### Source - https://paulund.co.uk/using-htaccess-to-force-trailing-slash ###
    RewriteCond %{REQUEST_URI} /+[^\.]+$
    RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]

    ### FORCE WWW ###
    #### Modified from source https://paulund.co.uk/add-www-subdomain-to-all-urls-using-htaccess ###
    RewriteCond %{HTTP_HOST} !^$
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]

    ### FORCE SSL ###
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://www.example.com/$1 [R=301,L]

</IfModule>
danielmcclure
  • 25
  • 1
  • 6
  • A possible and well documented .htaccess based solution might be https://stackoverflow.com/a/43052755/4137738 – wmk Nov 22 '17 at 14:55

3 Answers3

1

Our approach is to enforce www and https in the Apache virtual host file:

<VirtualHost *:80>
  ServerName www.myexampledomain.com
  Redirect permanent / https://www.myexampledomain.com/
</VirtualHost>
<VirtualHost *:443>
  ServerName myexampledomain.com
  Redirect permanent / https://www.myexampledomain.com/
</VirtualHost>
<VirtualHost *:443>
  ServerName www.myexampledomain.com
  DocumentRoot etc etc
</VirtualHost>

Then finally we use this module to enforce trailing slashes: https://github.com/axllent/silverstripe-trailing-slash . There is a chance of a double redirect with this approach.

leptinella
  • 66
  • 3
  • I'm not sure that I'm able to use this method as I'm using a pre-configured container on a managed host. I have made use of the module for the trailing slashes now though, thanks! – danielmcclure Nov 21 '17 at 02:10
0

You probably want to start with moving your rewrite rules above the SilverStripe ones - they can be last.

Secondly, the [L] flag on your rules means "Last" and will stop any further processing, you may want to try removing them.

Thirdly, from your code you could potentially see 2 redirects (3 requests in totla) for a URL here which (IMO) is a worse experience (thus SEO impact) than a single redirect that doesn't enforce the www and/or the trailing slash.

It looks to me like you could have the following set of redirects just to hit a page:

http://example.com/contact-us
http://example.com/contact-us/
https://www.example.com/contact-us/

The alternative is SS4 is to use a HTTPMiddleware that could enforce this for you in PHP. Whilst not recommended it could be a bit more "transportable"

Dan Hensby
  • 1,118
  • 6
  • 11
  • Thanks for the additional information, the documentation for writing your own .htaccess isn't always that helpful. I was hoping to write a single rule that would cover all bases dynamically but didn't manage to get there. – danielmcclure Nov 21 '17 at 02:12
  • It's not really possible or worthwhile for SilverStripe to attempt to completely document all the different aspects you may wish to achieve with RewriteRules, therefore I wouldn't rely on SilverStripe documentation as a canonical or complete reference for writing RewriteRules in .htaccess files - the apache documentation would be a much better place to look. - https://httpd.apache.org/docs/2.0/misc/rewriteguide.html – Dan Hensby Nov 22 '17 at 09:24
  • 1
    I was actually referring to .htaccess documentation I had found, not SilverStripe's docs. But the page you have linked is much better than what I had been looking at so thanks again! – danielmcclure Nov 29 '17 at 20:14
0

We've had the same issue and added the following to the /.htaccess file (not /public/.htaccess)

RewriteEngine On

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

# Redirect to https
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteRule ^(.*)$ public/$1

Adding the rules to the /public/.htaccess resulted in a redirection to https://www.your-domain.com/public which caused an 404 - Page not found error.