Server Bug Fix: How to create a reverse proxy to host specified in url?

Original Source Link

I need to configure proxy with apache to proxy requests like

http://example.com/proxy/www.anothersite.com/[some-params]

to

http://www.anothersite.com/[some-params]

I tried to do this like that:

<LocationMatch ^/proxy/(.*)$>
    ProxyPassMatch http://$1
</LocationMatch>

But how can I make all redirects that sends to me remote host go via proxy? For example, if I go to url:

http://example.com/proxy/another-site.com

and another-site.com send me redirect to yet-another-site.com, it shall forward my browser to

http://example.com/proxy/yet-another-site.com

You can use Apache ProxyPassReverse directive for this. You can find its documentation in Apache documentation

I would recommend not using Location or LocationMatch blocks, just use the 2 argument versions of ProxyPass and ProxyPassMatch. So in your case:

ProxyPassMatch ^/proxy/(.*)$ http://$1

However you cannot use Apache configuration to fix back end redirects as there is no corresponging ProxyPassReverseMatch directive (this directive simply cannot work this way). You would need to edit Location, Content-Location and URI headers using the Header directive (which duplicates what the the ProxyPassReverse directive does) and possibly use mod_sed/mod_substitute to fix and hard coded URLs in the HTML.

But it will be messy, very messy. The reason this sort of thing is not easy to do is that in general Apache is not an HTML content aware server, it’s an HTTP aware server, two very different things.

It maybe slightly easier to upgrade to apache v2.4 so you can use mod_proxy_html (which is HTML aware) or write your own handler in mod_lua or similar.

Tagged : / /

Server Bug Fix: REMOTE_USER through Apache reverse proxy

Original Source Link

I have an Apache webserver with mod_proxy enabled and a Virtualhost, proxy.domain.com. This proxy is configured to prompt the user for credentials with AuthType Basic. Then, the content of web.domain.com is available through the proxy with ProxyPass and ProxyReverse. However, the REMOTE_USER variable is empty. I read different things to achieve this with mod_rewrite and mod_headers but all my tries have failed. Does anybody has been luckier than me?

Thanks.

This is possible with mod_headers, mod_rewrite, and mod_proxy.

On the proxy, I assume you have your authentication working and setting REMOTE_USER appropriately. If so, then put the value of REMOTE_USER into a Proxy-User header to the backend like this:

RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER}] # note mod_rewrite's lookahead option
RequestHeader set Proxy-User %{PROXY_USER}e

Here’s what happens:

  1. The RewriteRule fires for every request and sets the environment variable PROXY_USER equal to the value of REMOTE_USER, which should have been set already by an auth module.
  2. The RequestHeader sets a request header named Proxy-User with the value of PROXY_USER

Now on the backend, you can pull that header value and set REMOTE_USER like this:

RewriteCond %{HTTP:Proxy-user} ^(.*)$
RewriteRule .* - [E=REMOTE_USER:%1]

Here’s what happens:

  1. The RewriteCondition checks the value of the Proxy-User header to see if it matches the pattern ^.*$ (which it will). The parentheses tells mod_rewrite to store that value in %1.
  2. The RewriteRule then sets the environment variable REMOTE_USER with the value in %1.

On apache 2.4, trying to get the env vars produced by mod_authnz_ldap and mod_kerb, this is what worked.

Let’s say you are looking for AUTHORIZE_sAMAccountName,

RewriteEngine On
RewriteRule .* - [E=THE_ACCOUNT_NAME:%{ENV:AUTHORIZE_sAMAccountName}] 
RequestHeader set MY_ACCOUNT_NAME %{THE_ACCOUNT_NAME}e

After that, the HEADER can be for example logged:

CustomLog /tmp/custom.log "%h %l %u %t "%r" %>s %b %{MY_ACCOUNT_NAME}i"

References:

On the backend side you can also use standard mod_auth_basic if you don’t want to mess with mod_rewrite. Assuming you pass the user in as X-Remote-User:

<Location />
  AuthBasicFake "%{HTTP:X-Remote-User}" "password"
</Location>

This only works in 2.4 but has the extra benefit of setting up the other aspects of true mod_auth (i.e. PHP’s auth support)

Example to populate header X-Remote-User with the content of REMOTE_USER variable after being authenticated and send that header to a backend proxy (apache 2.4.6).

# Example for Apache 2.4.6

<VirtualHost *:80>

