RewriteRule includding only last part of REQUESTI_URI - mod-rewrite

<LocationMatch /foo/>
ProxyPreserveHost On
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* "ws://192.168.0.101:1234%{REQUEST_URI}" [P]
when client connects to
ws://www.example.com/foo/whatever_arbitrary_random
this works great, but the outcome is
ws://192.168.0.101:1234/foo/whatever_arbitrary_random
how can i get rid of the /foo/ so the outcome would be
ws://192.168.0.101:1234/whatever_arbitrary_random
client must still need to connect to /foo/ to trigger this
EDIT: I found how to do it, replace last line with
RewriteRule ([^/]+)/?$ ws://192.168.0.101:1234/$1 [P,L]
But please read the first answer suggesting not to do this in a Location

You shouldn't use mod_rewrite directives inside <Location> (and <LocationMatch>) containers.
UPDATE: As stated in the Apache docs for the RewriteRule directive:
Although rewrite rules are syntactically permitted in <Location> and <Files> sections (including their regular expression counterparts), this should never be necessary and is unsupported. A likely feature to break in these contexts is relative substitutions.
<Location> sections are merged very late. When used inside a <Location> section, the RewriteRule directive matches the absolute filesystem-path, not the URL-path as would ordinarily be expected.
If .htaccess overrides are disabled then you can do it like this instead inside the appropriate <Directory> container:
<Directory /path/to/foo>
# Disable .htaccess overrides if not already
AllowOverride None
ProxyPreserveHost On
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* ws://192.168.0.101:1234/$0 [P]
</Directory>
The backreference $0 naturally excludes /foo/.
UPDATE:
RewriteRule ([^/]+)/?$ ws://192.168.0.101:1234/$1 [P,L]
This only matches the last path segment, it doesn't strictly match everything after /foo/. This may or may not be OK, depending on your requests. eg. It will redirect a request for /foo/bar/baz to /baz only, not /bar/baz.
The regex should really be anchored. However, you've probably written it this way because the directive is inside a <Location> section and matches the absolute file-path, rather than the requested URL-path.
Incidentally, you don't need the L flag when used with P - it is implied.
An alternative to the above... you don't need to use these directvies in a directory context (ie. inside a <Directory> or <Location> section). You can instead place these rules directly in the <VirtualHost> container (a virtualhost context), in which case they should be written like this instead:
ProxyPreserveHost On
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/foo/(.*) ws://192.168.0.101:1234/$1 [P]

Related

Unable to remove empty parameters in url using context path in Location tag in apache http server

Unable to remove empty parameters in url using context path in Location tag in apache http server
Without context path setting, empty parameters are being removed correctly as expected,
Below is the example with context path, where empty parameters are not removed (Problem statement)
<Location /reports/>
LogLevel alert rewrite:trace8
RewriteEngine On
RewriteBase /
ProxyPass http://1.2.3.4:3000/
ProxyPassReverse http://1.2.3.4:3000/
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^/reports$ /reports/?%1%2 [R=302,NE,L]
</Location>
Below is the example without context path, where empty parameters are removed as expected (But the final solution needs to work with a context path)
<Location />
ProxyPass http://1.2.3.4:3000/
ProxyPassReverse http://1.2.3.4:3000/
RewriteEngine On
AllowOverride All
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^ %{REQUEST_URI}?%1%2 [R=302,NE,L]
</Location>
How do I remove the empty parameters from the URL with the context path setting in the location?
<Location /reports/>
:
RewriteEngine On
RewriteBase /
:
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^/reports$ /reports/?%1%2 [R=302,NE,L]
</Location>
There are several issues here...
Your <Location> block matches /reports/ (with a trailing slash), but your RewriteRule pattern ^/reports$ omits the trailing slash, so it will never match.
<Location> blocks are merged very late and in this context the RewriteRule pattern matches against the absolute filesystem path, not the root-relative URL-path.
So in order to match the request, the RewriteRule pattern should be like /reports/$ instead to allow for the absolute filesystem path, eg. /path/to/document-root/reports/. In other words:
RewriteRule /reports/$ /reports/?%1%2 [R=302,NE,L]
Or, omit the path component of the RewriteRule pattern altogether (eg. simply ^), unless you must only match /reports/ and not /reports/<anything>.
HOWEVER, you shouldn't use mod_rewrite directives inside a <Location> block to begin with. From the Apache 2.4 docs on the RewriteRule directive:
Although rewrite rules are syntactically permitted in <Location> and <Files> sections (including their regular expression counterparts), this should never be necessary and is unsupported. A likely feature to break in these contexts is relative substitutions.
The RewriteBase directive is not being used here. (But it is not supported/not required outside of a directory context.)
The RewriteRule pattern and the <Location> directive are performing the same check. Move these mod_rewrite directives outside of the <Location> container and have them directly in the <VirtualHost> container (or server context). For example:
LogLevel alert rewrite:trace8
RewriteEngine On
RewriteCond %{QUERY_STRING} ^(.+?&)?[^=]+=(?:&(.*))?$
RewriteRule ^/reports/$ /reports/?%1%2 [R=302,NE,L]
<Location /reports/>
ProxyPass http://1.2.3.4:3000/
ProxyPassReverse http://1.2.3.4:3000/
</Location>

