17

I have the following lines in my haproxy.conf:

acl valid_domains hdr(Host) -i mysite.com images.mysite.com docs.mysite.com admin.mysite.com
redirect location http://mysite.com/invalid_domain if !valid_domains

How do I match any subdomain?

I tried:

acl valid_domains hdr(Host) -i *.mysite.com

and:

acl valid_domains hdr(Host) -i [a-z]+.mysite.com

... But neither worked.

Thanks

Tom
  • 691
  • 3
  • 11
  • 23

3 Answers3

17

I feel that hdr_sub is better for your needs. I was using hdr_end for a while but it runs into the following problem:

requests with port 80 usually get the port stripped so the host header looks like "example.com", but if you were requesting on a port explicitly, like example.com:8080, the header will have the port, and hdr_end will fail the check for "example.com".

hdr_sub will do a substring match, which seems like a better fit for you (and me).

Either solution still has a nasty thing I don't like. Order dependent evaluation of the results.

e.g (my conditions look like this on the frontend)

acl is_dbadmin hdr_sub(host) -i dbadmin.example.com

Requesting on port 8080 would be like this:

Jul  9 02:48:40 localhost haproxy[8]: 192.168.1.1:55870 [09/Jul/2015:02:48:40.865] http-in example/s1 1/0/0/20/110 200 330722 - - ---- 0/0/0/0/0 0/0 {**example.com:8080**||http://example.com:} {Apache/2.4.10 (Debia||||} "GET /wp-includes/js/zxcvbn.min.js HTTP/1.1"

where as port 80 could likely be like this

Jul  9 02:48:40 localhost haproxy[8]: 192.168.1.1:55870 [09/Jul/2015:02:48:40.865] http-in example/s1 1/0/0/20/110 200 330722 - - ---- 0/0/0/0/0 0/0 {example.com||***http://example.com***:} {Apache/2.4.10 (Debia||||} "GET /wp-includes/js/zxcvbn.min.js HTTP/1.1"
Dan Soap
  • 145
  • 7
Rj Wilson
  • 171
  • 1
  • 2
15

There are cases where you need to be explicit about this, such as handling redirects for wildcard SSL with multiple levels of subdomains.

Matching end (hdr_end or -m end) or substring (hdr_sub or -m sub) can have unintended side-effects of matching more than you expect. In many cases this may not really matter, since you don't have traffic for those domains coming to the server, but it doesn't mean it's the technically correct solution.

Using a regular expression is the best way I've found to do explicit matching. For example, if you want to only match *.example.org without matching sub.domain.example.org:

acl valid_domains hdr(host) -m reg -i ^[^\.]+\.example\.org$

If you also want to handle (any) non-standard ports, this can be extended slightly:

acl valid_domains hdr(host) -m reg -i ^[^\.]+\.example\.org(:[0-9]+)?$

The above will match:

  • test1.example.org
  • test2.example.org:8080

and will not match:

  • example.org
  • two.subs.example.org
  • myexample.org
  • test.myexample.org
  • test.example.org.other.com
gregmac
  • 1,459
  • 3
  • 18
  • 27
  • But I want example.org :-) Probably lots do as they map fred.org to www.fred.org ... No pressure to write a new version ... – blissweb Dec 22 '21 at 08:36
14

hdr_end is what you're looking for. Try this:

acl valid_domains hdr_end(host) -i mysite.com 
redirect location http://mysite.com/invalid_domain if !valid_domains
quanta
  • 50,327
  • 19
  • 152
  • 213
  • 1
    what if you have two domains. One called mysite.com and one called notmysite.com? The both end with mysite.com. So the match is not specific enought, right? – Saab Jun 01 '15 at 18:48
  • 3
    @Saab in that case I would write `acl valid_domains hdr(host) -i mysite.com` + `acl valid_domains hdr_end(host) -i .mysite.com`, or just use `acl valid_domains hdr_dom(host) -i mysite.com` – howanghk Aug 27 '15 at 17:55
  • Amazingly this doesn't work if there is a trailing port number, like :90, even howanghk 's answer doesn't work, have to use something like @gregmac 's answer with the regex if using a port other than (80/noport). – blissweb Dec 22 '21 at 08:32