Apache / Httpd mod_rewrite and Files directive not working - apache

I'm setting up some Apache (httpd) configuration for an Apache server fronting a Tomcat server like this:
<Proxy *>
Order deny,allow
Allow from all
AllowOverride All
</Proxy>
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)\.v(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L]
</IfModule>
ProxyPass / http://localhost:8080/ retry=0
ProxyPassReverse / http://localhost:8080/
ProxyPreserveHost on
<Files "*.html">
Header set Cache-Control "public, max-age=900"
</Files>
I have both the rewrite module and header module installed. The mod_rewrite rule is there so that I can version my static resources e.g. style.v2.css will be transformed to style.css etc. The custom header is to avoid aggressive caching of html files by browsers.
The proxy directives pass requests onto the Tomcat server listening on port 8080. The rewrite rules is not working though. I get a 404 for style.v2.css because it's not transforming the filename to style.css.
The custom header does not get applied either, but only because the <Files> directive is not matching my html files. If I remove the <Files> directive and apply the custom header to all files, then they all get that header in the their responses.
I'm not sure how to debug this. Is there anything obviously wrong with this configuration?
I had forgotten to include RewriteEngine On to make the rewrite rule work. It does now that I've added that. The <Files> match still doesn't work, even though I am requesting html files.
Also, using:
<Files "myfile.html">
Header set Cache-Control "public, max-age=900"
</Files>
...still does not work when I make a request specifically for myfile.html. By the way, this configuration is inside <VirtualHost _default_:443>.
I've also tried putting my <Files> directive inside a <Directory> directive, but it still doesn't work:
<Directory "/var/www">
<Files "*.html">
Header set Cache-Control "public, max-age=600"
</Files>
</Directory>

The Files directive was apparently useless because I had no DocumentRoot setup e.g.
DocumentRoot /var/www
Once I did that the files started matching.

Related

Combining a proxy rewrite in apache http server with header manipulation

I have to modify the response headers delivered via a proxy rewrite directive I set up in an apache http server.
Things work fine with that simple example, it unconditionally delivers the goal from the backend server for all requests:
<VirtualHost ...>
...
# unconditionally modify headers
Header set Content-Type "text/html"
Header unset Content-Disposition
Header unset Content-Transfer-Encoding
# fetch goal from backend
RewriteEngine on
SSLProxyEngine on
RewriteRule ^ https://back.example.org/goal [P]
...
# prevent all access to the file system
DocumentRoot /var/www/html
<Directory /var/www/html>
Options none
Order deny,allow
Deny from All
</Directory>
</VirtualHost>
However the issue is that the host also has to deliver a few static files from another backend server where the headers must not be altered! So I made an attempt to rewrite to a virtual goal in a first step, apply the header modification rules and then to proxy in a second step:
<VirtualHost ...>
...
# modify headers only for /goal
<Location /goal>
Header set Content-Type "text/html"
Header unset Content-Disposition
Header unset Content-Transfer-Encoding
</Location>
# fetch static exceptions from static backend
RewriteEngine on
SSLProxyEngine on
RewriteRule static-1$ https://static.example.org/static-1 [P]
RewriteRule static-2$ https://static.example.org/static-2 [P]
RewriteRule static-3$ https://static.example.org/static-3 [P]
# two step rewrite and proxy to fetch goal from backend and get the headers modified
RewriteRule ^/goal$ https://back.xample.org/goal [P]
RewriteRule ^ /goal [PT,N]
...
# prevent all access to the file system
DocumentRoot /var/www/html
<Directory /var/www/html>
Options none
Order deny,allow
Deny from All
</Directory>
</VirtualHost>
This however leaves me with a http status 403.
I used rewrite logging for further insight and indeed the request is rewritten to /goal according to the first step, the URI -to-filehandler API is invoked again and then the request gets simply mapped onto the file system which explains the 403. Why doesn't the second rewrite step get applied, the proxy step, in a next round?
Or, my actual question: how can I have header modifications get applied to a catch-all rewrite proxy rules result, but define some explicit exceptions from the header modifications?
Ok, poked a bit mir, since I received neither answer nor comment... (why is it that most of my questions only hit a wall of silence? ).
A working solution is to use a negative LocationMatch directive for the static content exceptions. Not sexy, but working:
<VirtualHost ...>
...
RewriteEngine on
SSLProxyEngine on
# fetch static exceptions from static backend
RewriteRule static-1$ https://static.example.org/static-1 [P]
RewriteRule static-2$ https://static.example.org/static-2 [P]
RewriteRule static-3$ https://static.example.org/static-3 [P]
# proxy goal from backend
RewriteRule ^ https://back.xample.org/goal [P]
...
# modify headers, but _not_ for static exceptions
<LocationMatch "^/(?!static)">
Header set Content-Type "text/html"
Header unset Content-Disposition
Header unset Content-Transfer-Encoding
</LocationMatch>
...
# prevent all access to the file system
DocumentRoot /var/www/html
<Directory /var/www/html>
Options none
Order deny,allow
Deny from All
</Directory>
</VirtualHost>

