Codeigniter4 Shared web hosting. Issue with configuring URLs - .htaccess

here is the thing. localhost development works fine. as I move to shared hosting try to configure codeigniter4 I'm facing issues with routes.
I use softaculouse to install CI4 on the main directory (public_html). when I try to configure the routes things work fine except
when I write the domain name.
example
https://example.com/ (Issue) it will send me to https://example.com/public/ (Code 500)
I contacted support they claim the issue in public folder I'm not allowed to add .htaccess so they deleted it for me .htaccess file in public. things work fine. however; when I write https://example.com/ works but the URL in the address bar changes to https://example.com/public
How to remove /public ?
is it a .htaccess configuration?
is it an issue with Apache configuration from hosting company side?
by the way
https://example.com/home (No problem)
https://example.com/en (No Problem) after modifying routes using {locale}
htaccess in public_html
# To prevent access to .env and other files
<Files .*>
# Apache 2.2
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
</Files>
<IfModule mod_alias.c>
RedirectMatch 301 ^/$ https://example.com/public
</IfModule>
This is htaccess which initially was generated inside public folder (Its standard generated by composer i think)
# Disable directory browsing
Options All -Indexes
# ----------------------------------------------------------------------
# Rewrite engine
# ----------------------------------------------------------------------
# Turning on the rewrite engine is necessary for the following rules and features.
# FollowSymLinks must be enabled for this to work.
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
# If you installed CodeIgniter in a subfolder, you will need to
# change the following line to match the subfolder you need.
# http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase
# RewriteBase /
# Redirect Trailing Slashes...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Rewrite "www.example.com -> example.com"
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# Checks to see if the user is attempting to access a valid file,
# such as an image or css document, if this isn't true it sends the
# request to the front controller, index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]
# Ensure Authorization header is passed along
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
<IfModule !mod_rewrite.c>
# If we don't have mod_rewrite installed, all 404's
# can be sent to index.php, and everything works as normal.
ErrorDocument 404 index.php
</IfModule>
# Disable server signature start
ServerSignature Off
# Disable server signature end

Related

How to htaccess-redirect single directory to external URL, while URL-masking

There are many similar questions here, but none seem to be exactly the same, and something is tripping me up.
I have one specific internal URL, mydomain.com/a-directory, that I want to forward to the external URL https://mailchi.mp/mydomain.com/a-directory , while still keeping the browser's shown URL as mydomain.com/a-directory.
I have tried:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^mydomain\.com/a-directory$
RewriteRule ^(.*) https://mailchi.mp/mydomain.com/a-directory [P]
</IfModule>
And also:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^a-directory$ https://mailchi.mp/mydomain.com/a-directory [P]
</IfModule>
Apache mod_proxy is installed.
Edit: Both seem to be mostly ignored, as no forwarding is happening, and it's not crashing. The browser is just saying that the page can't be found, as www.httpmydomain.dom/a-directory doesn't exist.
Edit:
The .htaccess file contains the following.
AuthType Basic
AuthName "Restricted access"
AuthUserFile /home/cpanelUser/.htpasswd
Require valid-user
#
# 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.
Options +FollowSymLinks
# 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
RewriteCond %{HTTP_HOST} ^mydomain\.com/a-directory$
RewriteRule ^(.*) https://mailchi.mp/mydomain.com/a-directory [P]
# 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]
# 2 Redirect to HTTPS
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
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]
# 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} !^blog2
RewriteCond %{REQUEST_URI} !=/phpinfo.php
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>
# Add headers to all responses.
<IfModule mod_headers.c>
# Disable content sniffing, since it's an attack vector.
Header always set X-Content-Type-Options nosniff
</IfModule>
RewriteCond %{HTTP_HOST} ^anotherAliasDomain\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.anotherAliasDomain\.com$
RewriteRule ^/?$ "https\:\/\/www\.mydomain\.com\/" [R=301,L]
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php72†package as the default “PHP†programming language.
<IfModule mime_module>
AddHandler application/x-httpd-ea-php72 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit
Any help will be greatly appreciated.
RewriteCond %{HTTP_HOST} ^example\.com/a-directory$
RewriteRule ^(.*) https://mailchi.mp/example.com/a-directory [P]
I have modified it to: RewriteCond ^https://www\.example\.com/a-directory$
Whilst the code is in the correct place (although it is before the HTTP to HTTPS redirect, so you might be trying to proxy an HTTP request), you are not using the correct directives (although the 2nd code block in your question is correct, providing the two domains point to different servers).
Neither of the above two conditions (RewriteCond directives) make much sense. The 2nd condition above is syntactically invalid as you are missing the first (or second?) argument.
The HTTP_HOST server variable contains the value of the Host HTTP request header. eg. If you request http://example.com/a-directory then HTTP_HOST contains example.com. However, if you request http://www.example.com/a-directory then HTTP_HOST will contain www.example.com.
So, if you are requesting http://example.com/a-directory then the directive you should be using is as per your second code block:
RewriteRule ^a-directory$ https://mailchi.mp/example.com/a-directory [P]
If you specifically need to check the requested host then:
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule ^a-directory$ https://mailchi.mp/example.com/a-directory [P]
However, assuming the target server allows you to proxy requests via this URL (they could block you) then you may still need additional directives in your server config / virtualhost to correctly configure the reverse proxy. Notably the ProxyPassReverse directive. Without this, if the target server issued an HTTP redirect then the user would be redirected away from your domain (example.com).

