htaccess Map One Directory To Another One Level Up - apache

So here’s what I’m trying to accomplish. I have this link:
https://www.mydomain.com/foo/bar/
Now, the directory "foo" actually has a site in it that is up and operational. For the sake of organization I have had to create another site like this:
https://www.mydomain.com/fubar/
So in reality the link https://www.mydomain.com/foo/bar/ isn’t really a directory with anything it. What I would rather like to happen is when people go to https://www.mydomain.com/foo/bar/ that this address doesn’t change in the address bar, but rather on the backend the software actually brings up and uses https://www.mydomain.com/fubar/.
EXAMPLE:
When someone goes to https://www.mydomain.com/foo/bar/sign_up.php they still see this in their address bar, but what they're actually getting is https://www.mydomain.com/fubar/sign_up.php.
What I've tried so far to no avail:
htaccess at https://www.mydomain.com/foo/
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteRule ^bar/(.*) ../fubar/$1 [NC,L]
Also
RewriteCond %{PATH_INFO} ^bar/(.*)$ RewriteRule ^.*$ ../fubar/%1 [L]
htaccess at https://www.mydomain.com/
RewriteRule ^foo/bar/(.*) /fubar/$1 [L]
UPDATE: The directory https://www.mydomain.com/foo/ is actually the root directory for https://www.anotherdomain.com/. So https://www.anotherdomain.com/bar should be bringing up https://www.mydomain.com/fubar/

You can’t do things like have ../ parent directory references like that for rewrite rules:
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteRule ^bar/(.*) ../fubar/$1 [NC,L]
What you need to do is set something like this in the .htaccess of your site’s root on https://www.mydomain.com/:
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteRule ^foo/bar/?(.*)$ fubar/$1 [QSA,NC,L]
The last line basically grabs any URL that has foo/bar in it’s path, the /? makes the trailing slash optional, and the (.*)$ captures the values passed as parameters.
Now, not 100% sure on my addition of QSA (Query String Append) to the rewrite rule flags, but the idea is the query string values get fully passed to the destination when you use. Which I assume you would need, but if you don’t just use this instead:
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteRule ^foo/bar/?(.*)$ fubar/$1 [NC,L]
Also, there is a nice way to debug rules like this without reloading the browser all of the time which can be a headache & cause issues when content is cached. And that is to temporarilly add the R (Rewrite) flag & use curl -I to view response headers directly while debugging.
For example, on my local MAMP (Mac OS X LAMP) setup I see this when I run curl -I to http://localhost:8888/foo/bar/ with the R flag set:
curl -I http://localhost:8888/foo/bar/
HTTP/1.1 302 Found
Date: Mon, 23 Jun 2014 14:11:11 GMT
Server: Apache/2.2.23 (Unix) mod_ssl/2.2.23 OpenSSL/0.9.8y DAV/2 PHP/5.4.10
Location: http://localhost:8888/fubar/
Content-Type: text/html; charset=iso-8859-1
As you can see the Location changes to Location: http://localhost:8888/fubar/ when using the R flag. Which is what you want. Then when you are done tweaking your rules, just remove the R flag & you should be good to go.
EDIT: Since the original poster states this desired behavior in their update to the question, a rewrite rule will never work:
The directory https://www.mydomain.com/foo/ is actually the root
directory for https://www.anotherdomain.com/. So
https://www.anotherdomain.com/bar should be bringing up
https://www.mydomain.com/fubar/.
For a case like this, mod_rewrite is the wrong tool for the job. Use mod_proxy instead. First enable it in Apache like this; example assumes you are on Ubuntu 12.04 but should work on most any Linux Apache install
sudo a2enmod proxy proxy_http
Then set this to enable a reverse proxy on https://www.anotherdomain.com from your path of /bar/ to https://www.mydomain.com/fubar/:
<IfModule mod_proxy.c>
# Proxy specific settings
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
AddDefaultCharset off
Order deny,allow
Allow from all
</Proxy>
ProxyPass /bar/ https://www.mydomain.com/fubar/
ProxyPassReverse /bar/ https://www.mydomain.com/fubar/
</IfModule>

