Providing unique directives to proxy block by virtual host - apache

Say I have the following Proxy block in my main config:
<Proxy balancer://PrivateSSL/>
BalanceMember http://host:8080/ route=01 loadfactor=100
BalanceMember http://host:8080/ roout=02 loadfactor=100
ProxySet stickysession=ROUTEID
</Proxy>
Now, in a VirtualHost can I "enhance/spice/modify" that block like so:
<VirtualHost ip:port>
...
<Proxy balancer://PrivateSSL/>
RequestHeader set Host reverse-proxy-host
</Proxy>
</VirtualHost>
without having all the previously defined Proxy elements repeated?
I'm actually going to play with this, but the community might have a pattern that works better (maybe saying that is verboten, but I think others will benefit from the answer).

Testing locally is going to be a dog. But some RTFM helped out:
The configuration sections are applied in a very particular order. Since this can have important effects on how configuration directives are interpreted, it is important to understand how this works.
The order of merging is:
<Directory> (except regular expressions) and .htaccess done
simultaneously (with .htaccess, if allowed, overriding <Directory>)
<DirectoryMatch> (and <Directory ~>)
<Files> and <FilesMatch> done
simultaneously
<Location> and <LocationMatch> done simultaneously
<If>
...
When the request is served by mod_proxy, the <Proxy> container takes the place of the <Directory> container in the processing order.

Related

Apache ProxyPass error

