How to set up proxy in .htaccess - apache

The Apache documentation states that RewriteRule and the should be put in the server configuration, but they can be put in htaccess because of shared hosting situations. I am in such a situation.
I am trying to set up a transparent proxy:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/foo [OR]
RewriteCond %{REQUEST_URI} ^/bar
RewriteRule ^(.*)$ http://example.com/$1 [P]
This is working fine...except for redirects (like if /foo redirects to /bar). Redirects go back to example.com, not my server.
I understand the the ProxyPassReverse directive will solve this, but I get an "Internal Server Error" page when I add this to .htaccess
Unlike the Rewrite directives, ProxyPassReverse will not work in htaccess.
How do I set up a transparent proxy in shared hosting situation, or is this not possible?
(This seems reasonable, since Rewrite already gets 80% of the way there, and having a transparent proxy in one htaccess would not interfere with having it in another.)

Unfortunately, I'm fairly sure what you want to do isn't possible: I'm trying to do the exact same thing! From my research, I'm fairly confident it's not possible.
Put simply, you need to use ProxyPassReverse, which is only available at a VirtualHost level (or similar); not a htaccess level.
Edit: the only way I have achieved this is by also configuring the responding server/application to know it's behind a proxy, and serving pages appropriately. That is, I use .htaccess to redirect to another server as follows:
RewriteEngine on
RewriteRule (.*) http://localhost:8080/$1 [P,L]
Then on the application server -- in this case, a JIRA installation -- I configured the Java Tomcat/Catalina appropriately to serve pages with the proxied information:
proxyName="my.public.address.com"
proxyPort="80"
However, that's not completely transparent; the app server needs to serve pages in a proxied manner. It might be of some use, though.