Related

Apache URL redirection

I would like to set up an Apache redirect rule which will accept the following browser URL:
192.168.100.128/test
and transform it into the following:
http://192.168.100.128:9001/forms/frmservlet?config=testjpi
I have had a look at the httpd.conf and have tried to use both the Alais and Rewrite modules but I can't get either to work.
Alias:
Alias /test http://192.168.100.128:9001/forms/frmservlet?config=testjpi
And also Rewrite:
<IfModule rewrite_module>
RewriteEngine on
RewriteRule http://192.168.100.128/test http://192.168.100.128:9001/forms/frmservlet?config=testjpi
RewriteRule /test http://192.168.100.128:9001/forms/frmservlet?config=testjpi
</IfModule>
Any ideas if what I'm doing is even possible, and if so, how do I go about getting it right? I have limited knowledge of Apache so I'm going in a bit blind.
TIA.
Alias won't work on URLs it only works to directories.
Try:
Redirect permanent /test http://192.168.100.128:9001/forms/frmservlet?config=testjpi
for more documentation: http://httpd.apache.org/docs/2.2/mod/mod_alias.html#redirect

Disable Track and Trace in apache

I have Apache 2.2.22 in suse Linux. I want to disable track & trace in Apache and use 1- TraceEnable Off and 2- RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F] .
but of 2 way don't work.
In Apache2 you can just add TraceEnable Off in httpd.conf (end of file)
TraceEnable Off
To check if Trace is On/Off you can use Curl:
curl -v -X TRACE http://www.yourserver.com
You need to put TraceEnable Off in httpd.conf
To disable these methods, add the following lines for each virtual
host in your configuration file :
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]
nessus said)))
For Apache HTTPD 2.4:
Require not method TRACE TRACK
see Require Directive
Unless a module is installed which supports TRACK, then TRACK is not supported by default by Apache, hence the only need to have the directive:
TraceEnable Off
However, for a belt-and-suspenders approach, also add:
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) [NC]
RewriteRule ^.* - [F]
This will disable both TRACE and TRACK.
View Demo Trace Using SSH Command
TRACE is enabled by default in an apache installation. There are two ways to remediate. The first can be used if you are running Apache 1.3.34, 2.0.55, or anything in the 2.2 release. Simply add the TraceEnable directive into your httpd.conf and set the value to Off.
TraceEnable Off
add this line in httpd.conf
The first thing to do is make sure that mod_rewrite is loaded. If mod_rewrite.so is missing from your apache configuration but you have it installed, (and your install location is /usr/local/apache), then add the following statement to your httpd.conf:
LoadModule rewrite_module "/usr/local/apache/modules/mod_rewrite.so"
Then add the following as well to your httpd.conf file:
RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]
Test With Curl Command
curl -v -X TRACE http://localhost
I know there's already a few answers here, but I thought I'd chime in and add some additional options.
Slipstream's approach is certainly the simplest approach here, so if you're seeking a quick and easy fix, there's your pot of gold.
TraceEnable directive
As mentioned by a few people here, in Apache2, you can append the TraceEnable directive to the end your httpd.conf or apache2.conf file:
TraceEnable Off
Rewrite Module
You can also add a rewrite configuration to your VirtualHost to explicitly block TRACK and TRACE requests:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCondition %{REQUEST_METHOD} ^(TRACE|TRACE)
RewriteRule . * - [F]
</IfModule>
With this configuration, Apache catches all TRACK and TRACE requests, and replies with a 403 Forbidden error. None of the original request's content is echoed back.
Rewrite Module (More Restrictive)
But, what I haven't seen anyone else suggest is explicitly passing the methods you want to allow. This is a slighly tighter fix, and is required for PCI compliance:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)
RewriteRule .* - [F]
</IfModule>
This will reject any request which is using a method not specified in the directive. Again, the original request content is not echoed back, and the server responds with a 403 Forbidden error.
Something to keep in mind is that for production systems is that RewriteEngine can be processor intensive. This is generally not much of an issue because the increase would be milliseconds (if not microseconds), but something to be mindful of if you have loads of rewrites.
Note: For the above rewrite configurations, you'll need to uncomment the LoadModule or AddModule (depending on your setup) directives in your Apache config for rewrite_module.
You can also use the mod_allowmethods found in apache 2.3+
<Location "/">
AllowMethods GET POST OPTIONS
</Location>
https://httpd.apache.org/docs/2.4/mod/mod_allowmethods.html

