HAProxy - rewrite path from domain prefix - url-rewriting

I would like to rewrite path from the domain prefix. With two cases :
https://prefix.domain.com/path -> https://prefix.domain.com/path/#/prefix
https://prefix.domain.com/path1 -> https://prefix.domain.com/path1/#/prefix/home
I try to rewrite the path with this config. But I can not extract prefix from domain in reqirep. I think that reqrep is only for GET /XXXX HTTP/1.1 string, not full URL.
acl match path_end -i /path
acl match1 path_end -i /path1
use_backend traefik_path if match
use_backend traefik_path1 if match1
default_backend traefik_path
backend traefik_path
reqirep ^([^\ ]*\ /)path \1/path/#/??
balance roundrobin
server traefik 127.0.0.1:8000 check
backend traefik_path1
reqirep ^([^\ ]*\ /)path1 \1/path1/#/??/home
balance roundrobin
server traefik 127.0.0.1:8000 check

Related

Setup HTTPs Forward Proxy with HAProxy

In HAProxy, I've used option http-proxy to make it work like forward proxy. This seems to be working fine, but for HTTPS traffic that's not possible.
So, is there any option in the HAProxy configuration that allows to proxy the HTTPS traffic just like Squid does ?
I think the problem is that the option https_proxy isn't available.
This configuration works perfectly for HTTP protocol:
frontend http_proxy
bind :3128
option http_proxy
default_backend proxy_server
backend proxy_server
option http_proxy
Note - I've used the certificate with "ssl crt" along with the bind option but that didn't seem to proxy over HTTPS protocol
This is my Haproxy file configuration, it works well for HTTP and HTTPS protocol.
Here's the code :
#-----------------------------------------------------------------------------
# global
#-----------------------------------------------------------------------------
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL). This list is from:
# https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
# An alternative list with additional directives can be obtained from
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
ssl-default-bind-options no-sslv3
# Tuning if required/needed
# tune.ssl.default-dh-param 2048
#-----------------------------------------------------------------------------
# defaults
#-----------------------------------------------------------------------------
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
#-----------------------------------------------------------------------------
# http frontend
#-----------------------------------------------------------------------------
frontend http-in
bind *:80
# Domain redirect, force the 'www' prefix
redirect prefix https://www.domain1.net code 301 if { hdr_beg(host) -i domain1.net }
redirect prefix https://www.domain2.net code 301 if { hdr_beg(host) -i domain2.net }
# Define hosts
acl is-domain1-site hdr(host) -i www.domain1.net
acl is-domain1-blog hdr(host) -i blog.domain1.net
acl is-domain1-wiki hdr(host) -i wiki.domain1.net
acl is-domain2-site hdr(host) -i www.domain2.net
acl is-domain2-blog hdr(host) -i blog.domain2.net
acl is-domain2-wiki hdr(host) -i wiki.domain2.net
# Force https for domain1
redirect scheme https if is-domain1-site !{ ssl_fc }
redirect scheme https if is-domain1-blog !{ ssl_fc }
redirect scheme https if is-domain1-wiki !{ ssl_fc }
# Force https for domain2
redirect scheme https if is-domain2-site !{ ssl_fc }
redirect scheme https if is-domain2-blog !{ ssl_fc }
redirect scheme https if is-domain2-wiki !{ ssl_fc }
# Default backend (parking)
default_backend bk-ct100
#-----------------------------------------------------------------------------
# https frontend
#-----------------------------------------------------------------------------
frontend https-in
bind *:443 ssl crt /etc/ssl/private/
# Domain redirect force www
redirect prefix https://www.domain1.net code 301 if { hdr_beg(host) -i domain1.net }
redirect prefix https://www.domain2.net code 301 if { hdr_beg(host) -i domain2.net }
# Define hosts for domain1
acl is-domain1-site hdr(host) -i www.domain1.net
acl is-domain1-blog hdr(host) -i blog.domain1.net
acl is-domain1-wiki hdr(host) -i wiki.domain1.net
# Define hosts for domain2
acl is-domain2-site hdr(host) -i www.domain2.net
acl is-domain2-blog hdr(host) -i blog.domain2.net
acl is-domain2-wiki hdr(host) -i wiki.domain2.net
# Figure out which backend to use for domain1
use_backend bk-ct101 if is-domain1-site
use_backend bk-ct101 if is-domain1-blog
use_backend bk-ct101 if is-domain1-wiki
# Figure out which backend to use for domain2
use_backend bk-ct102 if is-domain2-site
use_backend bk-ct102 if is-domain2-blog
use_backend bk-ct102 if is-domain2-wiki
# Default backend (parking)
default_backend bk-ct100
#-----------------------------------------------------------------------------
# ct100 backend - parking
#-----------------------------------------------------------------------------
backend bk-ct100
mode http
option forwardfor
server ct100 192.168.100.100:80 check
#-----------------------------------------------------------------------------
# ct101 backend - domain1
#-----------------------------------------------------------------------------
backend bk-ct101
mode http
option forwardfor
server ct101 192.168.100.101:80 check
#-----------------------------------------------------------------------------
# ct102 backend - domain2
#-----------------------------------------------------------------------------
backend bk-ct102
mode http
option forwardfor
server ct102 192.168.100.102:80 check
#-----------------------------------------------------------------------------
# End-Of-File
#-----------------------------------------------------------------------------
In this configuration, I chose to redirect all traffic from HTTP to HTTPS. All of my certificates are stored inside /etc/ssl/private directory. I generated them using CertBot.
You can adapt this file for your needs but it should work :)