I managed to gather a few sources to figure out how to do this. I use a shared hosting provider, so I don't have access to server configuration (httpd.conf). I can only use .htaccess to accomplish the proxying. This example is for a WordPress site where I want most of the content served by origin.example.com, but will have some pages served locally, sort of like an overlay. You could go the other way and ONLY proxy specific subdirectories using different RewriteCond rules.
Things to know:
You can’t use ProxyPass or ProxyPassReverse in .htaccess, so we have to use other methods to mimic what they do.
You can’t make proxy calls over HTTPS if SSLProxyEngine is not turned on by your provider, so you will lose some security if you have concerns about MITM attacks. If the origin server is internal, this may not be an issue. You could also use .htaccess on the origin server to enforce HTTPS from everywhere except the proxy server.
You need to rewrite headers
You need to rewrite the HTML that comes back from the origin server, and that needs to be done on the origin server. You can restrict it to certain IPs (i.e. the IP of the proxy) so it won’t break if you access it elsewhere.
What I want:
I want calls to proxy.example.com to serve content origin.example.com. In my case, I want to map everything with a few exceptions. If you only want to map a portion of your site, adjust your rules accordingly.
How to do it:
Configure the .htaccess file on proxy.example.com to proxy all URIs to origin.example.com. I want to be able to log into proxy.example.com, so I don’t rewrite /wp-admin or /wp-login.php. In my case, I have a /programs/ section that I want served by the proxy server itself (also a WordPress instance). Prevent looping by checking REDIRECT_STATUS.
# I force everything coming into proxy.example.com to be HTTPS <IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] </IfModule> <IfModule mod_proxy.c>
# Redirect access for / (or any index) to the origin. NOTE target is http:// without SSLProxyEngine
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(index\.(php|html|cgi))?$ http://origin.example.com/ [P]
# Do NOT redirect these patterns
RewriteCond %{REQUEST_URI} !^/wp-admin/
RewriteCond %{REQUEST_URI} !^/wp-login.php
RewriteCond %{REQUEST_URI} !^/programs/
# Redirect everything else. NOTE target is http:// without SSLProxyEngine
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+)$ "http://origin.example.com/$1" [P]
# Mimic ProxyPassReverse. Fix the headers. Force to be https.
Header edit Location ^https?://origin\.example\.com/(.*)$ https://proxy.example.com/$1
Header edit* Link https?://origin\.example\.com/ https://proxy.example.com/ </IfModule>
ONLY for the IP of the PROXY server, rewrite any references in the HTML itself. This example is for a WordPress site.
Stolen from WordPress filter to modify final html output
2a) Add a Must Use plugin to add a ‘final_output’ hook. Add a file in wp-content/mu-plugins/buffer.php:
<?php
/** * Output Buffering * * Buffers the entire WP process, capturing
the final output for manipulation. */
ob_start();
add_action('shutdown', function() {
$final = '';
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
// that buffer's output into the final output.
$levels = ob_get_level();
for ($i = 0; $i < $levels; $i++) {
$final .= ob_get_clean();
}
// Apply any filters to the final output
echo apply_filters('final_output', $final); }, 0); ?>
2b) Add the following PHP to the wp-content/themes/yourthemenamehere/functions.php. It uses the ‘final_output’ hook above. (PHP 5.3 or later required for use of anonymous function.)
add_filter('final_output', function($output) {
// IP of the proxy server
$WWW_IP = “4.4.4.4”;
//$WWW_IP = “4.4.2.2”; // My workstation, for testing purpose only
if ($_SERVER['REMOTE_ADDR'] == $WWW_IP) {
// Force HTTPS when rewriting
$output = str_replace('http://origin.example.com', 'https://proxy.example.com’, $output);
// Catch anything that wasn’t a URL
return str_replace(‘origin.example.com, 'proxy.example.com', $output);
}
return $output;
});
If all goes well, you should now see the content from origin.example.com served from proxy.example.com.
I'm still testing this, so if you find errors or omissions, please add a comment.

Related

Remove trailing forward slash and question mark

Quick summary, I have implemented the following .htaccess file which successfully redirects http:// and any www. searches to https://
My issue - After redirectrule has been applied it then leaves a trailing //? so for example: http://www.example.com becomes https://example.com//?
Another example of another page: http://www.example.com/test becomes https://example.com//test?
So to clarify further. I am happy with the http to https redirect however I only need one final trailing slash and nothing else to my URL, any help and advice would be great as I cannot for the life of me find any other example like this.
Required - http://www.example.com to become https://example.com/
Here is my .htaccess code...
RewriteEngine On
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^(.*)$ https://settlerslodge.co.uk/$1 [R,L]
Use below rewrite rule and test.
RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(.+)/?$ https://%{HTTP_HOST}/$1 [L,R]
This would be a clean setup:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.+)/?$ https://example.com/$1 [R=301,QSD,END]
It is a good idea to start out with a 302 temporary redirection and only change that to a 301 permanent redirection later, once you are certain everything is correctly set up. That prevents caching issues while trying things out...
In case you receive an internal server error (http status 500) using the rule above then chances are that you operate a very old version of the apache http server. You will see a definite hint to an unsupported [END] flag in your http servers error log file in that case. You can either try to upgrade or use the older [L] flag, it probably will work the same in this situation, though that depends a bit on your setup.
This implementation will work likewise in the http servers host configuration or inside a distributed configuration file (".htaccess" file). Obviously the rewriting module needs to be loaded inside the http server and enabled in the http host. In case you use a distributed configuration file you need to take care that it's interpretation is enabled at all in the host configuration and that it is located in the host's DOCUMENT_ROOT folder.
And a general remark: you should always prefer to place such rules in the http servers host configuration instead of using distributed configuration files (".htaccess"). Those distributed configuration files add complexity, are often a cause of unexpected behavior, hard to debug and they really slow down the http server. They are only provided as a last option for situations where you do not have access to the real http servers host configuration (read: really cheap service providers) or for applications insisting on writing their own rules (which is an obvious security nightmare).

.htaccess Mask Domain and hide url

