htaccess to hide subdirectory without changing base root, and with exception of another subdirectory - apache

I have a website https://example.com
which has 2 subdirectories, https://example.com/admin and https://example.com/store.
I want to hide /store from URL so my requests would look like:
https://example.com/shop.php?id=someid
But Also, I want https://example.com/admin/index.php to work.
I found some answers that achieve both 1 and 2 but they change base root so all my css,js, images don't load
So far I have:
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule ^store/(.*) /$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule !^store/ store%{REQUEST_URI} [L]
This achieves 1 but not 2.

RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule ^store/(.*) /$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule !^store/ store%{REQUEST_URI} [L]
In the second rule... exclude the /admin subdirectory (as well as /store) in the RewriteRule pattern. And add a condition to exclude requests that contain a file extension (ie. .css, .js, .png, etc.). For example:
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteRule !^(store|admin)($|/) store%{REQUEST_URI} [L]
Alternatively (although marginally less efficient), exclude any request that already maps to a physical file:
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !^(store|admin)($|/) store%{REQUEST_URI} [L]
This rule assumes you have another .htaccess file in the /store subdirectory that also uses the rewrite engine. (But if that is the case then the first rule isn't actually doing anything.)
Unless you are hosting multiple domains/sites then you don't need the first condition that checks the requested Host.

Related

Redirect url with ids range to another url using htaccess

I try to redirect user from Joomla plugins links that have specific IDs to the default admin page as following:
When user login in Joomla backend, he can reach this page of plugins:
https://www.example.com/administrator/index.php?option=com_plugins
Then if he wants to open a plugin with the id like 422 to edit it, he's to click on this link:
https://www.example.com/administrator/index.php?option=com_plugins&task=plugin.edit&extension_id=422
But instead of opening the plugin, I want the user to get redirected to this page:
https://www.example.com/administrator/index.php
To achieve this, I created a .htaccess in the folder administrator and placed the code at the end. So, I set a range of IDs of plugins that user cannot edit, but gets redirected.
Please find the all content of .htaccess file as following:
# Canonical https/www
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
# Redirect plug id from 350 to 423:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=\b(3[5-8][0-9]|39[0-9]|4[01][0-9]|42[0-3])\b($|&)
RewriteRule ^administrator/index\.php$ https://www.example.com/administrator/index.php? [L,R=302]
# Redirect plug id from 425 to 10864:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=\b(42[5-9]|4[3-9][0-9]|[5-9][0-9]{2}|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|10[0-7][0-9]{2}|108[0-5][0-9]|1086[0-4])\b($|&)
RewriteRule ^administrator/index\.php$ https://www.example.com/administrator/index.php? [L,R=302]
But does not work.
I create a .htaccess in the folder administrator and placed the code at the end.
# Redirect plug id from 350 to 423:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=\b(3[5-8][0-9]|39[0-9]|4[01][0-9]|42[0-3])\b($|&)
RewriteRule ^administrator/index\.php$ https://www.example.com/administrator/index.php? [L,R=302]
If the .htaccess file is inside the /administrator subdirectory then you need to remove administrator/ from the start of the RewriteRule pattern (1st argument), otherwise the rule will never match.
In .htaccess, the RewriteRule pattern matches against a relative URL-path to the directory that contains the .htaccess file.
In other words, it should look like this:
:
RewriteRule ^index\.php$ https://www.example.com/administrator/index.php [QSD,R=302,L]
Also, on Apache 2.4 you can use the QSD (Query String Discard) flag instead of appending an empty query string to remove the original query string.
The preceding conditions that match the query string and plugin id are OK and should match the requested URL. (Although the word boundary \b elements are unnecessary.)
Depending on what other directives you have, this rule should be near the top of the .htaccess file, not "at the end". Since you have used an absolute substitution string it would be more optimal to include these rules before your general canonical redirects (although this does assume you are not implementing HSTS).
You are also missing the RewriteEngine On directive from the rules in question.
So, it should look like this instead:
RewriteEngine On
# Redirect plug id from 350 to 423:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=(3[5-8][0-9]|39[0-9]|4[01][0-9]|42[0-3])($|&)
RewriteRule ^index\.php$ https://www.example.com/administrator/index.php? [QSD,R=302,L]
# Redirect plug id from 425 to 10864:
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{QUERY_STRING} (^|&)option\=com_plugins($|&)
RewriteCond %{QUERY_STRING} (^|&)extension_id=(42[5-9]|4[3-9][0-9]|[5-9][0-9]{2}|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|10[0-7][0-9]{2}|108[0-5][0-9]|1086[0-4])($|&)
RewriteRule ^index\.php$ https://www.example.com/administrator/index.php [QSD,R=302,L]
# Canonical https/www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Additional notes:
I assume you have not implemented HSTS.
I reversed the order of your two canonical redirects to reduce the number of redirects when requesting http://example.com/ (HTTP + non-www). But this does assume #1 above.
Optimised the regex on the canonical redirects... no need to traverse and capture the entire URL-path when using the REQUEST_URI server variable.
Removed the word boundary \b from the regex as this would seem unnecessary here.

.htaccess rewrite in subdirectory

I am currently deploying a number of sites from one hosting account. I have all of the sites in their own folder including the primary domain. The issue I have is when I rewrite the primary domains address with my current code, it includes the subdirectory in it. So currently if I type in http://www.example.com/url it rewrites to https://example.com/folder/url. I just want it to rewrite without the folder.
Any ideas. I know I am complicating this by running my primary domain in a subdirectory, just trying to clean up hosting as best as possible.
In my public_html .htaccess file:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/folder/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /folder/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ folder/index.php [L]
and in public_html/folder .htaccess:
RewriteCond %{HTTP_HOST} ^www.example.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
So currently if I type in http://www.site.whatever/url it rewrites to https://site.whatever/folder/url.
This is a "redirect", not a rewrite.
This is happening because of the use of the REQUEST_URI server variable in your HTTP to HTTPS redirect in your public_html/folder .htaccess file:
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
The REQUEST_URI server variable contains the full URL-path of the request, which, by the time the subdirectory's .htaccess file is called, has been updated to contain /folder.
You need to either:
Move your canonical www to non-www and HTTP to HTTPS redirects to the .htaccess file in the document root. (This would be preferable if you have no other mod_rewrite directives in your public_html/folder .htaccess file.)
OR,
Modify the above directive to use the $1 backreference (to the captured RewriteRule pattern) as you are doing in the preceding www to non-www redirect. For example:
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
(Note that this should ultimately be a 301 redirect, once you have confirmed it works OK.)
And don't forget to escape literal dots in the regex.

Redirects based on file folder structure

We have an website whose url structure is undergoing major changes. As there are lots of pages, I am trying to find a method that redirects based on the requests file structure AND the lack of a file extension.
The webpages are primarily one of two version:
mydomain.com/some-page-title
mydomain.com/multiple/folder/levels/some-other-page
The end goal is:
mydomain.com/some-page-title.htm
mydomain.com/newfolder/some-other-page.htm
I know I can assign a condition to point to a specific redirect for the second example, as in the upper code block. And I can do a simple redirect for the first example. But disappointingly both rewrites effect the urls with multiple/file/folders structure and I end up with two redirects, one with the new folder and one with the original folders.
RewriteCond %{REQUEST_URI} !\.[a-zA-Z0-9]{3,4}
RewriteCond %{DOCUMENT_ROOT}/multiple/$1 -d
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^multiple/folder/levels/(.*)$ /learn/$1.htm [R=301,NC,L]
RewriteCond %{REQUEST_URI} !\.[a-zA-Z0-9]{3,4}
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^(.*)$ $1.htm [R=301,NC,L]
Is there RewriteCond that says CAN NOT contain a specific file structure? Thanks
You may try these rules that won't affect each other:
RewriteEngine On
RewriteRule (?:/|\.[a-z0-9]{3,4})$ - [L,NC]
RewriteRule ^multiple/folder/levels/(.+)$ /learn/$1.htm [R=301,NC,L,NE]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/learn/ [NC]
RewriteRule ^(.+?)/?$ $1.htm [R=301,NE,L]
RewriteCond %{REQUEST_URI} !^/learn/ [NC] will prevent second redirect rule to execute after first redirect.
Make sure to clear browser cache or use a new browser for testing this change.

Mod_Rewrite setting subdomain and directory to GET variable

I programmed a website that I want to be multilingual, the separate languages should be accessable via subdomain, for example en.example.com, de.example.com and so on.
Furthermore I already have a rewrite to set a "directory" as GET variable, that changes example.com/name to example.com/index.php?page=name.
No matter what I tried I find no possibilities to properly combine the two codes I need to use with these respective problems. Each in it's own works, I only need a method to combine both, so that en.example.com/name will be rewritten to example.com/index.php?page=name&lang=en
What I use for directories to GET variables
RewriteRule ^/?(\w*)/?$ index.php?page=$1 [L]
What I found for subdomains to GET variables
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{REQUEST_URI} !index\.php
RewriteCond %{HTTP_HOST} ^(.+?)\.example\.com$
RewriteRule .* /index.php?lang=%1 [L]
You just have to combine your 2 rules
RewriteEngine On
RewriteCond %{HTTP_HOST} ^((?!www\.)[^.]+)\.example\.com$
RewriteCond %{REQUEST_URI} !^/index\.php$ [NC]
RewriteRule ^(.*)$ /index.php?page=$1&lang=%1 [L]

Using .htaccess to redirect by domain, either in the URL or in HTTP_HOST

I am hosting several domains on the same apache server and I want to set them all up so that /home is unique to each domain. (suppose I have 3 domains example.com example1.com and example2.com) I have setup my file structure like this...
/www/htdocs/domain/example
/www/htdocs/domain/example1
/www/htdocs/domain/example2
http://example.com/home/ ==> .../domain/example/
http://example1.com/home/ ==> .../domain/example1/
http://example2.com/home/ ==> .../domain/example2/
So I have an htaccess rule like this
RewriteCond %{HTTP_HOST} ^(.+)\.(.+)$ [NC]
RewriteRule ^home/(.*)$ /domain/%1/$1 [L]
This works perfectly. But I want to extend it to include www.example.com So I add this rule.
RewriteCond %{HTTP_HOST} ^(.+)\.(.+)\.(.+)$ [NC]
RewriteRule ^home/(.*)$ /domain/%2/$1 [L]
That works great, and is generally how I have been building my .htaccess file. It is growing quite unweildy and I need to rethink my approach. So I am trying to concatenate the above two rules into a single block. Here is what I have but it isn't working...
RewriteCond ^home/
RewriteCond %{HTTP_HOST} ^(.+)\.(.+)$ [OR]
RewriteCond %{HTTP_HOST} ^.+\.(.+)\.(.+)$ [OR]
RewriteRule ^home/(.*)$ /domain/%2/$1 [L]
Additionally and separately I would like a rule that would cause the following URL to return error 404.
http://example1.com/domain/example/logo.jpg
I am answering my own question. At least the first part. I am still looking for an answer to the second part.
RewriteCond %{REQUEST_URI} ^/home/
RewriteCond %{HTTP_HOST} ^.+\.(.+)\.(.+)$ [OR]
RewriteCond %{HTTP_HOST} ^(.+)\.(.+)$
RewriteRule ^home/(.*)$ /domain/%1/$1 [L]