Silverstripe htaccess

I have a Silverstripe platform website that has duplicate URLs for www, non-www, http and https
There seem to be multiple solutions but no definitive answer. Is there someone that knows the correct code for the htaccess file for Silverstripe?
I want to get all pages pointing to https ://www
This is the current code in the htaccess file -
ErrorDocument 401 /base/401.txt
### SILVERSTRIPE START ###
# Deny access to templates (but allow from localhost)
<Files *.ss>
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Files>
# Deny access to IIS configuration
<Files web.config>
Order deny,allow
Deny from all
</Files>
# Deny access to YAML configuration files which might include sensitive information
<Files ~ "\.ya?ml$">
Order allow,deny
Deny from all
</Files>
# Route errors to static pages automatically generated by SilverStripe
ErrorDocument 404 /assets/error-404.html
ErrorDocument 500 /assets/error-500.html
<IfModule mod_env.c>
# Ensure that X-Forwarded-Host is only allowed to determine the request
# hostname for servers ips defined by SS_TRUSTED_PROXY_IPS in your _ss_environment.php
# Note that in a future release this setting will be always on.
SetEnv BlockUntrustedIPs true
</IfModule>
<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
</IfModule>
RewriteEngine On
# non-www to www redirect
#RewriteCond %{HTTP_HOST} ^bolstered.com.au$ [NC]
#RewriteRule (.*) https://www.bolstered.com.au/$1 [R=301,L]
# http to https redirect
#RewriteCond %{HTTPS} !=on
#RewriteRule ^ (.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Enable HTTP Basic authentication workaround for PHP running in CGI mode
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Deny access to potentially sensitive files and folders
RewriteRule ^vendor(/|$) - [F,L,NC]
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
RewriteRule composer\.(json|lock) - [F,L,NC]
RewriteCond %{REQUEST_URI} ^(.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.php$
RewriteRule .* index.php?url=%1&%{QUERY_STRING} [L]
</IfModule>
### SILVERSTRIPE END
I typically keep the SilverStripe part between ### SILVERSTRIPE START ### and ### SILVERSTRIPE END ### untouched and put my rules only before or after those of silverstripe.
There is no issue with having RewriteEngine On twice.
I also did not bother to check if mod_rewrite exists, because all my servers will have it enabled and I wouldn't let a client put it on a server without it.
Here is a full example of a .htaccess that I would typically use in silverstripe a project:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^localhost [NC]
RewriteCond %{HTTP_HOST} !^127.0.0.1 [NC]
RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP_HOST} !^www\.examle\.org [NC]
RewriteRule ^ https://www.examle.org%{REQUEST_URI} [R=301,L]
### SILVERSTRIPE START ###
# Deny access to templates (but allow from localhost)
<Files *.ss>
Require ip 127.0.0.1
</Files>
# Deny access to IIS configuration
<Files web.config>
Require all denied
</Files>
# Deny access to YAML configuration files which might include sensitive information
<Files ~ "\.ya?ml$">
Require all denied
</Files>
# Route errors to static pages automatically generated by SilverStripe
ErrorDocument 404 /assets/error-404.html
ErrorDocument 500 /assets/error-500.html
<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
# Enable HTTP Basic authentication workaround for PHP running in CGI mode
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]
RewriteRule ^Security - [F,L,NC]
# Process through SilverStripe if no file with the requested name exists.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php
</IfModule>
### SILVERSTRIPE END ###
Step-by-step explanation:
Turns on the rewrite engine
RewriteEngine On
The 4 RewriteCond are all conditions connected to the RewriteRule below it.
RewriteCond %{HTTP_HOST} !^localhost [NC]
RewriteCond %{HTTP_HOST} !^127.0.0.1 [NC]
RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP_HOST} !^www\.examle\.org [NC]
Multiple conditions will be a logical AND, unless you add a [OR].
[NC] stands for no-case, so not case-sensitive
The first 2 are an exception for localhost/127.0.0.1 to ensure a redirect will not be done when I am developing on my workstation.
3 is checking if https if off
4 is checking if the domain is correct
So speaking in pseudo code, it's like this:
if ($HTTP_HOST != "localhost" && $HTTP_HOST != "127.0.0.1" AND ($HTTPS != "on" OR $HTTP_HOST != "www.examle.org") {
do_redirect();
}
The actual redirect
RewriteRule ^ https://www.examle.org%{REQUEST_URI} [R=301,L]
It's redirecting to the desired domain and attaches the path (/foo/bar) and the query paramters (?foo=bar) to it.
R=301 is the http response code. If you wanted a temporary redirect you could make it 302.
L means Last I think, which will stop the processing at this point and will not continue to try other rules below.
Alternatives:
.htaccess is the best way to do it. But it's worth pointing out that this is not the only option.
You could do it in plain PHP, in the config of any/most webservers, ...
And SilverStripe has builtin methods for doing the check & redirect:
Director::forceSSL();
Director::forceWWW();
but as said, .htaccess is much better (much faster and only a single redirect)

Installing Codeigniter 4 in a subdirectory and keep the domain general URL structure

Current situation:
I already have a Wordpress installation at http://example.com and this site is multilanguage so you can access a web page in English at http://example.com/en/something-here/ and you can access the Spanish version of this webpage at http://example.com/es/algo-aqui/.
What I am trying to do:
I want to install Codeigniter 4 in http://example.com/software/ but I want to keep the general website URL structure, so I need to be able to access the CI4 software through the URL http://example.com/en/software/ and http://example.com/es/software/. Always reading the same CI4 installation mentioned at the beginning of this paragraph.
What I already tried:
I deployed the CI4 files at http://example.com/software/ and modified the .htaccess files of both, the Wordpress site and Code Igniter.
This is my WP .htaccess file on the root directory:
# Disable directory browsing
Options All -Indexes
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^[a-z]{2}/software(.*)$ /software/index.php$2 [L]
</IfModule>
# BEGIN WordPress
# Las directivas (líneas) entre `BEGIN WordPress` y `END WordPress` se generan dinámicamente
# , y solo se deberían modificar mediante filtros de WordPress.
# Cualquier cambio en las directivas que hay entre esos marcadores se sobreescribirán.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
And this is my .htaccess file on the "software" directory:
# Disable directory browsing
Options All -Indexes
# ----------------------------------------------------------------------
# Rewrite engine
# ----------------------------------------------------------------------
# Turning on the rewrite engine is necessary for the following rules and features.
# FollowSymLinks must be enabled for this to work.
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
# If you installed CodeIgniter in a subfolder, you will need to
# change the following line to match the subfolder you need.
# http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase
RewriteBase /
# Redirect Trailing Slashes...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Rewrite "www.example.com -> example.com"
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# Checks to see if the user is attempting to access a valid file,
# such as an image or css document, if this isn't true it sends the
# request to the front controller, index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /software/index.php/$1
# Ensure Authorization header is passed along
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
<IfModule !mod_rewrite.c>
# If we don't have mod_rewrite installed, all 404's
# can be sent to index.php, and everything works as normal.
ErrorDocument 404 index.php
</IfModule>
# Disable server signature start
ServerSignature Off
# Disable server signature end
The error I am getting:
I can access both, the site and the software. The site works well but when I try to access let's say http://example.com/en/software/, I get a 404 error when I access Codeigniter. The error message says: "Controller or its method is not found: App\Controllers\En::software".
This is as if CI is trying to find the controller En (that not exist) and the method software.
Any help will be appreciated.
I have solved the problem after trying for 2 days relentlessly. Here's the steps I actually followed-
First Backup the Codeigniter4 Application by giving the below command as root:
tar --exclude=".git" -czvf zipped_file_name.tar codeigniter4_project_folder/
upload the codeigniter4_project_folder in public_html directory at Shared Hosing and change the following:
Change the base url in app/Config/App.php or .env file in root folder of codeigniter application (here ci4 is the subdomain which will be configured in cpanel later)
app.baseURL = 'http://ci4.yourdomain.com/'
Change the Database Config in app/Config/Database.php or .env file in root folder
database.default.hostname = localhost
database.default.database = your_db_name
database.default.username = your_db_user
database.default.password = your_db_password
database.default.DBDriver = MySQLi
Change .htaccess file in Public Folder
RewriteBase /codeigniter4_project_folder/
Add the Subdomain in Cpanel ci4.yourdomain.com which path will be as follows:
public_html/codeigniter4_project_folder/public
Here public folder will be the last in the path. It is very important.
Hope this may help others struggling with the problem.
In my case I needed to add:
RewriteRule ^(.*)$ index.php?/$1 [L]
in public/.htaccess.

RewriteRule ^ index.php [L] affecting 301 redirect

I have a Drupal 7 website with several 301 redirects, however we've recently noticed an odd issue... When typing the url into your browser, it will not work if you include www.
www.example.com/something redirects to https://www.example.com/index.php
Using https://wheregoes.com/retracer.php the results for the above are:
http://www.example.com/something
301 Redirect -> http://www.example.com/here/something
301 Redirect -> https://www.example.com/index.php
example.com/someting will redirect correctly to https://www.example.com/here/something
Using https://wheregoes.com/retracer.php the results for the above are:
http://example.com/something
301 Redirect -> https://www.example.com/something
301 Redirect -> https://www.example.com/here/something
https://www.example.com/here/something is the expected endpoint.
From digging in my htaccess the issue appears to be with the standard Drupal 7 RewriteRule ^ index.php [L] line; however if I remove this I cannot log into the admin area.
Any thoughts on how this can be resolved? The SSL is only installed on www.example.com, so we need to redirect users to www.example.com and apply the SSL there. example.com has no SSL and unfortunately we cannot control this.
Below is my htaccess file:
#
# 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.
Options +FollowSymLinks
# 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
# 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]
#
# 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
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>
# Add headers to all responses.
<IfModule mod_headers.c>
# Disable content sniffing, since it's an attack vector.
Header always set X-Content-Type-Options nosniff
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
Redirect 301 /examplelink.php /example-link
Redirect 301 /someoldlink.php /new/location
Redirect 301 /something /here/something
</IfModule>
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
The problem you are probably having is that your 301 redirects are happening after your internal routing to the index.php page. Additionally, you're using the Redirect directive, which is mod_alias and not part of mod_rewrite. This means the same request gets processed twice, once by mod_alias and once by mod_rewrite. This is making it so an internal rewrite (to index.php) ends up getting redirected because mod_alias marked the request for a 301.
Remove these lines from the bottom of your .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine on
Redirect 301 /examplelink.php /example-link
Redirect 301 /someoldlink.php /new/location
Redirect 301 /something /here/something
</IfModule>
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Then under the first mod_rewrite block, which looks like this:
# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
Add these lines under RewriteEngine on:
RewriteRule ^examplelink\.php$ /example-link [L,R=301]
RewriteRule ^someoldlink\.php$ /new/location [L,R=301]
RewriteRule ^something$ /here/something [L,R=301]
RewriteCond %{HTTPS} !on
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Redirect top-level domain except for one page in Drupal

I have two top-level domains pointing to my Drupal installation, abc.com and xyz.com.
I'd like to force all pages to use abc.com, EXCEPT for one page (node), which should always use xyz.com.
I've tried a bunch of different .htaccess, none seem to work. This is the closest I've gotten:
# Redirect abc.com/path/to/my/page to xyz.com/path/to/my/page
RewriteCond %{HTTP_HOST} ^(www\.)?abc\.com$ [NC]
RewriteRule ^path/to/my/page$ http://www.xyz.com$1 [R,L,NC]
# Redirect xyz.com to www.abc.com
RewriteCond %{HTTP_HOST} ^(www\.)?xyz\.com$ [NC]
RewriteRule ^ http://www.abc.com%{REQUEST_URI} [R,L]
The above works for the whole site redirect, but when you go to abc.com/path/to/my/page it redirects to the main page, abc.com. I also tried this:
# Redirect abc.com/path/to/my/page to xyz.com/path/to/my/page
RewriteCond %{HTTP_HOST} ^(www\.)?abc\.com$ [NC]
RewriteRule ^path/to/my/page$ http://www.xyz.com/path/to/my/page [R,L,NC]
But that just gave me an error about too many redirects to xyz.com/path/to/my/page.
Any ideas? I'm not sure if my .htaccess code is wrong, or if it has to do with Drupal's clean URL functions, or what.
Here's the full Drupal .htaccess file:
#
# 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)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$">
Order allow,deny
</FilesMatch>
# Don't show directory listings for URLs which map to a directory.
Options -Indexes
# Follow symbolic links in this directory.
Options +FollowSymLinks
# 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_initialize_variables() 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
# Redirect abc.com/path/to/my/page to xyz.com/path/to/my/page
RewriteCond %{HTTP_HOST} ^(www\.)?abc\.com$ [NC]
RewriteRule ^(path/to/my/page)$ http://www.xyz.com/$1 [R=302,L,NC]
# Redirect xyz.com to www.abc.com (except for /path/to/my/page)
RewriteCond %{REQUEST_URI} !^/path/to/my/page$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?xyz\.com$ [NC]
RewriteRule ^ http://www.abc.com%{REQUEST_URI} [R=302,L]
# 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]
# 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} !^www\. [NC]
# RewriteRule ^ http://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://%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 /
#custom redirects (there are lots of these, all are specific paths used on an old site mapped to their respective pages on the new, reorganized site)
RewriteRule ^specific/old/path/$ http://www.abc.com/corresponding/new/path [R=301,L]
#end custom redirects
# 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>
Your code generates a loop. abc.com/path/to/my/page redirect to xyz.com/path/to/my/page, but all xyz urls are redirect to abc.com, so it would redirect back to abc.com/path/to/my/page, over and over again.
# Redirect abc.com/path/to/my/page to xyz.com/path/to/my/page
RewriteCond %{HTTP_HOST} ^(www\.)?abc\.com$ [NC]
RewriteRule ^(path/to/my/page)$ http://www.xyz.com/$1 [R=302,L,NC]
# Redirect xyz.com to www.abc.com (except for /path/to/page)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !^/path/to/my/page$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?xyz\.com$ [NC]
RewriteRule ^ http://www.abc.com%{REQUEST_URI} [R=302,L]
The rule in your first code was incorrect, redirecting abc.com/path/to/my/page to abc.com/ (and that didn't create a loop).
RewriteRule ^path/to/my/page$ http://www.xyz.com$1 [R,L,NC]
This was because $1 reference to the first pair of parentheses, but you didn't have any. Secondly you needed to add a / before it, or it would redirect to xyz.compath/to/my/page
If this "page" is a file, then you might need to do it this way. I used this to keep all Drupal files served from the original server, then forward all non-file traffic to the new site.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/files/.* [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?iradvocates\.org$ [NC]

Resources