I am trying to get a subdomain to show to contents of another domain, with the ability to go to any area of the other domain i.e. all directories
So for example I would like my client to go to "sub.domain-one.com" or more specifically "sub.exampledomain.com/client_name". I would like this to then show the content of "domain-two.com", my development server, without the client knowing.
I would also if possible like to keep the base domain of "sub.domain-one.com" to stay on my live server so that I can keep a index.php on that server. But this is only an extra wish :)
My current code is
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_URI} !^(sub.)?domain-one.com/$1
RewriteCond %{HTTP_HOST} ^(sub.)?domain-one.com
RewriteRule ^(.*) http://domain-two.com/$1 [P,NC]
This code seems to work to an extent (it will let me go to sub.domain-one.com but if I go to sub.domain-one.com/client_name it will redirect my browser url to domain-two.com/client_name
But I need it hidden :(
Thanks heaps in advanced
James
You need to use a ProxyPassReverse in order to rewrite redirects from the proxied site to the site that you are proxying from. Unfortunately, you can't do this in an htaccess file. In the server/vhost config, you'll need to create a virtual host for "sub.domtain-one.com"/"domain-one.com", then use ProxyPass:
ProxyPass / http://domain-two.com/
ProxyPassReverse / http://domain-two.com/

Apache mod rewrite to direct from one server to another

I've got to apache web servers running. One on port 80 and another on port 8077.
I'm wanting to try and redirect all the traffic through the port 80 version if possible.
What I'm ideally wanting is to be able to go to http://translate.example.com
and the traffic get directed to http://www.example.com:8077
I've already got a lot of mod_rewrite going on at the main port 80 server, but I'm not sure which of the servers needs configuration or whether both do.
I'm wanting to make sure that translate.example.com/img (or any other subdirectory) actually points to the 8087/images directory.
update
I've now got the following:
RewriteCond %{HTTP_HOST} example[NC]
RewriteCond %{REQUEST_URI} ^/glot$ [NC]
RewriteRule ^(.*)$ http://www.example.com:8077/$1 [P]
ProxyPassReverse / http://www.example.com/
I'm getting to see the other servers new pages, but I'm finding all the resources aren't found like images, css etc
Doing a view source all the resources in the installed product are set with leading slash
For example
/img/glotpress-logo.png
So I'm not sure how to get the resources loaded up.
Note I'm happy enough if the original starting point is www.example.com/glot instead of glot.example.com as in the original question
You can remap your resources to another server but having the other server on non-default port might prevent some of your visitors from viewing them as they might be block (firewalled) from accessing the port. If you're not worry about the port being block you can use mod_rewrite Remapping Resources. method.
RewriteEngine On
RewriteRule ^/images/(.+) http://www.example.com:8077/images/$1 [R,L]
If you want to make sure that everyone is able to view the external resources, you need to use proxy where apache will tunnel the visitor connection to example.com:8077 transparently. You can read more about mod_rewrite for Proxying at apache website.
RewriteEngine on
RewriteBase /images/
RewriteRule ^images/(.*)$ http://example.com:8077/images/$1 [P]
ProxyPassReverse /images/ http://example.com/images/
UPDATE
Have you tried to remove
RewriteCond %{HTTP_HOST} example[NC]
This line basically tells that it will only process if the HTTP_POST is example.com if its coming from www.example.com this rule is not applicable. I'm hoping that "example[NC]" is a typo.
In the end it probably looks like
RewriteRule ^/glot/(.*)$ http://www.example.com:8077/glot/$1 [P]
ProxyPassReverse /glot/ http://www.example.com:8077/glot/
You need to do the configuration at the port 80 server to make it act as a proxy for the 8077 server.
The Apache document is here: http://httpd.apache.org/docs/trunk/rewrite/proxy.html

Internal redirect to another virtual host with mod_rewrite (or similar)

I'm trying to get site.com/api to internally redirect to api.site.com. Site.com's .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^api/(.*)$ http://api.site.com/$1 [P,QSA,L]
</IfModule>
I have mod_proxy and mod_rewrite installed. What am I doing wrong? Is this even possible?
EDIT: site.com and api.site.com are on the same server. I wish to do the redirect as efficiently as possible. If there's a way to pass a request in a certain path directly to a file, ie /srv/www/api.site.com/index.php via mod_rewrite, that would be just as good.
The point of this is to have two separate entities but circumvent javascript's cross-domain policy. Having a delegate is not an option, I want there to be direct communication. JSONP is not an option.
Figured this out via a url rewrite.
RewriteRule ^api/(.*)$ /library/api.php/$1 [QSA,L]
/library/api.php includes the index script in /srv/www/api.site.com/index.php directly. It has to rewrite some of the parameters in $_SERVER, but since the api.site.com's index.php is a singleton, this more than serves my purposes.

RewriteRule for mapping x.domain.com to y.domain.com

Is it possible to redirect all requests to x.domain.com/.* to y.domain.com/.* WITHOUT letting this redirection be visible in the url?
I have unsuccessfully tried several things in .htaccess. Just specifying the [L] flag still shows this redirection in the url (as it does when I use the [R] flag additionally).
EDIT: as somebody claimed there being no reason for this, let me give some more information :)
I have one nice url: x.domain.com , which is well known.
Then there are a number of other domains: spring.domain.com , summer.domain.com , autumn.domain.com, winter.domain.com .
Depending on the time of the year, a specific y.domain.com becomes the current one. The x.domain.com should always map to the current one.
EDIT2:
I'll write here, as the code isn't nicely rendered in the comments...
I tried what Arjan suggested:
RewriteCond %{HTTP_HOST} ^x.domain.com$
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1
Unfortunatly though this keeps redirecting forever. :(
Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
Putting the [R] flag behind, I see in the url something like:
http://x.domain.com/path/to/y.domain.folder/path/to/y.domain.folder/path/to/y.domain.folder/ ...
Any suggestions?
Now that I can read the errorlogs, I can give a direct response, as what a possible 500 error refers to.
Assuming you have access to the Apache configuration, create the following virtual host for domain x.domain.com. Then simply update y to whatever you need each season.
<VirtualHost ...:80>
ServerName x.domain.com
UseCanonicalName Off
ProxyRequests Off
<Proxy *>
Order Allow,Deny
Allow from all
</Proxy>
ProxyPreserveHost Off
RewriteEngine On
RewriteRule ^$ http://y.domain.com/ [P,NC]
RewriteRule ^/(.*)$ http://y.domain.com/$1 [P,NC]
ProxyPassReverse / http://y.domain.com/
</VirtualHost>
Also to pick up the Alias suggestions, if you have multiple virtual hosts (one for each season) then you could put a server alias into the current domain. E.g.
<VirtualHost ...:80>
ServerName summer.domain.com
ServerAlias x.domain.com
...
</VirtualHost>
<VirtualHost ...:80>
ServerName spring.domain.com
...
</VirtualHost>
...
This would make Apache deliver the summer.domain.com pages if you go to x.domain.com. If your seasonal subdomains depend on the HOST header line to be set correctly (i.e. to season.domain.com) you would need to use the first suggestion above, though.
If these are not hosted on the same server, then you'd need the Proxy flag. This also requires the proxy module to be running. Not tested:
RewriteCond %{HTTP_HOST} ^x.domain.com$
RewriteRule ^(.*)$ http://y.domain.com/$1 [P]
EDIT: Given the edits to your question they're probably just on the same server. So then indeed, as jetru suggested an Alias might do. Or:
# No RewriteCond required; serve all content from other folder:
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1
EDIT: The above would not change the HTTP_HOST header that was sent by the browser (maybe that can be done as well). This implies that it would only work if the subdomains are represented on the file system as separate directories. So, as the .htaccess would then be placed in the directory holding the website for x.domain.com, the RewriteCond wouldn't even be required. Also, the directory for this x.domain.com subdomain would in fact not need any HTML content then; in the end all content would be served from the directory of another subdomain.
EDIT: As the above does not seem to work either, and yields endless rewrite loops even when adding [NS], maybe simply adding [L] helps here:
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1 [NS,L]
Or maybe one can set an environment variable to stop the loop:
RewriteCond %{ENV:MY_VAR} !=1
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1 [E=MY_VAR:1]
But, for both [L] and [E]: I'm just guessing; I've never made mod_rewrite jump into the directory of another virtual host. I am not sure it can be done to start with.
Unfortunately, it's unclear how one would add a new subdomain. If one would just need to create a new directory with the name of the subdomain (without any use of some administrative tool) then the provider might be be using system wide rewriting as well. In fact, even without subdomains the provider might be doing some Mass Virtual Hosting as described in the URL Rewrite Guide.
I guess the best solution would be to change the value of HTTP_HOST on the fly, to solve issues with any system wide rewriting. Maybe the following is allowed to achieve that:
RewriteCond %{HTTP_HOST} ^x.domain.com$
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1 [E=HTTP_HOST:y.domain.com]
Again, as the above would only be present in the .htaccess in the x.domain.folder, the RewriteCond is probably not needed at all.
Have you tried
Alias /dir/file.html /full/path/to/other/file.html
??
To my knowledge and testing with firebug a redirect via .htaccess is always announced to the client and it's up to him how to proceed. It is therefore not an alternative to some sort of SSI functionality. To prevent a "fake" address modern browser should always make the REAL address visible to the user, however I think I have seen some misbehavior in programs like "feeddemon" where IE is embedded. If you - for whatever reason - really want to show content from one subdomain on another you can try using Javascript or (i)frames on the user side or some include functionality on the server site (eg. file_get_contents with php). However, I don't recommend this.