HAProxy: How to match on hostname instead of the IP address - haproxy

I am trying to match the host request header and use appropriate backend to route the request.
This is what I want to match on (which does not work):
acl from_external_url req.hdr(Host) -i mydomain.com
# Chrome dev tools network tab does show mydomain.com set as the Host header
However, matching to a direct IP address works (which I don't want):
acl from_external_url req.hdr(Host) -i 22.22.22.22
So, how do I make HAProxy route on hostname instead of the IP?
Update 1:
use_backend oid_external if from_external_url
use_backend oid_internal if !from_external_url

I use the below way to route based on hostname which works as I have about 12 sites going through haproxy.
acl host_mydomain.com hdr(host) -i mydomain.com
use_backend oid_external if host_mydomain.com

Related

Using haproxy to forward or redirect a URL

I am looking to perform something quite simple.
Using haproxy I would like to forward any requests from the URL http://webmail.rutest.org or https://webmail.rutest.org to https://outlook.com/rutest.org
BASICALLY:
We currently own the domain rutest.org. What I intend to do is create a DNS "A" record for "webmail" IP address 24.103.122.18. This will then go to a FortiGate Router which has 2 port forwarding rules for 80 and 443 to an internal IP address 10.1.1.18. 10.1.1.18 will be the haproxy server. Once that request gets there, I want haproxy to say ok, you want http://webmail.rockefeller.edu or https://webmail.rockefeller.edu then send the user to https://outlook.com/rutest.org
The users browser should then reflect this URL redirection.
Can this be done? If so, what are the entries needed in the haproxy.cfg?
You can try the following, untested.
listen webmail
bind :80 v4v6
# here should be your certificates
bind :::443 v4v6 alpn h2,http/1.1 ssl crt /etc/ssl/haproxy/
http-request redirect location https://outlook.com/rutest.org if hdr(host) -i webmail.rockefeller.edu
The documentation: http-request redirect

HAProxy - use_backend if it's available

Is there a way to utilize use_backend with an ACL match, but, in the case the backend is unavailable (down,maint,etc), then use the default?
For example:
# Define hosts
acl host_bacon hdr(host) -i ilovebacon.com
acl host_milkshakes hdr(host) -i bobsmilkshakes.com
## figure out which one to use
use_backend bacon_cluster if host_bacon
use_backend milshake_cluster if host_milkshakes
default_backend web-app-cluster
In the case above, if the bacon and milkshake backends have no available servers, to fall and use web-app-cluster?
Thanks
Yes, it is possible, for example, you could use something like this:
acl host_bacon hdr(host) -i ilovebacon.com
acl host_milkshakes hdr(host) -i bobsmilkshakes.com
# check if bacon & milk ok
acl bacon_cluster_down nbsrv(bacon_cluster) lt 1
acl milks_cluster_down nbsrv(milshake_cluster) lt 1
# use default web-app if backon & milk down
use_backend web-app-cluster if bacon_cluster_down
use_backend web-app-cluster if milks_cluster_down
use_backend bacon_cluster if host_bacon
use_backend milshake_cluster if host_milkshakes
default_backend web-app-cluster
...
Notice the use of nbsrv([<backend>]) : integer
From the docs:
Returns an integer value corresponding to the number of usable servers of
either the current backend or the named backend. This is mostly used with
ACLs but can also be useful when added to logs. This is normally used to
switch to an alternate backend when the number of servers is too low to
to handle some load. It is useful to report a failure when combined with
"monitor fail".
Check for more examples in this HAproxy post: failover and worst case management with HAProxy

Haproxy Route Traffic Based on Querystring

I want to config Haproxy to route traffic based on querystring. In particular...
If /lookup is in the URL, go to xxx.xxx.xxx.xxx
If /related and ?loc= is in the url, go to yyy.yyy.yyy.yyy
If /related and no ?loc=, go to zzz.zzz.zzz.zzz
Any ideas how to do this? Thanks in advance!
You're probably looking for urlp (aka url_param) to fetch sample from query string.
Something like this perhaps?
acl lookup path_beg /lookup
acl related path_beg /related
acl loc urlp(loc) -m found
use_backend xxx if lookup
use_backend yyy if related loc
use_backend zzz if related !loc
NOTE: lookup and related ACLs check if the URL begins with the path (not "in the" path). Also loc ACL checks if the query parameter exists even if it's empty. You need to change it a bit if it doesn't exactly fit your case.

Can I use wildcard SNI matching with HAProxy?

I'm looking around trying to find an example of HAProxy matching SNI wildcards, and my searching is bringing up similarly titled, but unrelated questions about certificates.
Specifically I need to route nonce domains for dvsni with acme / letsencyrpt.
frontend foo_ft_https
mode tcp
option tcplog
bind 0.0.0.0:443
acl foo_app_letsencrypt req.ssl_sni -i *.acme.invalid
use_backend foo_bk_letsencrypt if foo_app_letsencrypt
default_backend foo_bk_default
backend foo_bk_letsencrypt
mode tcp
option tcplog
server foo_srv_letsencrypt 127.0.0.1:3443
backend foo_bk_default
mode tcp
option tcplog
server foo_srv_default 127.0.0.1:8443
Note: all arbitrary names are prefixed with 'foo_' so that the reader can easily distinguish them from keywords, directives and such.
Change
acl foo_app_letsencrypt req.ssl_sni -i *.acme.invalid
to
acl foo_app_letsencrypt req.ssl_sni -m end .acme.invalid
It's not mentioned in the official documentation
https://cbonte.github.io/haproxy-dconv/configuration-1.5.html explicitly, but I was able to find other resources that lead me to the correct result:
https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#7.1.3
http://comments.gmane.org/gmane.comp.web.haproxy/14602
Note that if you were to try the first example, it would "work", but the "" would be interpreted as a literal "", not a wildcard.
Even this is very old question, I would like to share this solution, because this is still among first google's results:
The solution given by CoolAJ86 doesn't work for me (it probably works for older version of HAProxy). You can instead use ssl_fc_sni_end instead of ssl_fc_sni like this:
use_backend apache if { ssl_fc_sni_end domain.com }
It will do the work!

Reduce duplication in haproxy acl with multiple frontend sections

I'm using haproxy with stunnel handling SSL (and using the proxy mode to preserve the original IP from haproxy).
I have several acl tests that redirect to different backends depending on the domain, headers, or path.
The problem is that these are identical whether you're coming in via http or https, but I have to duplicate them in the config. Is there any way to reduce the duplication?
Here's a sample config:
global
user haproxy
group haproxy
#etc...
frontend http-in
bind *:80
acl files_path path_beg /files/
acl beta_host hdr_beg(host) -i beta.
use_backend files if files_path
use backend beta_host
default_backend appservers
frontend https-in
bind *:442 accept-proxy
acl files_path path_beg /files/
acl beta_host hdr_beg(host) -i beta.
use_backend files if files_path
use backend beta_host
default_backend appservers
backend appservers
balance roundrobin
option forwardfor
server appserver_1 localhost:8080 weight 1
server appserver_2 192.168.1.101:8080 weight 1
backend files
balance roundrobin
option forwardfor
server file1 192.168.1.102 weight 1
server file2 192.168.1.103 weight 1
backend beta
balance roundrobin
server beta1 192.168.1.104 weight 1
The http-in and https-in have different ports, and the https-in has to sepcify accept-proxy so that stunnel can use the proxy protocol to pass it the original IP of the user. But other than that they are identical, and should always be identical. Is there any way to reduce this duplication? (haproxy 1.5-dev)
you could simply bind one http in frontend to both.
frontend http-in
bind *:80
bind 0.0.0.0:443 transparent
Unfortunately, haproxy manual (http://haproxy.1wt.eu/download/1.5/doc/configuration.txt) stays that acl can be defined only in frontend, listen and backend sections.
If https and http frontends are same, you can define few bind sentences in one frontend.