Apache Rewrite: image directory based on HTTP host

My software supports multiple domain names all pointed at the same directory on the server (a different database for each of course). So these domains...
www.example1.com
www.example2.com
www.example3.com
...all point to...
/public_html/
In the image directory...
/public_html/images/
I have directories that exactly match the host names for each website:
/public_html/images/www.example1.com/
/public_html/images/www.example2.com/
/public_html/images/www.example3.com/
I'm trying to get Apache to rewrite requests so that if you view the image directly and look at the address bar you only see the host name once.
So a request for...
http://www.example1.com/images/book.png
...is fetched by Apache at...
/public_html/images/www.example1.com/book.png
One of the things I've tried and have had success with in different circumstances is the following though it doesn't work in this situation:
RewriteRule ^[^/]*/images(.+) images/%{HTTP_HOST}/$1
Try adding the following to the .htaccess file in the root directory of your site (public_html)
RewriteEngine on
RewriteBase /
#prevent looping from internal redirects
RewriteCond %{ENV:REDIRECT_STATUS} !200
#only rewrite gif, jpg or png
RewriteRule ^(images)(/.+\.(gif|jpg|png))$ $1/%{HTTP_HOST}$2 [L,NC]
Your rule
RewriteRule ^[^/]*/images(.+) images/%{HTTP_HOST}/$1
did not work because you have a leading / before images. In .htaccess the leading / is removed, so the rule would never match.
Here's one of the things I've made for my high performance framework (see my bio).
I give you an advanced RewriteRule, I'm pretty sure you'll have enough material to finish:
Create static domains:
static.example1.com
static.example2.com
static.example3.com
Where all your images will be.
From now on, no more:
www.example1.com/images/www.example1.com/picture.jpg
www.example2.com/images/www.example2.com/picture.jpg
www.example3.com/images/www.example3.com/picture.jpg
but
static.example1.com/picture.jpg
static.example2.com/picture.jpg
static.example3.com/picture.jpg
Nice URLs uh?
Now create a vhost with all your static files:
<VirtualHost *>
ServerName static.example1.com
ServerAlias static.example2.com static.example3.com
</VirtualHost>
Set your document root to the base without the vhost name, so in your case:
DocumentRoot "/public_html/images"
And add this RewriteRule
RewriteCond %{HTTP_HOST} ^static\.([a-zA-Z0-9\-]+)\.com$
# Change the path, and add the request:
RewriteRule (.*) %{DOCUMENT_ROOT}/static.%1.com$1 [QSA,L]
So all in all:
<VirtualHost *>
ServerName static.example1.com
ServerAlias static.example2.com static.example3.com
RewriteCond %{HTTP_HOST} ^static\.([a-zA-Z0-9\-]+)\.com$
# Change the path, and add the request:
RewriteRule (.*) %{DOCUMENT_ROOT}/static.%1.com$1 [QSA,L]
</VirtualHost>
Ok that doesn't aswer exactly to your question so here's the short answer, but I don't like it because it doesn't help you to do a very (very) good job:
RewriteCond %{HTTP_HOST} ^www\.(example1|example2|example3)\.com$
# Change the path:
RewriteRule (.*)(\.(css|js|txt|htc|pdf|jpg|jpeg|gif|png|ico))$ %{DOCUMENT_ROOT}/www.%1.com$1$2 [QSA,L]
And if that's not enough:
Two hints:
If you're not in a hosted environment (= if it's your own server and you can modify the virtual hosts, not only the .htaccess files), try to use the RewriteLog directive: it helps you to track down such problems:
# Trace:
# (!) file gets big quickly, remove in prod environments:
RewriteLog "/web/logs/mywebsite.rewrite.log"
RewriteLogLevel 9
RewriteEngine On
My favorite tool to check for regexp:
http://www.quanetic.com/Regex (don't forget to choose ereg(POSIX) instead of preg(PCRE)!)
John,
I've just posted a separate Q on some of the challenges that you face. I would welcome your comments, but back to your challenge: one trick that you can use an environment variable to store your (preferably validated) host, for example:
RewriteCond %{HTTP_HOST} ^www\.(host1|host2|host3\.com
RewriteRule ^ - [E=HOST:%1]
You might also want to add [S] flags to implement if/then/else logic in your rules. And you can also use the HOST variable in following rule or condition strings (not regexp patterns) as %{ENV:HOST}.
You also need to take a clear look at a full phpinfo() report to understand whether you hosting service is using an mod_php or a mod_suPHP, ... interface and host it supports DNS multihoming. E.g my supplier sets up %{ENV:DOCUMENT_ROOT_REAL} which I need to use instead of %{DOCUMENT_ROOT} when examining file-space.
All of your URI "arrivals" at DOCROOT/ are of the form http://www.exampleX.com/images/book.png so if your .htaccess location is your DOCROOT then your base is /. So assuming the above ENV setting, these should work
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.(host1|host2|host3)\.com
RewriteRule ^ - [E=HOST:%1]
RewriteCond %{ENV:HOST}==%{REQUEST_URI} !^(.*?)==/image/\1
RewriteRule ^image/(.*) image/%{ENV:HOST}/$1 [L,NS]
The cond is a botch to stop the rewrite rule looping.
Generalised version
The above solution is an already generalised solution as you as for. Just replace the RewriteCond regexp with whatever pattern matches your own naming convention, and I agree that if it is (.*) then you may as well drop the first rule and replace %{ENV:HOST} by %{HTTP_HOST}. You need the RewriteCond guard to prevent the loop which results in a 500.

How Can I Have A Conditional .htaccess Block?

This is an Apache question you've probably come across before. I want to have one source package that I can deploy to my workstation, my staging server, and my production server, but for it to load different .htaccess settings based on what the URL was.
Note that I was using a kludge with an IfModule call, but that won't work with our new production server because it shares all the same modules as my staging server.
Note I need to bundle SetEnv with these rewrites. Currently if you use RewriteCond, it only ties to the following RewriteRule, but not the SetEnv underneath.
Instead of using SetEnv, use the environment variable setting capabilities of RewriteRule itself:
RewriteCond %{HTTP_HOST} =foo.com
RewriteRule ^ - [E=VARNAME:foo]
RewriteCond %{HTTP_HOST} =bar.com
RewriteRule ^ - [E=VARNAME:bar]
Although I prefer doing this sort of thing by passing flags to the httpd process at startup and looking for them using IfDefine blocks.
<IfDefine FOO>
SetEnv VARNAME foo
</IfDefine>
<IfDefine BAR>
SetEnv VARNAME bar
</IfDefine>
On Ubuntu Linux, the IfDefine's variable is set in
/etc/apache2/envvars
and is called APACHE_ARGUMENTS. So, at the bottom of that file I had to add:
export APACHE_ARGUMENTS="-D dev"
...and then bounce the server with:
/etc/init.d/apache2 stop
/etc/init.d/apache2 start
On other systems:
However, there's a Debian article on this topic that discusses this here. In that example, the file to edit is /etc/default/apache2 and the variable is called APACHE_DEFINES.
Likewise, on some systems it is a variable named OPTIONS that is set in /etc/sysconfig/httpd.
So, what you really need to do is look for the start section in your apache2ctl file. So, begin by doing a whereis apache2ctl to find where that script is, cat it out and find the start section with the apache2 directive in it, and see if the variable it passes is OPTIONS, APACHE_ARGUMENTS, APACHE_DEFINES, or something else. Then, see which file you need to edit by experimentation with either /etc/sysconfig/httpd, /etc/default/apache2, or /etc/apache2/envvars.
I tried the IfDefine method and it didn't work, even though the defined variable i'd passed into the Apache startup was definitely showing up in phpinfo() on the APACHE_ARGUMENTS line.
I tried another method and it worked perfectly. In your .htaccess file you need something like:
# Is the domain local (i wanted to check two names)?
<If "%{SERVER_NAME} != 'localhost' && %{SERVER_NAME} != 'myproject.localhost'">
# I wanted to password protect the production server only
AuthType Basic
AuthName "Restricted area"
AuthUserFile /app/.htpasswd
require valid-user
</If>
I'm using Apache 2.4. Might not work for earlier versions.
Here is a simple example that should be enough for you to change it to meet your requirements:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^localhost
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule (.*) http://www.%{HTTP_HOST}/$1 [R=301,L]
</IfModule>

How can I implement a global RewriteCond / RewriteRule in Apache that applies to all virtual hosts?

The title pretty much says it all. :-) I have lots of virtual hosts and I want to put a single rewriting block at the top of the httpd.conf file that rewrites URLs no matter which virtual host the request might be directed to. How the heck do I do this?
I found this but my question is the same: how can I do this without resorting to .htaccess files and performing some other action for each virtual host?
OMGTIA!
Specify RewriteOptions InheritDown in the parent scope (such as httpd.conf) to get your rules applied in child Virtual Hosts without modifing them.
This will only work on Virtual Hosts where the RewriteEngine directive is set to on:
Note that rewrite configurations are not inherited by virtual hosts. This means that you need to have a RewriteEngine on directive for each virtual host in which you wish to use rewrite rules.
(source)
Apache supports this since 2.4.8 (not available at the time of the original question).
From documentation for RewriteOptions:
InheritDown
If this option is enabled, all child configurations will inherit the configuration of the current configuration. It is equivalent to specifying RewriteOptions Inherit in all child configurations. See the Inherit option for more details on how the parent-child relationships are handled.
Available in Apache HTTP Server 2.4.8 and later.
InheritDownBefore
Like InheritDown above, but the rules from the current scope are applied before rules specified in any child's scope.
Available in Apache HTTP Server 2.4.8 and later.
IgnoreInherit
This option forces the current and child configurations to ignore all rules that would be inherited from a parent specifying InheritDown or InheritDownBefore.
Available in Apache HTTP Server 2.4.8 and later.
(http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteoptions)
By default, mod_rewrite configuration settings from the main server context are not inherited by virtual hosts. To make the main server settings apply to virtual hosts, you must place the following directives in each <VirtualHost> section:
RewriteEngine On
RewriteOptions Inherit
click http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html to find more information
Looks like the simplest possible solution is to add
RewriteOptions inherit
to each VirtualHost directive. This is at least a lot simpler than messing with .htaccess files. Apache is pretty clear on the fact that
by default, rewrite configurations are
not inherited. This means that you
need to have a RewriteEngine on
directive for each virtual host in
which you wish to use it.
(http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html)
and apparently the way to change the default is via RewriteOptions in the child (vhost or director), so you have to do something in each child.
I've never tested it, so it might not work, but I would try adding an include directive in all of the virtual host blocks to a single file. You would have to change each virtual host configuration block once, but after that, you should have a central place from which to make changes. YMMV.
If you're only trying to rewrite something in the domain part of the name, e.g. to fix a common misspelling, you don't even need the 'inherit' option. I setup a no-name virtual host to catch all invalid host names and respell them correctly before redirecting them.
Since this uses redirects, the appropriate virtual host will be found after the rewrites have been applied.
Options +Indexes +FollowSymLinks
RewriteEngine on
# If it begins with only domain.com, prepend www and send to www.domain.com
RewriteCond %{HTTP_HOST} ^domain [NC]
RewriteRule ^(.*) http://www.domain.com$1 [L,R=301]
# Correct misspelling in the domain name, applies to any VirtualHost in the domain
# Requires a subdomain, i.e. (serviceXXX.)domain.com, or the prepended www. from above
RewriteCond %{HTTP_HOST} ^([^.]+\.)dommmmmain\.com\.?(:[0-9]*)?$ [NC]
RewriteRule ^(.*) %{HTTP_HOST}$1 [C]
RewriteRule ^([^.]+\.)?domain.com(.*) http://$1domain.com$2 [L,R=301]
# No-name virtual host to catch all invalid hostnames and mod_rewrite and redirect them
<VirtualHost *>
RewriteEngine on
RewriteOptions inherit
</VirtualHost>
You may want to use InheritDownBefore to avoid having to add more junk to your vhosts.
An example of a global letsencrypt alias:
# letsencrypt
<IfModule alias_module>
Alias /.well-known/ /var/www/html/.well-known/
</IfModule>
<IfModule mod_rewrite.c>
# prevent vhost rewrites from killing the alias
RewriteEngine On
RewriteOptions InheritDownBefore
RewriteCond %{REQUEST_URI} ^/\.well\-known
RewriteRule . - [L,PT]
</IfModule>
Then you can do this in each of your vhosts, with no other directives:
<VirtualHost *:80>
....
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^/.* /index.php [L,PT]
</IfModule>
</VirtualHost>
Thanks to everyone to answered above. It helped me find my answer.
Question has been answered already, I just wanted to add an example in case you are using Google Compute Engine. It says it requires Apache HTTP Server 2.4.8 BUT it works with Apache/2.4.25 (Debian). Even when I try to upgrade, I cannot go past Apache/2.4.25. It says this version is the latest version.
Here's an example of how to implement.
RewriteOptions InheritDown
RewriteCond %{HTTP_HOST} ^www\. [NC,OR]
RewriteCond %{HTTP_HOST} !\.co$ [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)\.[^.]+$ [NC]
RewriteRule ^ https://%1.co%{REQUEST_URI} [L,NE,R=301]
<VirtualHost *:80>
RewriteEngine On
ServerAlias *.*
</VirtualHost>
ALSO OF NOTE (For Testing):
When you are testing your rewrite engine. It is really easy to get confused about if it is working or not because of cache and cookies. If you got it to work once on a browser, it will continue to work even if you delete the rewrite code. Testing rewrite is really annoying sometimes. You might think it works but then it stops or starts.
Best way to test rewrite code is to open an incognito tab in your browser, clear or cookies and cache. Open developer mode just in case. DO NOT JUST REFRESH. You need to click into the URL and refresh. Or open new tab. Or copy/paste URL into new window. If you use same window with refresh, it might be just redoing results from the past instead of renewing the new code.
I've always used a "catch-all" VHost for directives I wanted across the board, like......
Listen 80
NameVirtualHost *:80
<VirtualHost *:80>
ErrorLog "/var/log/apache2/error_log"
</VirtualHost>
<VirtualHost *:80>
ServerName alloftherestoftheVHosts.com
DocumentRoot "/ServiceData/.........
............
And it's always seemed to work... error logs were getting combined properly, etc...... but it IS possible that this was the result of an earlier / conflicting / like-minded directive.
Personal note.. Whoever dreamed up the Apache configuration schema and syntax was a dingbat, or a group of dingbats, who spent too much time in their cave.... The whole thing should be exorcised and XMLized, or something! Although they are both wildly different... the Hello-Kitty setup process of Cherokee.. to the viciously succinct NGinx config.... are both so much more logical..