How to disable 301 redirect that adds trailing slash to directory name in Apache

The Apache 2.2.20 automaticaly redirects all requests which are points to directories and has no trailing slash to the same URL with trailing slash, like shown below:
GET /some/path/to/dir HTTP/1.1
Host: www.some.org
...
301 Moved permanently
Location: http://www.some.org/some/path/to/dir/
In all cases it is a fine behavior, but I need to turn off this feature for one special folder (not for all), and can't find were I can do it.
Searching for 'Rewrite' rules tells founds nothing - only directive LoadModule mod_rewrite.so. Also, there is no .htaccess files in directories server in directory tree.
Is there any other directives that make thing?
UPD1 I try to set up SVN trough HTTP with next config:
LoadModule dav_svn_module /opt/libexec/mod_dav_svn.so
LoadModule authz_svn_module /opt/libexec/mod_authz_svn.so
NameVirtualHost *:8000
<VirtualHost *:8000>
ServerAdmin admin#some.host.org
ServerName some.host.org
DocumentRoot /path/to/wwwroot
DAVLockDB /opt/var/lock/davlock/svndavlockdb
<Directory /path/to/wwwroot>
Options FollowSymLinks Indexes
# #AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory /path/to/wwwroot/svn>
Options FollowSymLinks Indexes
AllowOverride None
Order allow,deny
Allow from all
</Directory>
CustomLog /path/to/wwwroot/log/access_log.txt combined
ErrorLog /path/to/wwwroot/log/error_log.txt
<Location /svn>
#AllowOverride None
#RewriteEngine Off
#RewriteOptions AllowNoSlash
DirectorySlash Off
DAV svn
SVNParentPath /path/to/wwwroot/svn
# SVNListParentPath on
AuthType Basic
AuthName "Subversion Repository"
AuthBasicAuthoritative Off
AuthUserFile /path/to/wwwroot/svn/.htauthfile
<Limit GET OPTIONS REPORT PUT POST DELETE PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK>
Require valid-user
</Limit>
</Location>
</VirtualHost>
UPD2 It seems that the "DirectorySlash Off" directive works only for "some.host.org/svn" and not works for "some.host.org/svn/repo1", "some.host.org/svn/repo2" etc - child directories not inherit this option.
UPD3 I try to add the following lines into config, but result is same - "DirectorySlash Off" work only for "/svn" and not for childs.
<LocationMatch "/svn/.*">
DirectorySlash Off
</LocationMatch>
SOLVED
Problem solved. This is a my mistake - I placed SVN repository root under DocumentRoot folder, so apache and web_dav can't understand, who must handle request. This applies to TortoiseSVN client at least.
Comments from SVN developers:
It means your httpd.conf is misconfigured. Usually this error happens when you've defined the Subversion virtual "location" to exist within two different scopes at the same time.
For example, if you've exported a repository as , but you've also set your DocumentRoot to be /www, then you're in trouble. When the request comes in for /www/foo/bar, apache doesn't know whether to find a real file named /foo/bar within your DocumentRoot, or whether to ask mod_dav_svn to fetch a file /bar from the /www/foo repository. Usually the former case wins, and hence the "Moved Permanently" error.
The solution is to make sure your repository does not overlap or live within any areas already exported as normal web shares.
It's also possible that you have an object in the web root which has the same name as your repository URL. For example, imagine your web server's document root is /var/www and your Subversion repository is located at /home/svn/repo. You then configure Apache to serve the repository at http://local.host/myrepo. If you then create the directory /var/www/myrepo/ this will cause a 301 error to occur.
Use mod_dir's DirectorySlash directive. Example from docs:
# see security warning in docs
<Location /some/path>
DirectorySlash Off
SetHandler some-handler
</Location>
Adding
DirectorySlash Off
to .htaccess worked fine for me.

Magento Multi Store Redirect loop

