Url rewrite showing the real directory - apache

I have read almost everything and in theory this should be correct. However the redirect shows the real directory in the url when I look for subdirectories.
RewriteCond %{HTTP_HOST} ^myhost\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/tool [NC]
RewriteRule (.*) /tool/$1 [L]
If I go to http://myhost.com there is no problem, but when I try to go to http://myhost.com/subfolder/ this redirects to http://myhost.com/tool/subfolder/ instead of letting me see the content at the requested url http://myhost.com/subfolder/
Btw the content is loaded my problem is just the url bar.
In other words it works on the base folder but fails when I add something below.
http://myhost.com OK
http://myhost.com/anything OK it redirects to http://myhost.com/tool/anything (I don't want to see /tool/)
http://myhost.com/anything/ (trailing slash) KO! it redirects to
http://myhost.com/tool/http:/myhost.com/var/www/html/anything

Related

htaccess URL redirect excluding a couple of urls

So from our old server we want almost all URLs to be redirected to new server except a few.
So I tried the following .htaccess rule:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !\.(css|js|Js|png|jpg|gif)$ [NC]
RewriteCond %{REQUEST_URI} !^/admin/
RewriteCond %{REQUEST_URI} !^/albums/
RewriteCond %{REQUEST_URI} !^/songs/
RewriteCond %{REQUEST_URI} !^/update_list.php
RewriteRule (.*) http://www.newserver.com/$1 [R=301,L]
The idea is that other than the admin, albums, songs URLs and update_list php file and the asset files (css, js, images) everything else should redirect to new server.
This works "almost" fine - admin URL correctly stays in old server, as does update_list. All other legacy urls redirect to the new server.
However my problem is that albums and songs URLs also keep redirecting to new server.
I am not sure why. Just so you are aware the songs url is of the structure
oldserver.com/songs/album-id/song-name
And the albums URL has session values set based on query params when loading.
Can anyone help me? I have been sitting with this for over 4 hours now :( And I have tried almost all kinds of rule syntaxes I read online. Any advice/pointers is greatly appreciated.
It looks like your albums and songs URLs would need to be internally rewritten to a "front-controller" (eg. index.php or something) in order to be successfully routed through your application.
If that's the case then these URLs are likely being redirected after the request has been rewritten to the front-controller, effectively bypassing the conditions in your current rule. (Although you should also be seeing a "malformed" redirect to the "front-controller", the original URL will be lost. Is that the case?)
You can ensure you only redirect direct requests from the client (and not "rewritten" requests) by checking against the REDIRECT_STATUS environment variable, which is empty on the initial request and set to "200" (as in 200 OK HTTP status) after the first successful rewrite.
For example:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif)$ [NC]
RewriteCond %{REQUEST_URI} !^/admin/
RewriteCond %{REQUEST_URI} !^/albums/
RewriteCond %{REQUEST_URI} !^/songs/
RewriteCond %{REQUEST_URI} !^/update_list\.php
RewriteRule (.*) http://www.newserver.com/$1 [R=301,L]
You can use REQUEST_URI, rather than REQUEST_FILENAME to check for the file extension. And there's no need to check for js and Js, since the comparison is not case-sensitive (ie. NC - nocase)
You will need to clear your browser cache before testing, since the erroneous 301 (permanent) redirect will have been cached by the browser.
Always test first with 302 (temporary) redirects to avoid potential caching issues.

Apache mod_rewrite - unwanted redirect instead of rewrite

I have an issue with mod_rewrite and I can't seem to solve it. I stripped the example down to the bare bones and I don't understand why a specific rule forces my browser to redirect instead of rewrite:
RewriteEngine on
#if request is for a physical-file OR for one of the language paths - skip (return as-is)
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{REQUEST_URI} ^/de [OR]
RewriteCond %{REQUEST_URI} ^/en-US
RewriteRule ^ - [L]
#otherwise: rewrite to en-US folder
RewriteRule ^(.*)$ /en-US/$1 [NC,L,QSA]
I read the documentation very carefully and it seems like this should actually rewrite every call, so https://example.com/fuBar.html should actually retrieve the file /en-US/fuBar.html from my server - the users browser shouldn't know about it.
What's really happening is that for some reason the browser is redirected to https://example.com/en-US/fuBar.html. While this does display the correct content, it's just not what I want or what I thought this RewriteRule should do. What am I doing wrong?
*add - the .htaccess of the subfolders de and en-US:
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
There's nothing in the code you've posted that would trigger an external "redirect".
Make sure you have cleared your browser (and any intermediary) cache(s) to ensure you are not seeing an earlier/erroneous 301 (permanent) redirect. (301 redirects are cached persistently by the browser.)
Check the "network traffic" in the browser's developer tools to see the precise nature of this redirect to see what it redirects from/to, and well as the 3xx HTTP status code of the redirect (if indeed this is an external redirect).
It would seem the front-end (JavaScript/Angular) is manipulating the URL in the address bar (there is no redirect). From comments:
Actually there was no redirect happening at all! Rather since I set <base href="/en-US"> somehow my frontend (Angular) seems to have outsmarted me, manipulating the address without me realizing it. Turns out I don't even need to change the base href, I just need the rewrites.