RewriteEngine on
<Location />

    ###############################################
    # Your authentication logic here
    AuthType .......
    AuthName .......
    AuthBasicProvider .......
    .... etc
    Require valid-user
    ###############################################

    RewriteCond %{LA-U:REMOTE_USER} (.+)
    RewriteRule . - [E=RU:%1]
    RequestHeader set X-Remote-User %{RU}e

</Location>

    ProxyTimeout 300
    ProxyPass / http://localhost:81/
    ProxyPassReverse / http://localhost:81/

</VirtualHost>

Tagged : / /

Server Bug Fix: Apache mod_proxy_html Substitute: how to re-use part of regex match? (regex variables?)

Original Source Link

Have a unique URL-rewriting situation in Apache.

I need to be able to take a URL that starts with

"u002f[X]"

or

'u002f[X]"

Where X is the rest of some URL,
and substitute the text

"u002fmeis2u002f[X]

I’m not sure how the Regex works in Apache — I think it’s the same as Perl 5? — but even then I’m a little unsure how this would be done. My hunch is that it has to do with Regex grouping and then using $1 to pull the variable out, but I’m entirely unfamiliar with this process in Apache.

Hoping someone can help — thanks!

I’m not sure what the proxy part has to do with this but you can do this with mod_rewrite.

RewriteRule ^/(.*) /meis2/$1

I’m assuming here that by “u002f” you mean “/” and you mean the brackets “[]” to be part of the substitution and not in the actual URL.

EDIT

Ok, since you mean you want to rewrite the HTML output with mod_proxy_html. Then I think it would be something like this.

ProxyHTMLURLMap ^\u002f(.*) u002fmeis2u002f$1 R

Tagged : / / /

Server Bug Fix: Apache 2.4.7 mod_proxy_wstunnel tunneling too much (HTTP as well as WS)

Original Source Link

I’m running Apache 2.4.7 as a reverse proxy on Ubuntu 14.04 LTS. This Apache server acts as the entrypoint to a lot of different backend applications, which are accessed via different mod_proxy configurations in <Location> blocks

I need to provide reverse proxy access to an application that uses WebSockets. The application is a Java Spring application that serves HTML and other static files over HTTP, and then uses a WebSocket for dynamic data after the page has loaded.

I’ve got the application running behind Nginx using the following config:

location /newapp/ {
    proxy_pass http://newapp.example.com:8080/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Unfortunately, due to needing an Apache authentication module that isn’t available on Nginx, I can’t use this in production.

What I want to do, in pseudo-Apache-config is:

<Location /newapp/>
    if not WebSockets:
        ProxyPass http://newapp.example.com:8080/
        ProxyPassReverse /
    else
        ProxyPass ws://newapp.example.com:8080/
        ProxyPassReverse /
</Location>

The Apache mod_proxy_wstunnel module makes me think that this should be possible. The WebSocket is accessed on the URL /api/socket/..., so I’ve tried separating the two types of ProxyPass using separate <Location> blocks:

<Location /newapp/>
    ProxyPass http://newapp.example.com:8080/ disablereuse=on
    ProxyPassReverse /

    ProxyPassReverseCookieDomain newapp.example.com apps.example.com
    ProxyPassReverseCookiePath http://newapp.example.com:8080/ /newapp/
</Location>

<Location /newapp/api/socket/>
    ProxyPass ws://newapp.example.com:8080/api/socket/
    ProxyPassReverse /
</Location>

This works initially – the browser requests http://apps.example.com/newapp/, the page loads over HTTP, the static assets are loaded, the JavaScript code connects to the websocket, everything is awesome.

However, when a new request is made over HTTP – say, for GET /newapp/static/someimage.png, something goes wrong. This request doesn’t match against the WebSocket Location, so I would expect it to proxy GET /static/someimage.png through to http://newapp.example.com:8080/.

Instead, the application server receives a request for GET /newapp/static/someimage.png and returns a 404, as this isn’t a URL that it’s aware of. This breaks the application, as HTTP requests that should work fail instead.

Notes:

  • This doesn’t just occur for images – GET /newapp/api/ajax/someapicall also gets proxied through incorrectly.
  • This doesn’t always happen. While testing things to complete this question I managed to get the app to completely work. It might have been time based – I left the app running without interacting with it for a few minutes before making any new HTTP requests. When I did make new HTTP requests, they went through correctly.
  • Disabling the <Location /newapp/api/socket/> section causes two things to happen – the WebSocket fails to connect, and the HTTP requests continue to work.
  • I discovered this issue after refreshing the page via the browser’s Refresh button. Instead of the page loading again, I saw the app’s 404 screen.

What I think is happening:

I think mod_proxy_wstunnel, once activated by the first request to match /newapp/api/socket/, is taking over for all further inbound requests from the client, whether they match the Location or not. I tested this by adding a RequestHeader set Test "some_identifying_value" directive to each Location – the HTTP requests for static files & for /api/socket/info had the Test header on them, but the incorrectly-proxied HTTP requests did not have a Test
header on them, which suggests that they are being passed straight through without being processed by the Apache directives.

Ultimately, my question is this: Is it possible to configure any version of Apache (I’m happy to upgrade!) to reverse-proxy WebSocket-based applications in such a way that HTTP requests are also reverse-proxied correctly after the WebSocket has connected? If so, how is this configured?

anders’ answer got me 95% of the way there.

The basic scenario:

  • We have a server on newapp.example.com
  • Port 8080 is running both HTTP and WebSockets
  • The URL that responds to WebSockets requests is /api/socket/
  • We’re reverse-proxying this application as http://apps.example.com/newapp/

This is how to configure WebSockets and HTTP reverse-proxying for the above scenario in a <Location> block:

<Location /newapp/>
    ProxyPass http://newapp.example.com:8080/
    ProxyPassReverse /

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /api/(.*) ws://newapp.example.com:8080/api/$1 [P]
</Location>

The final rewrite rule is crucial – without it, we’ll pass the request /newapp/api/socket through to the WebSocket server – which it will reject.

The regex is parsing out everything after api – there might be a better way to capture that block, but this worked. We then have to remember to re-add /api/ to the final redirect URL.

Most importantly, HTTP requests continue to work after the WebSocket connection is established!

I’m using apache 2.4 as a proxy in front of my spring boot app, this app serves some rest api calls, websockets (sockjs) and some static pages. I had some problems getting the websocket to work, the secret there was to add the rewrite rules you see below, now it works for me, my apache virtual host config looks like this:

<VirtualHost *:443>
  SSLEngine on
  SSLCertificateFile /etc/httpd/ssl/my.crt
  SSLCertificateKeyFile /etc/httpd/ssl/my.key
  SSLCertificateChainFile /etc/httpd/ssl/intermediate.crt
  ProxyPreserveHost On
  ProxyPass / http://127.0.0.1:8080/
  ProxyPassReverse / http://127.0.0.1:8080/
  ProxyRequests Off
  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
  RewriteRule .* ws://localhost:6868%{REQUEST_URI} [P]
  ServerName my.dnsname.com
</VirtualHost>

Tagged : / / /

Server Bug Fix: Apache ProxyHTMLURLMap with string substitution from LocationMatch

Original Source Link

I am trying to build an Apache reverse proxy to make a set of servers accessible through a single point of access. The servers all offer a web admin interface on port 3000, and I intend to present all of them as directories on the reverse proxy. The interfaces contain local links which must of course be rewritten to go to the correct server’s subdirectory on the proxy.

I can achieve the required behaviour with configuration snippets like this for each server individually:

<Location /testadmin-warsaw/>
        ProxyPass http://warsaw.example.com:3000/
        ProxyPassReverse /
        ProxyHTMLEnable  On
        ProxyHTMLURLMap  / /testadmin-warsaw/ L
        RequestHeader    unset Accept-Encoding
</Location>

As this gets rather tedious and error-prone as servers come and go, I am aiming for a dynamic configuration.
According to the Apache documentation, the following should work:

<LocationMatch "^/testadmin-(?<OFFICENAME>w+)/(.*)$">
        ProxyPassMatch   http://$1.example.com:3000/$2
        ProxyPassReverse /
        ProxyHTMLEnable  On
        ProxyHTMLInterp  On
        ProxyHTMLURLMap  / /testadmin-${env:MATCH_OFFICENAME|unknown}/ VL
        RequestHeader    unset Accept-Encoding
</LocationMatch>

<LocationMatch> would set the environment variable MATCH_OFFICENAME to the office name part of the directory, and ProxyHTMLURLMap would insert this name at the appropriate place in the rewritten links.

But when I test that configuration, a link originally pointing to /other/page.html is rewritten to /testadmin-unknown/other/page.html instead of /testadmin-warsaw/other/page.html as intended. In other words, ProxyHTMLURLMap acts as if the environment variable MATCH_OFFICENAME was unset.

If I omit the env: part and put just /testadmin-${MATCH_OFFICENAME}/ as the to-pattern, Apache logs a warning: “AH00111: Config variable ${MATCH_OFFICENAME} is not defined”.

Where’s my mistake?

The syntax without env: is correct.
The AH00111 warning message it produces is spurious, as per Apache Bug #58467.

The configuration:

<LocationMatch "^/testadmin-(?<OFFICENAME>w+)/(.*)$">
        ProxyPassMatch   http://$1.example.com:3000/$2
        ProxyPassReverse /
        ProxyHTMLEnable  On
        ProxyHTMLInterp  On
        ProxyHTMLURLMap  / /testadmin-${MATCH_OFFICENAME|unknown}/ VL
        RequestHeader    unset Accept-Encoding
</LocationMatch>

works as intended, except for the spurious warning at each startup.

Tagged : / /

Server Bug Fix: Apache and PHP-FPM security with mod_proxy_fcgi

Original Source Link

I use PHP-FPM in a shared hosting configuration. Each FPM pool runs as a different user. Apache runs as www-data. Apache connects via a socket using mod_proxy_fcgi. I allow users to use .htaccess files.

How do I prevent a user from connecting to the wrong FPM pool?

The vhost looks something like this:

<VirtualHost *:80>
        ServerName foo.com
        DocumentRoot /var/www/sites/foo.com/html
        <FilesMatch ".php$">
                SetHandler "proxy:unix:/var/run/foo-com-fpm.sock|fcgi://localhost"
        </FilesMatch>
</VirtualHost>

But, the foo-com user can easily override that handler from his .htaccess:

<FilesMatch ".php$">
        SetHandler "proxy:unix:/var/run/bar-com-fpm.sock|fcgi://localhost"
</FilesMatch>

This would allow him to run PHP scripts as a different user. How can I prevent that, without disallowing FileInfo overrides?

AllowOverrideList allows to further restrict .htaccess directives to the specified list.

Quote from the docs:

When this directive is set to None and AllowOverride is set to None,
then .htaccessfiles are completely ignored. In this case, the server
will not even attempt to read .htaccess files in the filesystem.

Example:

AllowOverride None
AllowOverrideList Redirect RedirectMatch

In the example above, only the Redirect and RedirectMatch directives
are allowed. All others will cause an internal server error.

Example:

AllowOverride AuthConfig
AllowOverrideList CookieTracking CookieName

In the example above, AllowOverride grants permission to
the AuthConfig directive grouping and AllowOverrideList grants
permission to only two directives from the FileInfo directive
grouping. All others will cause an internal server error.

Tagged : / / / /

Server Bug Fix: Route traffic from certain site/url to a number of hand-picked nodes in a load balanced environment

Original Source Link

I inherited a loadbalancer (mod_proxy) setup consisting of 5 nodes.

The setup serves a number of 6 sites (site1, site2 etc, with shared disk space) and would like to know if there is a way to route traffic to only 2 of the nodes, namely 4 and 5 based on the site/url requested.

For example, what configuration do I have to include to mod_proxy config to only route traffic destined to say site3 (for example, www.site2.com/profile) to only nodes 4 and 5?

Have you ever done something similar?

Thank you in advance.

So you are looking for a Layer7 Load Balancer? So as below

site.com/Page1 = Server1/2
site.com/Page2 = Server3/4

Something like that? If so, please refer to the below link

https://httpd.apache.org/docs/2.4/mod/mod_proxy.html

Tagged : / /

Server Bug Fix: Apache2 mod_substitute not working in

Original Source Link

I have a working Reverse Proxy that is active only on a specific Location in my site, in this case for example: www.example.com/reverseproxy/site1 I am reverse proxying site1. I want to replace some part of the body of every page that is proxied so I tried to use mod_substitute, the problem is that I can’t get it to work under <Location /reverseproxy>

This is my httpd (SSL is enabled):

<VirtualHost _default_:443> 

    ProxyPassInterpolateEnv On
    RewriteEngine On

    ... Some rewrite rules
    RewriteRule /?reverseproxy/http(s*):/([^/]*)/*(.*) "http$1://$2/$3" [P]
    SSLProxyEngine On
    ProxyPassReverse "/reverseproxy/http${ssl}://${page}" http${ssl}://${page} interpolate

    SetOutputFilter INFLATE;proxy-html;SUBSTITUTE;DEFLATE;
    ProxyHTMLInterp On
    ProxyHTMLExtended Off

    ...Some ProxyURLMap
    AddOutputFilterByType SUBSTITUTE text/html
    Substitute "s|<body>|<body1>|"
</VirtualHost>

This substitute does work but it applies to all the pages and not only to /reverseproxy. When I try to put it in <Location /reverseproxy> it does not work, it just ignores it:

<Location /reverseproxy>
AddOutputFilterByType SUBSTITUTE text/html
Substitute "s|<body>|<body1>|"
</Location>

What I tried:

I tried adding

 RequestHeader unset Accept-Encoding

outside the <Location> tag but it didn’t work

I tried then adding this

SetOutputFilter SUBSTITUTE;DEFLATE

in the <Location /reverseproxy> tag but no luck

And as someone suggested tried with this filterchain

FilterDeclare filter
FilterProvider filter SUBSTITUTE "%{CONTENT_TYPE} =~ m|^text/html|"
FilterDeclare unpackGZIP
FilterProvider unpackGZIP INFLATE "resp('Content-Encoding') == 'gzip'"

<Location /reverseproxy>
FilterChain unpackGZIP filter DEFLATE

Everything else inside the Location works, it just seems to ignore the substitution.

Tagged : / / / /

Server Bug Fix: Lighttpd reverse proxy HTTPS to another server on HTTP

Original Source Link

I’ve a Lighttpd server running on HTTPS, and I want to have one subdirectory on the server act as a reverse proxy for a separate server that runs on HTTP. I’ve tried following guides on doing both proxy and url rewrite, but something to do with how the SSL is set up is interfering.

$SERVER["socket"] == ":81" {
    url.rewrite-once = ( "^/directory/(.*)$" => "/index.html" )
    proxy.server  = ( "" => ( "" => ( "host" => "192.0.0.1", "port" => 123 )))
}

$HTTP["scheme"] == "http" {
     $HTTP["host"] =~ ".*" {
        url.redirect = (".*" => "https://%0$0")
     }
}

$SERVER["socket"] == ":443" {
        ssl.engine = "enable"
        ssl.ca-file = "/etc/lighttpd/fullchain.pem"
        ssl.pemfile = "/etc/lighttpd/server.pem"
        $HTTP["url"] =~ "^/directory/" {
               proxy.server = ( "" => ( "" => ( "host" => "127.0.0.1", "port" => 81)))
        }
}

My intention was that going to /directory/ would redirect you to the 192.0.0.1:123/index.html. I followed this guide which mentioned doing the first redirect to port 81, then redirecting port 81 to the second server.

This doesn’t seem to work and just gets stuck in a redirection loop, and always returns a 301 to the https site.

If I don’t do the :81 redirect, I can get the bottom proxy.server to redirect to the right place, but it keeps the /directory/ ending which doesn’t get to where I need it.

Thanks.

lighttpd 1.4.46 and later have a feature in mod_proxy which allows remapping url-path prefixes. See the ‘proxy.header’ directive and “map-urlpath” sub-option.

https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModProxy

This feature avoids the double-proxy config you are trying to use.

lighttpd 1.4.46 was released just over a year ago and the latest lighttpd release is lighttpd 1.4.51.

Tagged : / / /

Server Bug Fix: Configure Apache Web Server (shared hosting) to provide simultaneous Web and Websocket Access

Original Source Link

I’m trying since some days to find a way to configure simultaneous websocket and web server connections with one same Apache Web Server I have on a shared hosting basis. Now, before giving that up and definitely switching to a dedicated hosting contract with my host, I want to be sure that this is actually not possible.

What I’ve tried so far:

Installing a reverse proxy in front of my web server, and create websocket chat application (most likely in node.js, tried with ratchet in PHP, but node seems to be the better choice) on the same apache server, listening on a different port than the web server.
Problem: I have no root access, so I can’t change the port at which my apache web server is listening, meaning that I can’t actually “place” my NGINX reverse proxy in front of my web server.

What may works, but I have no idea how that works:

I found out about https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html, the extension for Websockets for Apache Servers, and may Apache version (2.4) of my web server would support that. However, can I actually 1) configure this extension without root access 2) use it to make simultaneous websocket & web server connections via my only apache web server work?

Thanks in advance for any help / other ways to may figure this out (guess the mod_proxy_wstunnel extension is kind of my last chane)!

Tagged : / / / /