I'm using Magento 1.6.2.0., Apache, Fast CGI, OpenSUSE
I have set up Multi Store successfully by redirecting a different domain using vhost.conf and vhost_ssl.conf, and by altering the .htaccess in the 'root' domain. I need to do it this way because I need 2 separate IP addresses and 2 SSL certs. The redirect works and I have been able to skin the new domain to my liking.
.htaccess:
SetEnvIf Host .*domain.* MAGE_RUN_CODE=domain_code
SetEnvIf Host .*domain.* SetEnv MAGE_RUN_TYPE=website
vhost_ssl.conf:
<IfModule mod_suexec.c>
SuexecUserGroup "user" "xxxx"
</IfModule>
DocumentRoot "/var/www/vhosts/domain.co.uk/dev.domain.co.uk"
<Directory /var/www/vhosts/domain.co.uk/dev.domain.co.uk>
<IfModule mod_fcgid.c>
<Files ~ (\.php)>
SetHandler fcgid-script
FCGIWrapper /var/www/cgi-bin/cgi_wrapper/cgi_wrapper .php
Options +ExecCGI
allow from all
</Files>
</IfModule>
SSLRequireSSL
Options -Includes -ExecCGI
</Directory>
My concern is that whenever I try to navigate to an https:// page I get a redirect loop in the browser.
I have no SSL cert set up for this domain, but to my mind this should not create this error, but rather a 'no cert' error (if anything).
I was hoping that someone might be able to point out a solution that they have had in the past.
Thanks for any time that anyone spends on this.

apache virtual host and "Dynamic" Domains

I have a java application responding multiple domains and uses, for each domain, a specific apache virtual host. This because Apache is faster than tomcat, to serve static resources.
The need is to do that at runtime, without restart apache configuration.
To perform this action I'm using VirtualDocumentRoot directive, as described below:
AddType text/html .html .shtml
AddOutputFilter INCLUDES .html .shtml
NameVirtualHost *:80
UseCanonicalName Off
<VirtualHost *:80>
ServerName domain.com
ServerAlias *
# Define virtual host directory, using entire domain
VirtualDocumentRoot /path/to/whosts/%0
# Define directory access
<Directory "/path/to/whosts/">
Options -Indexes MultiViews +Includes
Order allow,deny
Allow from all
</Directory>
# Define Java Proxies
<Proxy *>
AddDefaultCharset Off
Order deny,allow
Allow from all
</Proxy>
# Allow Libs (static resources) to access apache directly
ProxyPass /libs !
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/
</VirtualHost>
This does not work well, because if I try to access to www.domain.com, is different than access to domain.com.
Do you think is a good idea to register a symbolic link from www.domain.comto domain.com???
Exists another way to do that? I'm really poor in apache managing...
Thank's a lot!
Ciao, Davide.
I regularly use symlinks to link multiple domains to the same webroot when doing configurations similar to this, there is no explicit harm in that solution so definitely no reason to shy away from it.
A good way would be to decide which type of URL should be the canonical one, and use mod_rewrite to redirect URLs to it - for instance, match requests to domain.com and redirect them to www.domain.com. There's plenty of tutorials on how to do this available on the web which you should be able to find easily.
Off the top of my head, you could use something like:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www\.$ [NC]
RewriteRule ^(.*) http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
That would cause problems if you're using SSL, though, due to the hardcoded http://. I think you could change the RewriteRule line to the following to avoid that:
RewriteRule ^(.*) %{SERVER_PROTOCOL}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Can I turn off an Apache Directive then turn it on in an include?

I have a VirtualHost block that includes common configuration items, one directive is ProxyPreserveHost.
Can I "procedurally" turn off ProxyPreserveHost for a Rewrite directive then have the include turn it back on? For example:
<VirtualHost *:80>
ServerName www.blah.com
...
...
ProxyPreserveHost off
RewriteRule /somepath http://otherhost/otherpath [P]
Include /path/to/file/turning-on-ProxyPreserveHost
</VirtualHost>
The otherhost is on a CDN and preserving the host is creating some name resolution issue that is not allowing the proxying of content in the host namespace.
ProxyReserveHost is only allowed in a Server Config or VirtualHost. It doesn't look like I can selectively turn it off for the ProxyPass and ProxyPassReverse directives (encapsulated in the proxy flag of mod_rewrite).
The following, found on the internet, addressed my dilemma. As an aside, there is an open feature request to make ProxyPreserveHost configurable at the Location and Directory level within the Apache HTTPD project.
<IfModule mod_headers.c>
<Proxy "http://${build.replace.host}/">
RequestHeader set Host ${build.replace.external.host}
</Proxy>
RewriteRule ^/proxypath/ http://${build.replace.external.host}/path/to/resource.html [P]
ProxyPassReverse /proxypath/ http://${build.replace.external.host}/path/to/resource.html
</IfModule>