Redirect all pages in direcory except one subdirectory .htaccess

I want to have one URL still being served from a subdirectory on the old domain but redirect all others from the parent directory to the new domain.
www.olddomain.co.uk/directorya/directoryb -> no redirect
www.olddomain.co.uk/directorya -> www.newdomain.co.uk/directorya
This works if the URL is typed with a trailing slash
RewriteCond %{REQUEST_URI} !^/directorya\/directoryb [NC]
RewriteRule ^(.*)$ http://www.newdomain.co.uk/ [L,R=301]
So http://www.olddomain.co.uk/directorya/directoryb/ works but http://www.olddomain.co.uk/directorya/directoryb fails.
Tried added $ at the end and other connotations and tried
RewriteEngine on
RewriteRule !^myspecialdirectory/mynextdirectory($|/) http://newdomain.example%{REQUEST_URI} [L,R=301]
from Redirect entire site except one directory to a new site - apache .htaccess
What do I need to do to get http://www.olddomain.co.uk/directorya/directoryb/ or http://www.olddomain.co.uk/directorya/directoryb to redirect? (while all other http://www.olddomain.co.uk pages go to http://www.newdomain.co.uk
For reasons I don't understand http://www.olddomain.co.uk/directorya/directoryb goes to Google and doesn't redirect
Try using THE_REQUEST variable and make sure this this very first rule:
RewriteCond %{THE_REQUEST} !\s+/+directorya/directoryb [NC]
RewriteRule ^ http://www.newdomain.co.uk/? [L,R=301]
Test it after clearing your browser cache.

htaccess Silent Redirect to Subdirectory: Subdirectory showing when no trailing '/'

