Search code examples
mod-rewriteapache2.4mod-proxy

RewriteRule includding only last part of REQUESTI_URI


<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


Solution

  • 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]