I have to redirect all apache requests on 80 to tomcat on 8080, except one path.
So, if a receive http://example.com/anything --> tomcat:8080.
But, if the url is that: http://example.com/site --> apache should serve and no redirect is needed.
Currently, there is a folder named site inside /var/www/html/.
This is my current configuration file:
site.conf (this file contains only the following and is inside the conf.d folder)
<LocationMatch "/*">
Allow from all
ProxyPass /site !
ProxyPass http://127.0.0.1:8080
ProxyPassReverse http://127.0.0.1:8080
</LocationMatch>
I think this is a simple thing to accomplish with apache, but I have tried everything that I could find and I am still getting the error:
ProxyPass|ProxyPassMatch can not have a path when defined in a location.
The thing is that the root website is running on tomcat, but the other runs on apache (the one that I called site in this question).
If anyone can help, I appreciate.
Thanks!
Update 1 - 09/06/2017
I get it to work if I remove the LocationMatch and put the ProxyPass
direct in the .conf file:
ProxyPass /site !
ProxyPassReverse /site !
ProxyPass / http://127.0.0.1:8080
ProxyPassReverse / http://127.0.0.1:8080
But, I would like to know, why is that? What is the impact of putting this directives outside the LocationMatch tag? And, most important, why I cannot accomplish the same result using the LocationMatch?
I think the error is pretty clear:
ProxyPass|ProxyPassMatch can not have a path when defined in a location.
According to the documentation, inside a context block like Location or LocationBlock the ProxyPass directive does not accept a path:
When used inside a <Location> section, the first argument is omitted and the local directory is obtained from the <Location>. The same will occur inside a <LocationMatch> section; however, ProxyPass does not interpret the regexp as such, so it is necessary to use ProxyPassMatch in this situation instead.
You're getting the error because you were trying to use a path:
ProxyPass /site !
You could try to resolve this in theory by using multiple <Location> sections, like this:
<Location />
ProxyPass http://backend/
</Location>
<Location /site>
ProxyPass !
</Location>
The ordering of these sections is important.
Your solution of using ProxyPass directives outside of a LocationMatch block is probably the simplest solution.
As a side note, your LocationMatch directive is incorrect. The argument to LocationMatch is a regular expression, and /* would only match URLs consisting only of / characters. That is, it would match / or // or /////////, etc. I think you really meant /.*. The * in a regular expression means "the previous character, zero or more times".

Apache delete/remove/undefine a proxy balancer definition

I have an Apache configuration that needs to implement a balancer that uses a set of temporary upstream servers for a few months and then replace them with a permanent set. I am trying to design an approach that lets me deliver both configurations at install time and makes it easy to switch them programmatically later on. This needs to be done on about 40 servers that all have unique configurations.
What I've tried so far...
I added the following code to the httpd.conf file:
<proxy balancer://upstream>
balancermember http://permanentserver1:80
balancermember http://permanentserver2:80 status=+H
balancermember http://permanentserver3:80 status=+H
</proxy>
include conf\temp_upstream.conf
..and then inside the temp_upstream.conf file, I try to overwrite the definition of the balancer
<proxy balancer://upstream>>
balancermember http://temporaryserver1:80
balancermember http://temporaryserver2:80 status=+H
balancermember http://temporaryserver3:80 status=+H
</proxy>
…but it doesn't seem to work. The second balancer definition appears to be ignored (although it may be merged - I can't easily tell).
The reason I'm using this approach is so that I can just replace the temp_upstream.conf file with an empty file when it's time to perform the switch over - and then restart Apache.
Is there any way I can make this configuration work? Is there a way that I can undefine/delete a balancer that was defined earlier in the script so that the second definition is accepted? (I do know that I could pass a variable on the startup line and use IfDefine to conditionally process the right definition - but that would mean modifying the Apache startup command which I'd rather not do.)
I recently came upon a perfect solution to my problem.
I confirmed that the 2 definitions are merged in memory to make one larger definition.
I was able to make it work exactly like I wanted it to by adding "lbset=0" (the default) to each BalancerMember definition in the temporary configuration in the temp_upstream.conf file and "lbset=1" to the BalancerMember definitions in the permanent configuration in httpd.conf. The lbset=1 definitions are only used after all lbset=0 definitions have failed.

How to server static files + proxy context

I am wondering how to configure my httpd server to serves the following pages:
My need is to serve static content located in my /var/www/static when url is /context/static and to proxy the remaining to a tomcat server
In this order:
/context/static/* --> files served by httpd
/context/* --> resources served by tomcat
I have tried to rewrite /context/static/* to a folder pointing to my /var/www/static and added the ProxyPath directive for the remaining but I can't get it working.
What are the best practices and how to achieve that ?
Thanks in advance
Well, in fact it is quiet easy...
Having such folders configured:
/var/www/static/
|- css/*
|- js/*
\ medias/*
The following httpd configuration will redirect static/* to the /var/www and the rest will be proxied
# first rewrite for statics
RewriteEngine On
RewriteRule ^/context/static/(.+)$ /static/$1
# then proxy remaining...
ProxyPass /context http://127.0.0.1:8080/context
ProxyPassReverse /context http://127.0.0.1:8080/context
I've found the following approach that works and is quite general. (4/12/2018)
Location/Proxypass expressions always take priority over any other location block, so you have to Exclude the paths that you don't want to be proxied. the "?!" does that in the regex. Since static content is, um, static, it is not so bad to require that the apache configuration be updated if another directory is needed to be served directly for a different media type.
The following was taken from a server that was proxying a Python Flask application.
<LocationMatch "^/(?!js|css|media)" >
ProxyPass http://127.0.0.1:5000
ProxyPassReverse http://127.0.0.1:5000
</LocationMatch>
<Location "/">
Require all granted
</Location>
Both of the existing answers rely on Regular Expressions. While they work, it is possible to do this without such complicated constructs. ProxyPass can take "!" as a second parameter, in which case it doesn't proxy the matching URL. For example
ProxyPass /context/static/ !
ProxyPass /context http://127.0.0.1:8080/context
ProxyPassReverse /context http://127.0.0.1:8080/context
or, with multiple exclusions,
ProxyPass /js !
ProxyPass /css !
ProxyPass /media !
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
These exceptions need to come before the more general rule in order to take precedence.
Thanks to freenode user "thumbs" in #httpd.

Override single setting in default Apache <VirtualHost> block

In debian's default apache2 configuration, /etc/apache2/sites-enabled/000-default contains a lot of settings for the default VirtualHost:
<VirtualHost *:80>
# Many good settings here, among them:
CustomLog ${APACHE_LOG_DIR}/access.log combined
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
</VirtualHost>
In another configuration file, I'd like to override a single one of them, the CustomLog setting, so that logs go somewhere else. I don't want to copy or mess with all the other settings, e.g. ScriptAlias. But I still want it to apply to <VirtualHost *:80>.
Is that possible?
What I tried
I tried putting this in
/etc/apache2/sites-enabled/001-mylog:
<VirtualHost *:80>
CustomLog ${APACHE_LOG_DIR}/my.log combined
</VirtualHost>
That has no effect, presumably because apache only looks at the first <VirtualHost> section, and /etc/apache2/sites-enabled/000-default gets loaded before /etc/apache2/sites-enabled/001-mylog.
Instead I tried putting the same snippet in /etc/apache2/conf.d/mylog, that gets loaded before /etc/apache2/sites-enabled/000-default because /etc/apache2/apache2.conf has an Include conf.d/ before Include sites-enabled/. That does override the CustomLog value as I wanted. But now the ScriptAlias from /etc/apache2/sites-enabled/000-default doesn't take effect.
I'd like to avoid duplicating everything from /etc/apache2/sites-enabled/000-default effectively creating a fork of the default debian apache configuration file.
Documentation
Apache HTTP Server - core documentation has this rather vague:
When a request is received, the server first maps it to the best matching
based on the local IP address and port combination only.
Non-wildcards have a higher precedence. If no match based on IP and port occurs
at all, the "main" server configuration is used.
If multiple virtual hosts contain the best matching IP address and port, the
server selects from these virtual hosts the best match based on the requested
hostname. If no matching name-based virtual host is found, then the first
listed virtual host that matched the IP address will be used. As a consequence,
the first listed virtual host for a given IP address and port combination is
default virtual host for that IP and port combination.
<VirtualHost> doesn't behave like <Directory>
Very confusingly, it looks to me as if for <VirtualHost> directives, only a single matching instance is considered. But for e.g. <Directory> directives, they are added/combined, so that:
<Directory "/some/dir">
Options Indexes MultiViews FollowSymLinks
</Directory>
<Directory "/some/dir">
AllowOverride None
Order deny,allow
Allow from all
</Directory>
is equivalent to:
<Directory "/some/dir">
Options Indexes MultiViews FollowSymLinks
AllowOverride None
Order deny,allow
Allow from all
</Directory>
But that this mechanism doesn't work for <VirtualHost> :-(
Edit: This is not the same as Sharing configuration between several VHosts, because debian's default VirtualHost doesn't use any of those solutions. But perhaps others can find inspiration in that answer.
I get the same puzzle for the multiple vhosts'(virtual hosts') definition. Do they override(redefine), overlap? Or there are other veiled details inside?
I find some links for this puzzle as following:
https://www.thegeekstuff.com/2011/07/apache-virtual-host/
https://httpd.apache.org/docs/2.4/vhosts/examples.html
With cautions to these examples inside, I could say the vhosts' definitions are not the same (even they look like the same). The difference mainly lays on the SeverName inside definition. Apache httpd server distinguishes the different vhost definitions based on ServerName inside(each vhost definition), not the IP Address or Port Number as listed in the <VirtualHost> header.
This puzzle keeps coming and going since there lacks explicit explanation for this topic(in the web). I hope this post can help to relieve this mindboggler in a way.

Apache: <Directory> directive with no path specified

I have a local server environment running on my OS X machine using MAMP, and I am currently setting up a few virtual hosts. I found that, in order for one of my virtual hosts to recognize my site's .htaccess file, I needed to add a <Directory> directive within the <VirtualHost> directive.
Here is an example of what I am using to configure one of my virtual hosts:
<VirtualHost *>
DocumentRoot "/path/to/mysite"
ServerName mysite.local
<Directory "/path/to/mysite">
AllowOverride All
Order Allow,Deny
Allow from all
</Directory>
</VirtualHost>
Now, I would like to avoid redundancy by removing the path from that <Directory> directive. I tried doing so and it seems to work, although I am not familiar with Apache enough to know the potential consequences of doing this. Furthermore, I could not find an explanation of this case in the Apache Documentation.
This is what I would like to do:
<VirtualHost *>
DocumentRoot "/path/to/mysite"
ServerName mysite.local
<Directory>
AllowOverride All
Order Allow,Deny
Allow from all
</Directory>
</VirtualHost>
Therefore, my question is this: what happens when I omit the path from the <Directory> directive (in this case)?
Directory is a directive targeting a file system directory, and should always have a path (waildcards allowed).
Using some instructions targetd to no directory may be discarded silently, or maybe with an error (you could test it), but is would certainly be useless.
Why would you write some configuration instructions targeted to no directory at all?
But there's maybe more things in your question.
Ususally a Virtualhost should contains at least one Directory instruction, the DocumentRoot directory, and usually we also add one targeting the root of the filesystem, this way:
<Directory />
(instructions to deny access and avoid .htaccess reads)
</Directory>
<Directory /my/document/root/>
(instructions to allow access and still avoid .htaccess reads or to allow them if you are lazy and feel over confident that .htaccess are useful in any way and you do not need speed)
</Directory>
And you could add more, especially to avoid usage of .htaccess files as such file stored in /path/to/somewhere is the same thing as a <Directory /path/to/somewhere> section, but slower.
Now you do not like to repeat yourself in your VH configuration, so you coud maybe use .htaccess files or global level instructions for things that are usually set there. And you could also use another magical keyword, which is Location.
You can use a lot of Apache instruction in a <Location /foo> directive. Locations works on url, not on filesystem paths.
So <Location /> is your documentRoot, and <Location /foo> is maybe the subdirectory 'foo' under you DocumentRoot. This could help you write things in your VH without reusing the documentroot prefix everywhere. But be careful, urls are not file-system paths. Any protection applied on the url level may be weaker or stronger compared to a protection applied on a directory level. It depends on your alias, the way you use urls, etc.
Update:
If you use the new Apache 2.4 version you can now use mod_macro or even easier, built-in variables support:
Define docroot "/path/to/mysite"
DocumentRoot ${docroot}
<Directory ${docroot}>
(...)