I have dug high and low around Google and StackOverflow to try and figure out my problem, trying countless solutions but nothing has completely worked.
I'm looking to move the web root of the main domain on my server to a sub-directory. What I have currently for a server path to my web root:
/home/user/public_html/MyWebFilesHere
What I'm looking to have:
/home/user/public_html/subdir/MyWebfilesHere
When I browse to mydomain.com, there should be no visible difference though (i.e. "subdir" not visible after redirect).
Unfortunately, I am restricted to doing this purely with a .htaccess file since I'm on shared hosting and don't have access to Apache config files and such. :(
What I currently have in my .htaccess in public_html is:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$
RewriteCond %{REQUEST_URI} !^/subdir/
RewriteRule ^(.*)$ /subdir/$1 [L]
This successfully redirects all queries to the sub-directory, however there's a really weird issue. If I go to
mydomain.com/Contact/
it works great, redirecting the query to the path /subdir/Contact/ but leaving the address bar alone. If I go to
mydomain.com/Contact
(Note the lack of a trailing '/') though, what shows in the address bar is
mydomain.com/subdir/Contact/
which isn't what I want since "subdir" is showing.
For a working example on my actual site, try browsing to
colincwilliams.com/Contact/
compared with
colincwilliams.com/Contact
Do you guys have any ideas on how to make this work silently both with and without a trailing slash?
This is probably happening because mod_dir (the module that automatically redirects the browser if a request for a directory is missing a trailing slash to the same thing with a trailing slash. See the DirectorySlash directive in mod_dir
What's happening is:
You request: mydomain.com/Contact
mod_dir doesn't touch this since /Contact isn't a directory
/Contact gets rewritten to /subdir/Contact and internally redirected
mod_dir sees that /subdir/Contact is a directory and missing the trailing slash so it redirects the browser to mydomain.com/subdir/Contact/
So now, your browser's location bar has the /subdir/ in it.
You can add DirectorySlash off in your .htaccess to turn off mod_dir from redirecting. But if you want directories to have trailing slashes, you can add a separate condition for it. Based on what you already have, we can expand it to this:
RewriteEngine on
# Has a trailing slash, don't append one when rewriting
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$
RewriteCond %{REQUEST_URI} !^/subdir/
RewriteCond %{THE_REQUEST} ./\ HTTP/1\.[01]$ [OR]
# OR if it's a file that ends with one of these extensions
RewriteCond %{REQUEST_URI} \.(php|html?|jpg|gif|css)$
RewriteRule ^(.*)$ /subdir/$1 [L]
# Missing trailing slash, append one
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$
RewriteCond %{REQUEST_URI} !^/subdir/
RewriteCond %{THE_REQUEST} [^/]\ HTTP/1\.[01]$
# But only if it's not a file that ends with one of these extensions
RewriteCond %{REQUEST_URI} !\.(php|html?|jpg|gif|css)$
RewriteRule ^(.*)$ /subdir/$1/ [L]
Note: I changed !^/mydomain/ to !^/subdir/, figured it was a typo because without it, mod_rewrite would loop internally indefinitely (foo -> /subdir/foo -> /subdir/subdir/foo -> /subdir/subdir/subdir/foo, etc). If I got that wrong, you can change it back.
Edit: See my additions of RewriteCond's matching against \.(php|html?|jpg|gif|css). These are the file extensions that get passed through without getting trailing slashes added. You can add/remove to suit your needs.
Jon Lin's answer was very helpful in determining what was causing the problem in my very similar setup. For completeness I will include the relevant information from his answer:
This is probably happening because mod_dir (the module that automatically redirects the browser if a request for a directory is missing a trailing slash to the same thing with a trailing slash. See the DirectorySlash directive in mod_dir
What's happening is:
You request: mydomain.com/Contact
mod_dir doesn't touch this since /Contact isn't a directory
/Contact gets rewritten to /subdir/Contact and internally redirected
mod_dir sees that /subdir/Contact is a directory and missing the trailing slash so it redirects the browser to mydomain.com/subdir/Contact/
So now, your browser's location bar has the /subdir/ in it.
In my case, I had requests being redirected to /subdir with a few exceptions and didn't want to have to re-enable DirectorySlash for each of those exceptions.
By allowing RewriteEngine to continue after the initial redirect to /subdir, it's possible to mimic what mod_dir would be doing while also taking /subdir into account, before mod_dir gets to see it.
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/exception1|exception2|...
RewriteRule ^(.*)$ /subdir/$1
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^subdir/(.*) $1/ [R,L]
Note: You may need to be careful about allowing RewriteEngine to continue if there are further rules. Not matching the second rule will continue on to any further rules which may produce a different result.
This can be avoided by using a third rule to stop RewriteEngine processing if the redirect into /subdir has happened:
RewriteCond %{REQUEST_URI} ^subdir
RewriteRule .* - [L]

htaccess, MySQL DB and non-existent files

I have content in a MySQL DB that I'd like to display on my home page, depending on the URL the user came from. I don't want mod_rewrite to change my URL, but rather, to do the following:
Keep URL (ie mysite.com/demolink2)
Check is the page exists, and if not, redirect to index.php, passing the "demolink2" variable (essentially the end of the URL string after last trailing slash)
On the index.php side I'll be able to then serve up the content, but again, I don't want the user to see the URL changed to mysite.com/index.php?id=demolink2, but rather, have the mysite.com/index.php page STAY as mysite.com/demolink2 until they click a URL within the site that leads to a real page.
Here's my current .htaccess which accomplishes the first bit; i.e. it will see if the page already exists, and if not, direct user to index, however I've done that with a rewrite.
Any help/comments would be appreciated.
htaccess file:
Options +FollowSymLinks
RewriteEngine on
RewriteBase /
RewriteRule ^$ /index.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.php [L]
Just change the last line to
RewriteRule (.*) /index.php?id=$1 [QSA,L]
The URL in browser will remain the same as it is rewrite (internal redirect) and not proper 3xx code redirect.
If mysite.com/demolink2 is requested, your script will see it as /index.php?id=demolink2;
If it will be mysite.com/hello/kitten, then script will see index.php?id=hello/kitten;
QSA flag is added to preserve existing query string.