Search code examples
wordpress.htaccessmod-rewritehttpsurl-rewriting

How to force HTTPS on all URL's except one directory /images using .htaccess?


I am using WordPress and we have one directory that is not a WordPress directory /images and we need this directory to be HTTP only everything else should be forced to HTTPS.

In the WordPress settings we have the domain set to HTTP

WordPress settings

and in the .htaccess file we have the below.

I can not seem to get this to work. Our host is cloudways if that helps any

# This file was updated by Duplicator on 2018-09-10 16:52:27. See .htaccess.orig for the original .htaccess file.
# Please note that other plugins and resources write to this file. If the time-stamp above is different
# than the current time-stamp on the file system then another resource has updated this file.
# Duplicator only writes to this file once during the install process while running the installer.php file.

#RewriteEngine On

#RewriteCond %{HTTP:X-Forwarded-SSL} !on
#RewriteCond %{REQUEST_URI} ^\/(images)
#RewriteRule (.*) https://%{HTTP_HOST}/$1 [L,R=301]

#RewriteCond %{HTTP:X-Forwarded-SSL} =on
#RewriteCond %{REQUEST_URI} !^\/(images)
#RewriteRule (.*) http://%{HTTP_HOST}/$1 [L,R=301]

RewriteEngine On
RewriteCond %{HTTPS} on
RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI}

# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress



# MalCare WAF
<Files ".user.ini">
<IfModule mod_authz_core.c>
  Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
  Order deny,allow
  Deny from all
</IfModule>
</Files>

# END MalCare WAF

Solution

  • In the wordpress settings we have the domain set to http

    If you are wanting to force HTTPS everywhere except for the one directory, which is "outside of WordPress" then the "WordPress Address" and "Site Address" in the WP dashboard should both be set to HTTPS, not HTTP.

    #RewriteCond %{HTTP:X-Forwarded-SSL} !on
    #RewriteCond %{REQUEST_URI} ^\/(images)
    #RewriteRule (.*) https://%{HTTP_HOST}/$1 [L,R=301]
    
    #RewriteCond %{HTTP:X-Forwarded-SSL} =on
    #RewriteCond %{REQUEST_URI} !^\/(images)
    #RewriteRule (.*) http://%{HTTP_HOST}/$1 [L,R=301]
    
    RewriteEngine On
    RewriteCond %{HTTPS} on
    RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI}
    

    In the root .htaccess file you can redirect to HTTPS everywhere, but make an exception to exclude further processing if the /images/ directory (the one that should remain as HTTP) is requested.

    For example:

    # Prevent further processing if the "/images" directory is requested
    RewriteRule ^images($|/) - [L]
    
    # Redirect everything else to HTTPS
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    
    # BEGIN WordPress
    :
    

    No need to repeat the RewriteEngine On directive, since this already occurs later in the file (in the WP section).

    Make sure you clear your browser cache before testing and test with 302 (temporary) redirects to avoid caching issues.

    This assumes the SSL cert is installed on your application server and you aren't using a proxy/CDN/load balancer that might be managing the SSL connection.


    UPDATE: Since the above is still resulting in a redirect-loop it's possible you are behind a proxy server of some kind (either CloudWays - your webhost - or perhaps Cloudflare) that is managing the SSL connection. Try the following instead for the second rule (HTTP to HTTPS redirection):

    # Redirect everything else to HTTPS
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]