How to redirect only select subdomains in HAProxy?

I have several domains such as abc.blah.com, xyz.blah.com, 2a.blah.com, 3b.blah.com and many more. In my haproxy.cfg file I would like to handle only a few of the domains and leave the rest to go their intended destination.
For example:
Redirect abc and xyz to different destinations
abc.blah.com == 10.1.1.11
xyz.blah.com == 10.1.1.12
But not 2a.blah.com or 3b.blah.com or *.blah.com. Let them be directed to the actual destination.
That means 2a.blah.com should go to 2a.blah.com
here is the haproxy.cfg
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
contimeout 5000
clitimeout 50000
srvtimeout 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http-in
bind 0.0.0.0:80
acl xyz hdr(host) -i xyz.blah.com
acl abc hdr(host) -i abc.blah.com
acl default hdr_end(host) -i .blah.com
## figure out which one to use
use_backend xyz_cluster if xyz
use_backend abc_cluster if abc
use_backend direct_forward if default
# send it to xyz.blah.com
backend xyz_cluster
option forwardfor
server node1 10.1.1.12:8080
# send it to "abc.blah.com"
backend abc_cluster
option forwardfor
server node1 10.1.1.11:8080
# handle 2a.blah.com
# handle 3b.blah.com
# handle *.blah.com
# basically forwarding to the source itself
backend direct_forward
option httpclose
option http_proxy
listen stats :9000
mode http
stats enable
stats hide-version
stats realm Haproxy\ Statistics
stats uri /stats
stats auth test:test123
With this configuration, the requests to xyz and abc are routed correctly.
curl -x 10.148.240.78:80 http://xyz.blah.com
Works fine
But requests to 2a.blah.com are throwing 503
curl -x 10.148.240.78:80 http://2a.blah.com
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
The haproxy log shows the following,
Mar 30 16:48:17 ubuntu-ha-proxy-3289 haproxy[9105]: 10.254.184.246:54533 [30/Mar/2017:16:48:17.793] http-in direct_forward/<NOSRV> 2/-1/-1/-1/2 503 213 - - SC-- 0/0/0/0/0 0/0 "GET http://2a.blah.com HTTP/1.1"
Basically the direct_forward backend needs to be configured to pass the requests to the source domains itself. But it is unclear how it is achieved in haproxy.
Use default_backend <backend> when no "use_backend" rule has been matched.
When doing content-switching between frontend and backends using the
"use_backend" keyword, it is often useful to indicate which backend will be
used when no rule has matched. It generally is the dynamic backend which
will catch all undetermined requests.
frontend http-in
bind 0.0.0.0:80
acl xyz hdr(host) -i xyz.blah.com
acl abc hdr(host) -i abc.blah.com
## figure out which one to use
use_backend xyz_cluster if xyz
use_backend abc_cluster if abc
default_backend direct_forward
Source: https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#default_backend

Redirect to new domain based on path in Haproxy

