Combining a proxy rewrite in apache http server with header manipulation - apache

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>

Related

Redirect to custom 404-page doesn't work on localhost (Apache)

I have a .htaccess-file that has the directives as listed below. The first three lines are used to provide custom error pages for 403, 404 and 429.
ErrorDocument 404 /404.php
ErrorDocument 403 /403.php
ErrorDocument 429 /429.php
DirectoryIndex maintenance.html index.php index.html index.htm home.html
#Rewrite everything to https
<If "%{HTTP_HOST} != 'localhost'">
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</If>
<Else>
# local configuration
# nothing special here...
</Else>
This works perfectly fine when I publish to my website. When trying to open a non-existing page such as mysite.com/wrongpage.php the custom 404.php page is showed.
But when I try to do the same thing on localhost when entering localhost/wrongpage.php. It simply shows the browsers default 404 message. The 404.php page exists, but isn't used as expected.
I am not very good at how to work with the .htaccess file, but perhaps you can help me understand why it won't work on localhost?
This suggests you've not enabled .htaccess overrides on your local development server. .htaccess files are essentially disabled so the directives are not doing anything.
You need to set the AllowOverride directive in the appropriate <Directory> container in the server config (or <VirtualHost> container). By "appropriate" I mean the specific <Directory> container that targets your document root directory, not the entire server (which should remain AllowOverride None).
For example:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/html
<Directory /var/www/html>
Require all granted
# Enable .htaccess overrides
AllowOverride All
</Directory>
</VirtualHost>
And restart Apache.
Reference:
https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride

How can i use parts of the Referrer Header in an Apache Rewrite Rule

I'm writing a generic proxy of sorts - so I can access a single host in the form of http://<proxy-host>/<host-to-proxy-to>/<port>/<path>/ which currently uses rewrites to Proxy requests to https://<host-to-proxy-to>:<port>/<path>
I've got that part working and it seems to do what I want it to. However in some scenarios I'm using it with a stubborn sites that are forcing root relative urls. The application in question is not particularly easy (and in some cases impossible) to change.
My problem is how to identify the root relative URLs that are hitting apache, and proxy them to the correct host. I have identified that the correct host details are still in the path of the referrer header, so I'm trying to break apart and use the referrer path in a rewrite rule.
Updated Code Below:
<VirtualHost *:80>
ServerName wtf.devbox-cole.orion.internal
ServerAlias wtf.devbox-cole
RewriteEngine On
<LocationMatch "^/$">
Header always set X-CRAP-BASE "Its working kinda"
Redirect 410 /
</LocationMatch>
<Location /web/>
Header always set X-CRAP-BASE "Hardly Working"
RewriteCond %{HTTP_REFERER} "http://%{HTTP_HOST}/([a-zA-Z0-9_\.]*)/([0-9]*)/.*"
RewriteRule (.*) https://%1:%2/$1 [P]
</Location>
<LocationMatch "^/(?<host>[a-zA-Z0-9_\.]*)/(?<port>[0-9]*)/(?<path>.*)">
RewriteRule ".*" https://%{env:MATCH_HOST}:%{env:MATCH_PORT}/%{env:MATCH_PATH} [P]
ProxyPassReverse "https://%{env:MATCH_HOST}:%{env:MATCH_PORT}/%{env:MATCH_PATH}"
</LocationMatch>
# Enable proxying to https://
SSLProxyEngine On
# Allow Proxying to https without valid cert
SSLProxyVerify none
# Disable Domain Nmae checking on the Certs
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
# disbaled cert expiryt Check
SSLProxyCheckPeerExpire off
LogLevel debug rewrite:trace8
CustomLog "/var/log/apache2/wtf_log" "%h"
ErrorLog "/var/log/apache2/wtf_error
</VirtualHost>
The above code still isn't quite working. Still trying to track down why..
So after many attempts and reading as much documentation as I can find - I managed to solve my initial question. The following VHost block will Proxy http://domain.com/<host>/<port>/<path> to https://<host>:<port>/<path> AND it will map any requests to /web/* originating from that domain, back to the proper place.
<VirtualHost *:80>
ServerName domain.com
RewriteEngine On
<LocationMatch "^/$">
Header always set X-CRAP-BASE "Its working kinda"
Redirect 410 /
</LocationMatch>
<Location /web/>
Header always set X-CRAP-BASE "Hardly Working"
</Location>
RewriteCond %{REQUEST_URI} "^/web/.*"
RewriteCond %{HTTP_REFERER} "http://.*/([a-zA-Z0-9_\.\-]*)/([0-9]*)/.*"
RewriteRule (.*) https://%1:%2/$1 [P]
RewriteCond %{REQUEST_URI} "^/([a-zA-Z0-9_\.\-]*)/([0-9]*)/(.*)"
RewriteRule ".*" https://%1:%2/%3 [P]
<LocationMatch "^/(?<host>[a-zA-Z0-9_\.\-]*)/(?<port>[0-9]*)/(?<path>.*)">
ProxyPassReverse "https://%{env:MATCH_HOST}:%{env:MATCH_PORT}/%{env:MATCH_PATH}"
</LocationMatch>
# Enable proxying to https://
SSLProxyEngine On
# Allow Proxying to https without valid cert
SSLProxyVerify none
# Disable CN Checking on the Certs
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
# Disable Cert Expiry Check
SSLProxyCheckPeerExpire off
# Extra Logging
#LogLevel debug rewrite:trace8
CustomLog "/var/log/apache2/domain.com_log" "%h"
ErrorLog "/var/log/apache2/domain.com_error
</VirtualHost>
And then i remembered how silly Referrer headers are, in that if a CSS file requests another CSS file, or an image for example, then the Referrer isnt set as expected :facepalm:

Apache / Httpd mod_rewrite and Files directive not working

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.

apache add trailing slash redirects to different ServerName

In apache 2.2.22, I have multiple local servers setup such that localhostN refers to a server which I can access via local.myserver.com (for different "myserver"s). The problem is that one such server is doing a strange redirect when adding the automatic slash (I'm guessing via mod_dir), where accessing:
http://local.myserver.com/noslashdir
sends me to
http://localhost5/noslashdir/
instead of to
http://local.myserver.com/noslashdir/
I have not been able to override this behavior in the .htaccess file. Here are the relevant details:
/noslashdir/.htaccess:
DirectoryIndex index.html
/.htaccess:
SetEnvIf HTTPS on http_proto=s
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^noslashdir/(.*)$ /noslashdir/$1.html [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^noslashdir/(.+)\.html$ http%{http_proto}://%{HTTP_HOST}/noslashdir/$1 [L,R=302]
/etc/httpd/httpd.conf
<VirtualHost 127.0.0.5>
ServerName localhost5
DocumentRoot /var/www/myserver.com/
DirectoryIndex index.php index.html index.htm index.shtml
<Directory "/var/www/myserver.com">
Options Indexes +Includes FollowSymLinks
AllowOverride All
Allow from all
Order allow,deny
</Directory>
ScriptAlias /cgi-bin/ "/var/www/myserver.com/cgi-bin/"
</VirtualHost>
/etc/hosts
127.0.0.5 local.myserver.com localhost5
I have tried RewriteRules, DirectorySlash Off, etc, but nothing has worked so far. All other desired redirects work fine.
Apache is using the ServerName you have set for your VirtualHost when creating “self-referential URLs”.
http://httpd.apache.org/docs/2.2/en/mod/core.html#servername:
“The ServerName directive sets the request scheme, hostname and port that the server uses to identify itself. This is used when creating redirection URLs.”
You should set UseCanonicalName to Off:
“In many situations Apache must construct a self-referential URL -- that is, a URL that refers back to the same server. With UseCanonicalName On Apache will use the hostname and port specified in the ServerName directive to construct the canonical name for the server. This name is used in all self-referential URLs, […]
With UseCanonicalName Off Apache will form self-referential URLs using the hostname and port supplied by the client if any are supplied […]”

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]