Rewriting behaves differently in .htaccess vs vhost

I'm using following chunk of instructions to rewrite www to non www url:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]
</IfModule>
If I place it in .htaccess file, it works fine.
If I place it in vhost file, after rewriting two forward slashes are added to the host, for example www.domain.com will become domain.com//
Am I missing something?
Also, is it worth placing all .htaccess content in vhost performancewise?
RewriteRule is behaving as the docs say.
There is a difference in what RewriteRule matches against when in VirtualHost context & Directory & .htaccess context.
From RewriteRule Directive Apache Docs
What is matched?
In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html").
In Directory and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that lead the server to the current RewriteRule (e.g. "app1/index.html" or "index.html" depending on where the directives are defined).
If you wish to match against the hostname, port, or query string, use a RewriteCond with the %{HTTP_HOST}, %{SERVER_PORT}, or %{QUERY_STRING} variables respectively.
So, when in VirtualHost the server in not in a directory context so prefix / will not be removed. Also remember when matching with RewriteRule in VirtualHost context, the pattern will always begin with /.
So, your RewriteRule Should be:
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^/(.*)$ http://%1/$1 [R=301,NC,L]
in VirtualHost context.
Also, is it worth placing all .htaccess content in vhost performancewise?
Yes, Definitely. One reason is that, no file (.htaccess) will be read every time you are accessing a page.

How to make complex conditions in mod_rewrite?

I need to deny access to the whole site for everyone except some IPs.
Also, I need to permit access to one folder of site for everyone:
Options +FollowSymLinks
Options +Indexes
RewriteEngine on
# Allow access only for devs
RewriteCond %{REMOTE_ADDR} !10.10.10.10 [NC] # First dev id
RewriteCond %{REMOTE_ADDR} !11.11.11.11 [NC] # Second dev id
# Allow direct access to files
RewriteCond %{REQUEST_FILENAME} !-f
# Redirecting guests
RewriteRule (.*) /coming/soon/index.html [R=307]
# But where to place this condition?
RewriteRule ^/?preview/?$ /preview/index.html [NC]
# Other rules for main site structure
# ...
So, I need the whole site loading only for devs. Other users (guests) will see the /coming/soon/ page
And also guests are allowed to see /preview/ page of the site.
How to do this?
If your /preview/ rewrite is suitable for all users and does not depend on subsequent rewrite rules, the simplest way is to put this RewriteRule first with the [L] flag, so that subsequent rewrites will not be applied.
Otherwise, exceptions for RewriteRule may be specified as RewriteCond matching with %{REQUEST_URI}:
RewriteCond %{REQUEST_URI} !^/?preview/?$ [NC]
Also note that your suggested rule would rewrite both /preview and /preview/ into /preview/index.html, and the first of these rewrites may break relative links unless a redirect is performed.

