Apache htaccess to rewrite up one directory level - apache

I've seen this asked before and people provide answers, but none of them seem to work.
I'm trying to rewrite the URL so any request to /whatever show as /.
I don't want the location of the files to change, just the URL.
For example, if someone types in:
Http://www.mysite.com/whatever ( the files are located at /docroot/whatever )
I want the URL to show http://www.mysite.com/
In my htaccess ( placed in /docroot , not /docroot/whatever ) I'm currently using:
RewriteEngine on
RewriteRule ^whatever/(.+)$ /$1 [L]
What's happening is the URL is staying , but the server is looking for the files /docroot .
That's the opposite of what I need, I need the URL to be , with the server looking for the files in /docroot/whatever .

I think that you have it backwards.
If you want the root URIs to be mapped to DOCROOT/whatever then you need to do an internal redirect in Apache.
If you receive an external request for http://www.mysite.com/whatever and want the client to use the root URI then you need to do an external (301) redirect.
You also need to make sure that you don't end up in an infinite loop.
The following lines will do this for you:
RewriteEngine On
RewriteBase /
RewriteCond %{ENV:REDIRECT_END} !^1
RewriteRule ^whatever/(.+)$ $1 [R=301,L]
RewriteCond %{REQUEST_URI} !^/whatever
RewriteRule ^(.+)$ whatever/$1 [E=END:1,L]
In the second rule, the E=END:1 sets the env variable END to 1, and after the internal redirect, this becomes REDIRECT_END. The first cond stops, say /fred -> /whatever/fred -> (301) /fred -- which will cause the browser to barf.
Also start with 302s and when you've got the rules working switch to 301s -- since the client browser will cache 301s which makes a bugger of debugging these rules.

Try putting this in the htaccess file in your document root:
RewriteEngine On
# change the browser's URL address bar
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /whatever($|\ )
RewriteRule ^whatever / [L,R=301]
# internally rewrite / back to whatever
RewriteRule ^$ /whatever [L]

Related

htaccess rewrite subdomain to some folder if exists else another

