# HAProxy URL rewrite question/issue …

**URL:** <https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204>\
**Category:** Help!\
**Created:** [December 8, 2022, 9:44am UTC](https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204 "2022-12-08T09:44:57Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Opper](https://avatars.discourse-cdn.com/v4/letter/o/b5a626/32.png) [@Opper](https://discourse.haproxy.org/u/Opper)\
**Post date:** [December 8, 2022, 9:44am UTC](https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204/1 "2022-12-08T09:44:57Z")

</div>

HAProxy version: v2.6.6

URL Frontend: [http://haproxyserver.domain.com/application1](http://haproxyserver.domain.com/application1)  
URL Backend: [https://appserver1.otherdomain.com/](https://appserver1.otherdomain.com/)

What I’m trying to achieve is that when a user visits [http://haproxyserver.domain.com/application1](http://haproxyserver.domain.com/application1), HAProxy gets the page at [https://appserver1.otherdomain.com/](https://appserver1.otherdomain.com/) and send it back as [http://haproxyserver.domain.com/application1](http://haproxyserver.domain.com/application1)

So, I want to rewrite “/application1” from the front to “/” in the back and send the response back as “/application1”. E.g. an image on the backend like [https://appserver1.otherdomain.com/images/test.jpg](https://appserver1.otherdomain.com/images/test.jpg) should be send back as [http://haproxyserver.domain.com/application1/images/test.jpg](http://haproxyserver.domain.com/application1/images/test.jpg) and so on.

My haproxy.cfg file without any rewrite config in it:

```auto
#---------------------------------------------------------------------
# PRD http frontend which proxys to the backends
#---------------------------------------------------------------------
frontend PRD-http-front
    bind *:80
    http-request add-header X-Forwarded-For %[src]
    http-request add-header X-Forwarded-Proto http

    mode http
    option httplog
    option forwardfor except 127.0.0.0/8
    maxconn 10240

    # define acl's
    acl host_haproxy-stats hdr(host) -i haproxy-stats.domain.com

    ###################################
    ### decide which backend to use ###
    ###################################
    # HAProxy statistics page
    use_backend haproxy-stats if host_haproxy-stats

    # Other
    use_backend application1 if { path_beg /application1 }

    # default backend
    default_backend PRD-local-httpd

#---------------------------------------------------------------------
# haproxy-stats backend
#---------------------------------------------------------------------
backend haproxy-stats
    mode http
    option httpclose
    option forwardfor
    http-request add-header X-Forwarded-For %[src]
    http-request add-header X-Forwarded-Proto http
    server haproxy-stats 127.0.0.1:8888 check

#---------------------------------------------------------------------
# PRD-local-httpd backend
#---------------------------------------------------------------------
backend PRD-local-httpd
    mode http
    option httpclose
    option forwardfor
    http-request add-header X-Forwarded-For %[src]
    http-request add-header X-Forwarded-Proto http
    server HAProxy-Server haproxyserver.domain.com:8081 check

#---------------------------------------------------------------------
# application1 backend
#---------------------------------------------------------------------
backend application1
    mode http
    option httpclose
    option forwardfor
    http-request add-header X-Forwarded-For %[src]
    http-request add-header X-Forwarded-Proto http
    server appserver1 appserver1.otherdomain.com:443 check ssl verify none

```

This config doesn’t work because HAProxy will try to load [https://appserver1.otherdomain.com/application1](https://appserver1.otherdomain.com/application1) in the backend, which doesn’t exist. I Already tried several rewrite settings in the backend config part without any success. Some examples:

```auto
http-request replace-path ^([^\])\ /application1/(.) \1\ /\2
http-request replace-path /application1(.*) / \1
http-request set-path %[path,regsub(^/application1/?,/)]

```

I Even tried this in the frontend:

```auto
acl app1 path_beg -i /application1/
http-request set-path /%[path] if app1

```

I Googled for hours and tried many things but I can’t figure it out. Every help is much appreciated!

---

<div class="post-metadata">

**Author:** ![stormrover](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.haproxy.org/stormrover/32/1847_2.png) [@stormrover](https://discourse.haproxy.org/u/stormrover)\
**Post date:** [December 10, 2022, 12:15pm UTC](https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204/2 "2022-12-10T12:15:34Z")

</div>

It sounds like you need to modify responses to add back the path when HAProxy responds on behalf of the backend server. This is typically done in the `Location` header.

A word of caution: Some apps will let you play with this. Others send file payloads that include a relative path as the app expects it, so modifying the location header causes a mismatch and breaks things.

Assuming your app allows you to play with the Location header, I think you’re looking for something like this in your backend:

```auto
backend application1
    http-request replace-path /application1(.*) / \1
    http-response set-header Location /application1%[path]

```

That’s just an example. You may need to play around with the values a bit to get it to work.

---

<div class="post-metadata">

**Author:** ![Opper](https://avatars.discourse-cdn.com/v4/letter/o/b5a626/32.png) [@Opper](https://discourse.haproxy.org/u/Opper)\
**Post date:** [December 13, 2022, 11:16am UTC](https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204/3 "2022-12-13T11:16:03Z")

</div>

Thank you very much for your reply and effort.  
Unfortunately, the config gives an error when validating the config file:

error detected in backend ‘application1’ while parsing ‘http-response set-header’ rule : sample fetch \<path]\> may not be reliably used here because it needs ‘HTTP request headers’ which is not available here.

---

<div class="post-metadata">

**Author:** ![stormrover](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.haproxy.org/stormrover/32/1847_2.png) [@stormrover](https://discourse.haproxy.org/u/stormrover)\
**Post date:** [December 13, 2022, 11:41am UTC](https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204/4 "2022-12-13T11:41:15Z")

</div>

😉

> [@stormrover](#):
>
> That’s just an example. You may need to play around with the values a bit to get it to work.

This passes configuration checks on my instance of HAProxy. I’m not set up for what you’re trying to do, so I’m not able to test it for actual functionality.

```auto
backend application1
    # Removes /application1 before sending it to backend.
    http-request replace-path /application1(.*) \1
    # Adds /application1 to location on response from backend.
    http-response replace-header Location (.*) /application1/\1

```

Once again, there’s a good chance your application won’t like a proxy doing this as it messes with relative paths. I pulled something like this off for a little while by removing `/admin` from the pi-hole web interface, but an update broke it. I ended up having to let the app set its own paths. If your application supports setting its own paths, that’s the best way to accomplish this.

---

<div class="post-metadata">

**Author:** ![Opper](https://avatars.discourse-cdn.com/v4/letter/o/b5a626/32.png) [@Opper](https://discourse.haproxy.org/u/Opper)\
**Post date:** [December 13, 2022, 11:51am UTC](https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204/5 "2022-12-13T11:51:36Z")

</div>

With this settings the config validates but just gives “Bad Request”.  
Like you said: I’ll experiment some more with the values to see if I can get it to work.  
I’m well aware that it might never work if paths are not all relative and even then it still might not work. I Will also contact the app vendor to see if they can help by changing their web config to serve from a subfolder.

Thank you very much once again for your time and effort! Much appreciated!

---

<div class="post-metadata">

**Author:** ![denny](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.haproxy.org/denny/32/1875_2.png) [@denny](https://discourse.haproxy.org/u/denny)\
**Post date:** [May 26, 2023, 6:54am UTC](https://discourse.haproxy.org/t/haproxy-url-rewrite-question-issue/8204/6 "2023-05-26T06:54:50Z")

</div>

hi,

did you get it working ? I have the exact same issue and it is working on the old setup:

- Global frontend

```auto
...
acl app1 url_beg eq /app1

...
use_backend appint if app1

```

- backend from app server (VM with Nginx … classical way) , which contains several apps

```auto
    balance leastconn
    log global
    mode http
    option forwardfor
    stick-table type ip size 1m expire 2m
    acl app1 url_beg eq /app1
    acl app2 url_beg eq /app2
    acl valid_method method GET POST HEAD
    acl response-is-redirect res.hdr(Location) -m found
    http-request set-header Host fra-test-app1.test.local if app1
    http-request set-header Host fra-test-app2.test.local if app2
    http-request replace-uri ^/app1/(.*) /\1 if app1 valid_method
    http-request replace-uri ^/app2/(.*) /\1 if app2 valid_method
    http-response replace-header ^Location (http|https)://fra-test-app1.test.local\/(.*) Location:\ \1://%[hdr(host)]/app1/\2 if response-is-redirect
    http-response replace-header ^Location (http|https)://fra-test-app2.test.local\/(.*) Location:\ \1://%[hdr(host)]/app2/\2 if response-is-redirect

```

This setup works and I get the /app1/… or /app2/… on the global frontend. The difference on the new setup is, that App server is not a classical Nginx host, but Docker (Nginx → PHP-fpm).

If I try the same ruleset, then the /app1 is removed before it reaches the Docker container, but not readded before the global frontend. So images / css and co failing because of the missing “/app1”

I tried also very long … and I don’t understand … what the issue is … the only thing I can imagine is, the Hostname from the Nginx in Docker …

**ISSUE FOUND**

After a looooot of debug … I’ve found the issue: it was never working that way, we have on the classical setup … these rules where not used at all, except `http-request replace-uri ^/app1/(.*) /\1 if app1 valid_method`. The backend apps are Symfony and they have a param called `virtual_directory` whtih was set on the VMs to `app1/`, but that wasn’t the case on the Docker image. After setting it there too … it started working 🙂

Hours wasted …