How to configure mod_proxy to block every site except one

I'm trying to set up mod proxy to block all traffic except to a specific domain. I can configure it to block individual domains using the ProxyBlock directive, and I can block everything using ProxyBlock *. Is there a way to block everything but one domain?
Thanks,
-Andrew
On apache 2.2 you need to have 2 proxy sections.
ProxyRequests On
ProxyVia On
# block all domains except our target
<ProxyMatch ^((?!www\.proxytarget\.com).)*$>
Order deny,allow
Deny from all
</ProxyMatch>
# here goes your usual proxy configuration...
<ProxyMatch www\.proxytarget\.com >
Order deny,allow
Deny from all
Allow from 127.0.0.1
</ProxyMatch>
On apache 2.4 it would be much easier because you could use the If directive instead of that regexp to invert the match for the domain name.
Note: I got that regexp from Invert match with regexp
Try:
ProxyBlock *
ProxyPass <path> <destination>
See if that works.
EDIT: scratch that. I think you have to get creative here with mod_rewrite (the basic reference is at http://httpd.apache.org/docs/current/rewrite/proxy.html):
RewriteCond %{HTTP_HOST} =allowtoproxy.com
RewriteRule ^/(.*)$ http://proxytarget.com/$1 [P]
ProxyPassReverse / http://proxytarget.com/
Try that?
Try this code:
RewriteEngine On
# Testing URLs
RewriteCond %{HTTP_HOST} !google.co.uk [NC]
RewriteCond %{HTTP_HOST} !bbc.co.uk [NC]
RewriteCond %{HTTP_HOST} !amazon.com [NC]
RewriteCond %{HTTP_HOST} !centos.org [NC]
RewriteCond %{HTTP_HOST} !opensuse.org [NC]
# Url to redirect to if not in allowed list
RewriteRule (.*) http://example.org/notallowed.htm

mod_rewrite - redirect from one domain to another and preserve trailing values in url

I think this is a pretty straight forward question in mod_rewrite:
I got one domain, which needs to redirect to another, but keep any value after last slash (/) in the first URL, over to the second.
domain.com/4433 should transfer to domain.com/folder/?p=4333
Listed for clarity:
From: domain.com/4433
To: domain.com/folder/?p=4333
Any ideas?
Edit:
Did some testing, we found the following solution:
RewriteCond %{HTTP_HOST} ^domain.com$
RewriteRule ^([0-9a-z]*)$ /folder/?p=$1 [NC]
sincerely,
- bakkelun
In case you don't really want to redirect but to have pretty URLs, you can use
RewriteEngine On
RewriteRule ^/(.+)$ /folder?p=$1 [L]
This takes everything after the first slash and inserts it at the $1 - but only if there's something after the slash. It doesn't issue a redirect so the users won't notice.
Without any further information, try this:
RewriteEngine on
RewriteRule ^/([^/]+)$ /folder/?p=$1
If you want to use the rule in a .htaccess file, remove the leading slashes.
RewriteEngine On
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^(.*)$ domain.com/folder?p=$1 [R=301,L]
Just in case: domain.com = domain1.com and domain2.com? domain1.com should be redirected to domain2.com? Both run on the same server (optional)?
[EDIT:]
If you really only want to do the thing as stated in the comment, then do the following:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^domain1.com$
RewriteRule ^4433$ http://domain2.com/folder/?p=4433 [R=301,L]
Else, as Benedikt Eger said, or with R=301 if you want real redirection.
Or, if you want it to redirect only on numbers, then do the following:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^domain1.com$
RewriteRule ^([0-9])+$ http://domain2.com/folder/?p=$1 [R=301,L]
RewriteCond checks, if defined vhost is domain1.com, but not domain2.com, then the rewrite rule is applied, and redirects via HTTP status 301 [R=301] only number strings (0-9)+ consisting of at least one number to the specified URL. [L] makes this the last rule applied.

Resources