I know there are some similar questions about subdomain -> folder htaccess, but I already have a setup that works for me for that simple case.
What I want to add, is "rewrite to projects/subdomain/current/public/ if that current/public exists, else rewrite to projects/subdomain/"
It's because I'm hosting a laravel application, which is in 'public/', and I deployed it using a tool that symlinks 'current/' to its latest release.
My current setup is:
# Redirect everything non-www to /projects/...
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.* [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1 -d
RewriteRule ^(.*) /projects/%1/$1 [L]
Which is something like:
if it doesn't start with www
get the subdomain in a var
if the /projects/subdomain folder exists
rewrite the request to look into that folder
else 404
How would I update this to have an "IF /projects/subdomain/current/public exists, then that, ELSE IF /projects/subdomain exists, then that, ELSE 404"?
Thanks in advance!
Just create another rule before the existing one. For example, following the same pattern as your existing rule:
RewriteEngine on
# Redirect to /projects/<subdomain>/current/public/
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1/current/public -d
RewriteRule (.*) /projects/%1/current/public/$1 [L]
# Redirect everything non-www to /projects/...
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1 -d
RewriteRule (.*) /projects/%1/$1 [L]
I removed the ^ from the RewriteRule pattern (^(.*)) since it was superfluous.
I also changed !^www.* (matches any hostname that simply starts "www") to !^www\. (any hostname that starts "www." - the subdomain only) to avoid potentially spurious matches.
Presumably /var/www/mydomain.com is the document-root, so you could use the DOCUMENT_ROOT server variable instead in the RewriteCond TestString. For example:
RewriteCond %{DOCUMENT_ROOT}/projects/%1/current/public -d
However, by themselves, these directives will result in a rewrite-loop (500 error), so I assume you already have directives in place that prevent this. eg. Another .htaccess file in the directory that you are rewriting to that contains mod_rewrite directives (relevant to the individual projects)? If not then you can either add another condition to each rule that checks against the REDIRECT_STATUS environment variable, or include an exception at the top of the file that prevents further processing after the request is rewritten. For example:
RewriteEngine On
# Stop further processing if the request has already been rewritten
RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule ^ - [L]
: Remaining directives follow...
UPDATE: If you are on Apache 2.4 you can instead simply change the L flag to END to halt all processing by the rewrite engine, to prevent a rewrite loop. The END flag is a relatively recent addition and consequently often gets overlooked - but it's not strictly necessary as there are always other (perhaps more complex) ways to do this.
Why would it loop?
The L flag does not stop all processing. It simply stops the current round of processing and then the rewrite engine effectively starts over, passing the rewritten URL back into the rewrite engine. In the above example, the rewritten URL also matches the same rules, so the URL would be rewritten again, and again, and again, ....
For example (for simplicity, just using your original rule that rewrites to /projects):
Request subdomain.mydomain.com/foo
<doc-root>/projects/subdomain directory exists
URL rewritten to /projects/subdomain/foo
Rewriting process starts over... passing in the rewritten URL, essentially subdomain.mydomain.com/projects/subdomain/foo, back into the rewrite engine.
<doc-root>/projects/subdomain directory exists (as previous)
URL rewritten to /projects/subdomain/projects/subdomain/foo
Rewriting process starts over... etc. etc.
The Rewriting process loops in this fashion until the URL passes through unchanged, unless something else steps in the way... for example, as mentioned above, if you have another .htaccess file located at /projects/subdomain/.htaccess that also contains mod_rewrite directives then control would pass to this .htaccess file after the first round of rewrite processing and prevent further rewrites (since mod_rewrite directives are not inherited by default).

How to rewrite url and redirect with apache mod rewrite?

I have got url:
ipaddress/panelname/main/index.php
How to rebuild it to
ipaddress/center/index.php
?
ofcourse we can see another pages, not only index.php, but this folders in url we can see forever.
I tryed to do this in .htaccess:
RewriteEngine on
RewriteRule ^center/([^/]+)/?$ panelname/main/$1 [L]
RewriteRule ^/panelname(.*)$ /center$1 [QSA,L,R=301,NC]
Redirect 301 ^/panelname(.*)$ /center$1
but i don't see redirect from panelname to center.
but if i type center all works good (but i don't shure, that it works good by my htaccess or by symlink, which i was created in filesystem)
How to rewrite all to another links and howto see redirect from old links to my new? Thank you.
RewriteRule in directory context (which .htaccess is), does never begin with a slash, because the common prefix is stripped from the matched portion first.
Redirect does match strings, not regex'es. The variant that works on a regex is RedirectMatch. Both only work on absolute URL's (the one beginning with a slash).
You either have to do the following:
RewriteRule ^panelname(.*)$ /center$1 [R,L]
or:
RedirectMatch 302 ^/panelname(.*)$ /center$1
Change [R] to [R=301] once you have tested that EVERYTHING works. If you choose the second option, only change 302 to 301 after testing that everything works.
If you want to show /center/index.php to your visitors and keep a redirect from old URL to this URL then you will need one redirect and one rewrite rule (that you already have).
RewriteEngine on
# external redirect from old URL to new one
RewriteCond %{THE_REQUEST} /panelname/main/(\S+) [NC]
RewriteRule ^ /center/%1 [R=302,L]
# internal forward from new URL to actual one
RewriteRule ^center/([^/]+)/?$ panelname/main/$1 [L]

mod_rewrite writing local routes

You see, I want to redirect [R] from http://www.domain.com/dir1/ to http://www.domain.com/.
I also want to accept http://www.domain.com/dir1/([0-9]+) and [L] those requests to dir1.php?query=$1. And to [L] all http://www.domain.com/dir1/(.+) to the root.
So these are my rules:
RewriteRule dir1/([0-9]+) dir1.php?query=$1 [L]
RewriteRule dir1/(.+) $1 [L]
RewriteRule dir1/ . [R,L]
The problem with the last one (and I tried many variations of it) is that redirects to http://www.domain.com/home/domain/www/. I mean, that inserts the local directory. I just want it to redirect to http://www.domain.com/
Thanks,
Use a path with a slash to redirect the client to some absolute path.
RewriteRule dir1/ / [R,L]
The mistake is using . instead of /.
This comes straight from the RewriteRule examples:
Inside per-directory configuration for /somepath
(/physical/path/to/somepath/.htacccess, with RewriteBase /somepath)
for request ``GET /somepath/localpath/pathinfo'':
Given Rule Resulting Substitution
---------------------------------------------- ----------------------------------
[... snip ...]
^localpath(.*) /otherpath$1 /otherpath/pathinfo
In our case /otherpath is just / and we don't use $1 since we don't want the local part.
You can also redirect using absolute URLs. That is useful for redirecting http requests to https or going to other websites. You can redirect to the same server like this:
RewriteRule dir1/ http://%{HTTP_HOST}/ [R,L]
But this is needlessly complicated.

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]

Apache mod_rewrite redirect, keep sub-directory name

I'm wondering if this is possible.
I have a single page site in which I'd like to incorporate a trailing slash with a file name that anchors to a section on that site. I'm trying to avoid using hash or hash-bangs.
For example; www.example.com/recent
Right now, I'm removing any trailing slash, but I get a 404 with /recent because it's expecting a file.
RewriteRule ^(.*)/$ /$1 [R=301,L]
Is it possible to redirect to www.example.com, but still maintain the /recent without the server thinking it's a file so I can read it client-side (php/js)? More so that I can keep using the back and forward buttons.
Thanks for any help!
TBH it is not 100% clear for me what you want. As I understand you want URL www.example.com/recent to be rewritten (internal redirect, when URL remains unchanged in browser) to www.example.com/index.php?page=recent (or something like that).
DirectorySlash Off
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
# remove trailing slash if present
RewriteRule ^(.*)/$ /$1 [R=301,L]
# do not do anything for already existing files
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
# rewrite all non-existing resources to index.php
RewriteRule ^(.+)$ /index.php?page=$1 [L,QSA]
With the above rules (that need to be placed in .htaccess in website root folder) this can be achieved. Request for www.example.com/recent will be rewritten to www.example.com/index.php?page=recent so your single-page server side script knows which URL was requested. The same will be with any other non-existing resource e.g. www.example.com/hello/pink/kitten => www.example.com/index.php?page=hello/pink/kitten.
It may not be necessary to pass originally requested URI as a page parameter as you should be able to access it in PHP via $_SERVER['REQUEST_URI'] anyway.
If I misunderstood you and this is not what you want then you have to clarify your question (update it with more details, make it sound clear).