Hello and thanks ahead of time for the help.
I have a blog on my old site and I'm trying to 301 redirect all of the posts to their new location on my new site using haproxy. For example, I want https://www.oldsite.com/john-blog/blogpost1 to be 301 redirected to https://www.newsite.com/jill-blog/blogpost1.
https://www.oldsite.com/john-blog => https://www.newsite.com/jill-blog
frontend https
option http-server-close
reqadd X-Forwarded-Proto:\ https
acl is_ob path_sub john-blog
redirect location https://www.newsite.com/jill-blog code 301 if is_ob
I've figure out how to forward traffic for /john-blog but haven't been able to figure out how to do the rewrite so that /john-blog/blogpost1 on the old site 301s to /jill-blog/blogpost1 on the new site.
This is what I was able to come up with:
frontend https
option http-server-close
reqadd X-Forwarded-Proto:\ https
acl old_site hdr(host) -i www.oldsite.com
acl john_blog path_beg /john-blog
acl jill_blog path_beg /jill-blog
reqrep ^([^\ ]*\ /)john-blog(.*) \1jill-blog\2 if old_site john_blog
redirect prefix https://www.newsite.com code 301 if old_site jill_blog
The only downside of this config is that it will also redirect https://www.oldsite.com/jill-blog => https://www.newsite.com/jill-blog. If this is an issue I can try and figure something else out.
How is works
I will follow and example for a request to https://www.oldsite.com/john-blog/blogpost1.
In this example acl old_site would be true, acl john_blog would be true and acl jill_blog would be false.
The reqrep line replaces john-blog with jill-blog only if both the old_site and john_blog acls are true, which for this example is the case. After this line the example url would be https://www.oldsite.com/jill-blog/blogpost1.
At this point acl john_blog is now no longer true but acl jill_blog is as the uri now begins with /jill-blog. acl old_site is still true.
The redirect line is in prefix mode where the redirect location is determined by the provided string with the original uri appended. In this example the provided string is https://www.newsite.com and the uri that gets appended is /jill-blog/blogpost1 resulting in a reditect url of https://www.newsite.com/jill-blog/blogpost1.
Hope that helps.

Configuring single Squid server using url query string

Is it possible to use Squid as reverse proxy with multiple web servers based on a query string that is passed to squid proxy?
This is the example from Squid wiki:
acl foo urlpath_regex ^/foo
cache_peer ip.of.server1 parent 80 0 no-query originserver name=server1
cache_peer_access server1 deny foo
cache_peer ip.of.server2 parent 80 0 no-query originserver name=server2
cache_peer_access server2 allow foo
cache_peer_access server2 deny all
This requires me to setup acls per webserver that I want to have, for example:
acl foo urlpath_regex ^/toserver1
acl foo urlpath_regex ^/toserver2
acl foo urlpath_regex ^/toserver3
etc
I'd like to instead specify the webserver my reverse proxy should forward to using a url parameter. For example:
http://myproxyserver.com/?webserver=server1.com&port=8000
http://myproxyserver.com/?webserver=server2.com&port=8900
etc
Is this possible in Squid?

Block all other url's in HAPROXY

I have a couple of rules defined in HAPROXY
acl want_server_oa path_dir ServerOA
acl serveroa_avail nbsrv(ServerOA) ge 1
use_backend ServerOA if want_server_oa serveroa_avail
acl is_root hdr_dom(host) -i mydomain.com
use_backend domainRoot if is_root
The first 3 rules were setup to route traffic to a certain subdomain
mydomain.com/ServerOA/
And the next 2 rules to route traffic to just
mydomain.com/
This works as expected. However, if I type in
mydomain.com/anypath/
It gives me a tomcat 404. I suspect the second set of rules match and forward traffic to tomcat which then returns a 404.
Based on the documentation, I did try defining some acls for blocking all other paths which didn't quite work (configuration wasn't accepted when starting haproxy).
block unless METH_GET or METH_POST want_server_oa
block unless METH_GET or METH_POST is_root
Any help would be much appreciated.
You must explicitly define the items you allow to be accessible under the root "mydomain.com/" and subfolders then block all others. (Shouldn't be a lot, right?)
acl want_server_oa path_beg /ServerOA
acl allow_html path_reg -i /.*\.html
acl allow_styles path_reg -i /css/.*\.css
block unless METH_GET want_server_oa or METH_POST want_server_oa or METH_GET allow_html or METH_POST allow_html or METH_GET allow_styles or METH_POST allow_styles
Additional note: You can check if your configuration have any errors by using the haproxy -c command. Like so:
haproxy -f /etc/haproxy/haproxy.cfg -c

Resources