Apache mod_proxy
Apache webserver is a widely deployed modular web server.
One of its module is called mod_proxy. It aims to turn the web server into a proxy / reverse proxy server with load-balancing capabilities.
At HAProxy Technologies, we only use HAProxy :). Heh, what else ???
And during some deployments, customers ask us to migrate Apache mod_proxy configuration into HAProxy.
Present article explains how to translate ProxyPass related rules.
ProxyPass, ProxyPassReverse, etc…
Apache mod_proxy defines a few directives which let it forward traffic to a remote server.
They are listed below with a short description.
Note: I know the directives introduced in this article could be used in much complicated ways.
ProxyPass
ProxyPass maps local server URLs to remote servers + URL.
It applies on traffic from client to server.
For example:
ProxyPass /mirror/foo/ http://backend.example.com/
This makes the external URL http://example.com/mirror/foo/bar to be translated and forwarded to a remote server this way: http://backend.example.com/bar
This directive makes apache to update URL and headers to match both external traffic to internal needs.
ProxyPassReverse
ProxyPassReverse Adjusts the URL in HTTP response headers sent from a reverse proxied server. It only updates Location, Content-Location and URL.
It applies to traffic from server to client.
For example:
ProxyPassReverse /mirror/foo/ http://backend.example.com/
This directive makes apache to adapt responses generated by servers following internal urls to match external urls.
ProxyPassReverseCookieDomain
ProxyPassReverseCookieDomain adjusts the Set-Cookie header sent by the server to match external domain name.
It’s usage is pretty simple. For example:
ProxyPassReverseCookieDomain internal-domain public-domain
ProxyPassReverseCookiePath
ProxyPassReverseCookiePath adjusts the Set-Cookie header sent by the server to match external path.
It’s usage is pretty simple. For example:
ProxyPassReverseCookiePath internal-path public-path
Configure ProxyPass and ProxyPassReverse in HAProxy
Bellow, an example HAProxy configuration to make HAProxy work the same way as apache ProxyPass and ProxyPassReverse configuration. It should be added in the backend section while the frontend ensure that only traffic matching this external URL would be redirected to that backend.
frontend ft_global acl host_dom.com req.hdr(Host) dom.com acl path_mirror_foo path -m beg /mirror/foo/ use_backend bk_myapp if host_dom.com path_mirror_foo backend bk_myapp [...] # external URL => internal URL # http://dom.com/mirror/foo/bar => http://bk.dom.com/bar # ProxyPass /mirror/foo/ http://bk.dom.com/bar http-request set-header Host bk.dom.com reqirep ^([^ :]*)\ /mirror/foo/(.*) \1\ /\2 # ProxyPassReverse /mirror/foo/ http://bk.dom.com/bar # Note: we turn the urls into absolute in the mean time acl hdr_location res.hdr(Location) -m found rspirep ^Location:\ (https?://bk.dom.com(:[0-9]+)?)?(/.*) Location:\ /mirror/foo3 if hdr_location # ProxyPassReverseCookieDomain bk.dom.com dom.com acl hdr_set_cookie_dom res.hdr(Set-cookie) -m sub Domain= bk.dom.com rspirep ^(Set-Cookie:.*)\ Domain=bk.dom.com(.*) \1\ Domain=dom.com\2 if hdr_set_cookie_dom # ProxyPassReverseCookieDomain / /mirror/foo/ acl hdr_set_cookie_path res.hdr(Set-cookie) -m sub Path= rspirep ^(Set-Cookie:.*)\ Path=(.*) \1\ Path=/mirror/foo2 if hdr_set_cookie_path
Notes:
* http to https redirect rules should be handled by HAProxy itself and not by the application server (to avoid some redirect loops)
Hi,
There seem to be a few mistakes in your cookie rewrites:
res.hdr(Set-cookie) should be res.hdr(Set-Cookie)
Domain: bk.dom.com should be Domain=bk.dom.com
Likewise Path: should be Path=
Otherwise it was very helpful.
Cheers,
Pav
Hi Pav,
Thanks for your valuable feedback.
I’ve fixed the article.
Baptiste
Also a lot of cookies do not use capitals in domain and path settings, so the regexes should account for both cases,
i.e.
[Dd]omain=
[Pp]ath=
Cheers,
Pav
Hi Pav,
The directive “rspirep” is case insensitive, so both ‘Domain’ and ‘domain’ should match.
Baptiste
Hello HAProxy experts!
My desire is to create the following:
Interntet -> http://external.com/coolurl -> https://external.com/coolurl -> HAProxy -> http://server.internal.com
Interntet -> http://external.com/another-coolurl -> https://external.com/another-coolurl -> HAProxy -> http://another-server.internal.com
I use the configuration bellow and for some reason it works only with first HTML page and no js or image files are delivered.
Please advice!
SP
frontend coolurl-external
bind :80
mode http
option forwardfo
reqadd X-Forwarded-Proto: http
redirect scheme https code 301 if !{ ssl_fc }
frontend coolurl-secure-external
mode http
bind :443 ssl crt /etc/haproxy/cert.pem no-tls-tickets ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-RC4-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES128-SHA:AES256-SHA256:AES256-SHA:RC4-SHA
option forwardfor
reqadd X-Forwarded-Proto: https
acl secure dst_port eq 443
rsprep ^Set-Cookie: (.*) Set-Cookie: 1; Secure if secure
rspadd Strict-Transport-Security: max-age=31536000 if secure
acl host_external.com req.hdr(Host) external.com
acl path_coolurl path -m beg /coolurl
use_backend coolurl if host_external.com path_coolurl
acl path another_coolurl path -m beg /another-coolurl
use_backend another_coolurl if host_external.com path_another_coolurl
backend coolurl
# external URL => internal URL
# http://external.com/coolurl => http://serverv.internal.com
mode http
# ProxyPass /coolurl http://server.internal.com
http-request set-header Host server.internal.com
reqirep ^([^ :]*) /coolurl(.*) 1 /2
# ProxyPassReverse /coolurl http://server.internal.com
# Note: we turn the urls into absolute in the mean time
acl hdr_location res.hdr(Location) -m found
reqirep ^Location: (https?://server.internal.com(:[0-9]+)?)?(/.*) Location: /coolurl3 if hdr_location
# ProxyPassReverseCookieDomain server.internal.com external.com
acl hdr_set_cookie_dom res.hdr(Set-Cookie) -m sub Domain= server.internal.com
reqirep ^(Set-Cookie:.*) Domain=server.internal.com(.*) 1 Domain= external.com2 if hdr_set_cookie_dom
# ProxyPassReverseCookieDomain / /coolurl
acl hdr_set_cookie_path res.hdr(Set-Cookie) -m sub Path=
reqirep ^(Set-Cookie:.*) Path= (.*) 1 Path= /coolurl2 if hdr_set_cookie_path
option httpchk GET /
server Server-1 10.10.10.10:80 check
backend another_coolurl
….
Hello HAProxy experts!
My desire is to create the following:
Interntet -> http://external.com/coolurl -> https://external.com/coolurl -> HAProxy -> http://server.internal.com
Interntet -> http://external.com/another-coolurl -> https://external.com/another-coolurl -> HAProxy -> http://another-server.internal.com
I use the configuration bellow and for some reason it works only with the first HTML page and no js or image files are delivered.
Please advice!
SP
frontend coolurl-external
bind :80
mode http
option forwardfo
reqadd X-Forwarded-Proto: http
redirect scheme https code 301 if !{ ssl_fc }
frontend coolurl-secure-external
mode http
bind :443 ssl crt /etc/haproxy/cert.pem no-tls-tickets ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-RC4-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES128-SHA:AES256-SHA256:AES256-SHA:RC4-SHA
option forwardfor
reqadd X-Forwarded-Proto: https
acl secure dst_port eq 443
rsprep ^Set-Cookie: (.*) Set-Cookie: 1; Secure if secure
rspadd Strict-Transport-Security: max-age=31536000 if secure
acl host_external.com req.hdr(Host) external.com
acl path_coolurl path -m beg /coolurl
use_backend coolurl if host_external.com path_coolurl
acl path another_coolurl path -m beg /another-coolurl
use_backend another_coolurl if host_external.com path_another_coolurl
backend coolurl
# external URL => internal URL
# http://external.com/coolurl => http://serverv.internal.com
mode http
# ProxyPass /coolurl http://server.internal.com
http-request set-header Host server.internal.com
reqirep ^([^ :]*) /coolurl(.*) 1 /2
# ProxyPassReverse /coolurl http://server.internal.com
# Note: we turn the urls into absolute in the mean time
acl hdr_location res.hdr(Location) -m found
reqirep ^Location: (https?://server.internal.com(:[0-9]+)?)?(/.*) Location: /coolurl3 if hdr_location
# ProxyPassReverseCookieDomain server.internal.com external.com
acl hdr_set_cookie_dom res.hdr(Set-Cookie) -m sub Domain= server.internal.com
reqirep ^(Set-Cookie:.*) Domain=server.internal.com(.*) 1 Domain= external.com2 if hdr_set_cookie_dom
# ProxyPassReverseCookieDomain / /coolurl
acl hdr_set_cookie_path res.hdr(Set-Cookie) -m sub Path=
reqirep ^(Set-Cookie:.*) Path= (.*) 1 Path= /coolurl2 if hdr_set_cookie_path
option httpchk GET /
server Server-1 10.10.10.10:80 check
backend another_coolurl
….
There is either a missing escape in the space, or the space should not be there. I had to escape the space.
reqirep ^([^ :]*) /mirror/foo/(.*) 1 /2
should be
reqirep ^([^ :]*) /mirror/foo/(.*) 1 /2
Hi,
Another type
/mirror/foo3
should be
/mirror/foo3
Thanks for the article.
Regards,
Ben