HAProxy community

Sub directory not redirecting

Hi,

Anyone able to tell me what I’m doing wrong here? Most of my services are run on sub domains and work perfectly, However, for SSO to work I need Plex to be a sub directory. My dashboard service (Organizr) is at mydomain.com, and for plex I have told it to point to mydomain.com/plex. So, the relevant part of my config currently looks something like this:

frontend shared-frontend-merged
	acl			ACL1	var(txn.txnhost) -m str -i mydomain.co.uk
	acl			ACLPlex	var(txn.txnpath) -m beg -i /plex

use_backend Organizr_ipvANY  if  ACL1 
	use_backend Plex_ipvANY  if  ACLPlex 

Yet when I try to access Plex through Organizr I’m faced with a 404 served up by nginx. Have I missed something obvious?

The first backend wins because the ACL1 matches both in both conditions.

Einter switch the use_backend order, or (to be clear) add an if ACL1 !ACPlex for the first one, and ACL1 ACLPlex for the second one.

(Else only by using ACLPlex one could use any domain that points to that IP to access your service.)

Hmm, that makes sense and it has definitely done something. However, both methods are now returning a 401 unauthorized. Does this provide any clue as to where to go from here? Apologies, I’m rather new to HAproxy. I probably should have done this with nginx but I’m so far down the rabbit hole I’d like to get it finished!

Unless you’ve explicitly configured authentication in HAProxy, then the status code 401 most likely is replied by the backend servers (i.e. NGinx or something downstream).

Perhaps paste the entire HAProxy configuration?

Thanks for this, I’m sure you’re going to tell me I’ve done something really strange lol.

 # Generated on: 2019-07-03 16:44
global
maxconn			1000
log			 /var/run/log	syslog	debug
stats socket /tmp/haproxy.socket level admin 
uid			80
gid			80
nbproc			1
hard-stop-after		15m
chroot				/tmp/haproxy_chroot
daemon
tune.ssl.default-dh-param	2048
log-send-hostname		HaproxyMasterNode
server-state-file /tmp/haproxy_server_state

listen HAProxyLocalStats
bind 127.0.0.1:2200 name localstats
mode http
stats enable
stats admin if TRUE
stats show-legends
stats uri /haproxy/haproxy_stats.php?haproxystats=1
timeout client 5000
timeout connect 5000
timeout server 5000

frontend http-to-https
bind			62.20.15.210:80 name 62.20.15.210:80   
mode			http
log			global
option			http-keep-alive
timeout client		30000
acl			mydomain.co.uk-Redirect	var(txn.txnhost) -m beg -i mydomain.co.uk
http-request set-var(txn.txnhost) hdr(host)
http-request redirect scheme https 

frontend shared-frontend-merged
bind			62.20.15.210:443 name 62.20.15.210:443  no-sslv3 force-tlsv12 ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 ssl crt-list /var/etc/haproxy/shared-frontend.crt_list  
mode			http
log			global
option			http-keep-alive
option			forwardfor
acl https ssl_fc
http-request set-header		X-Forwarded-Proto http if !https
http-request set-header		X-Forwarded-Proto https if https
timeout client		30000
acl			ACL1	var(txn.txnhost) -m str -i mydomain.co.uk
acl			ACLPlex	var(txn.txnpath) -m beg -i /plex
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^fileshare\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^grafana\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^matrix\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^nextcloud\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^ombi\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^pfsense\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^portainer1\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^portainer2\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^proxmox\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^radarr\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^riot\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^sonarr\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^ssh\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			aclcrt_shared-frontend	var(txn.txnhost) -m reg -i ^wiki\.mydomain\.co\.uk(:([0-9]){1,5})?$
acl			ACL2	var(txn.txnhost) -m str -i riot.mydomain.co.uk
acl			ACL3	var(txn.txnhost) -m str -i matrix.mydomain.co.uk
acl			ACL4	var(txn.txnhost) -m str -i sonarr.mydomain.co.uk
acl			ACL5	var(txn.txnhost) -m str -i radarr.mydomain.co.uk
acl			ACL6	var(txn.txnhost) -m str -i nextcloud.mydomain.co.uk
acl			ACL7	var(txn.txnhost) -m str -i ombi.mydomain.co.uk
acl			ACL12	req.cook_cnt(organizr_token_b112kkk-hjib-7891-9ed6-e8eb190763f2) gt 0
acl			ACL8	var(txn.txnhost) -m str -i fileshare.mydomain.co.uk
acl			ACL9	var(txn.txnhost) -m str -i grafana.mydomain.co.uk
acl			ACL11	var(txn.txnhost) -m str -i pfsense.mydomain.co.uk
acl			ACL13	var(txn.txnhost) -m str -i proxmox.mydomain.co.uk
acl			ACL18	var(txn.txnhost) -m str -i portainer1.mydomain.co.uk
acl			ACL14	var(txn.txnhost) -m str -i portainer2.mydomain.co.uk
acl			ACL16	var(txn.txnhost) -m str -i ssh.mydomain.co.uk
http-request set-var(txn.txnhost) hdr(host)
http-request set-var(txn.txnpath) path
use_backend Organizr_ipvANY  if  ACL1 !ACLPlex 
use_backend Plex_ipvANY  if  ACL1 ACLPlex 
use_backend Riot_ipvANY  if  ACL2 
use_backend Matrix_ipvANY  if  ACL3 
use_backend Sonarr_ipvANY  if  ACL4  ACL12 
use_backend Radarr_ipvANY  if  ACL5 ACL12 
use_backend Nextcloud_ipvANY  if  ACL6 ACL12 
use_backend Ombi_ipvANY  if  ACL7 ACL12 
use_backend Fileshare_ipvANY  if  ACL12 ACL8 
use_backend Grafana_ipvANY  if  ACL9 ACL12 
use_backend PFsense_ipvANY  if  ACL11 ACL12 
use_backend Proxmox_ipvANY  if  ACL13 ACL12 
use_backend Portainer_ipvANY  if  ACL18 ACL12 
use_backend Portainer2_ipvANY  if  ACL14 ACL12 
use_backend SSH_ipvANY  if  ACL16 ACL12 

backend Organizr_ipvANY
mode			http
id			100
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Organizr 192.168.2.10:8899 id 101 check inter 1000  

backend Plex_ipvANY
mode			http
id			110
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Plex 192.168.1.12:32400 id 101 check inter 1000  

backend Riot_ipvANY
mode			http
id			102
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Riot 192.168.2.10:443 id 101 ssl check inter 1000  verify none 

backend Matrix_ipvANY
mode			http
id			103
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Matrix 192.168.2.10:443 id 101 ssl check inter 1000  verify none 

backend Sonarr_ipvANY
mode			http
id			104
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Sonarr 192.168.1.14:8989 id 101 check inter 1000  

backend Radarr_ipvANY
mode			http
id			105
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Sonarr 192.168.1.14:7878 id 101 check inter 1000  

backend Nextcloud_ipvANY
mode			http
id			106
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Nextcloud 192.168.2.10:8080 id 101 check inter 1000  

backend Ombi_ipvANY
mode			http
id			107
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Ombi 192.168.1.14:3579 id 101 check inter 1000  

backend Fileshare_ipvANY
mode			http
id			108
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Fileshare 192.168.2.10:8000 id 111 check inter 1000  

backend Grafana_ipvANY
mode			http
id			109
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Grafana 192.168.2.10:3000 id 101 check inter 1000  

backend PFsense_ipvANY
mode			http
id			112
log			global
timeout connect		30000
timeout server		30000
retries			3
server			PFsense 192.168.1.1:81 id 101 ssl check inter 1000  verify none 

backend Proxmox_ipvANY
mode			http
id			113
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Proxmox 192.168.1.2:8006 id 101 ssl check inter 1000  verify none 

backend Portainer_ipvANY
mode			http
id			114
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Portainer 192.168.1.14:9000 id 115 check inter 1000  

backend Portainer2_ipvANY
mode			http
id			117
log			global
timeout connect		30000
timeout server		30000
retries			3
server			Portainer2 192.168.2.10:9000 id 115 check inter 1000  

backend SSH_ipvANY
mode			http
id			116
log			global
timeout connect		30000
timeout server		30000
retries			3
server			SSH 192.168.2.10:5800 id 111 check inter 1000

Yup… Very strange…

But before that, quickly looking through your configuration I wouldn’t say that the 401 is from HAProxy, but in fact from one of the backend servers… (I would certainly search there…)

Check the log to see if a server was actually selected.


Now for the “very strange part”:

  • you could give some relevant names to the ACL’s, as it’s almost impossible to trace them…
  • the aclcrt_shared-frontend isn’t used anywhere; moreover it would be useless, as any behaving HTTP(S) client (given that HAProxy listens on only 443), wouldn’t send such a Host header…
  • you use var(txt...) when you don’t need to (because you are using request headers only in the request processing, thus they are available;) (you could use them if you needed these values in response processing;)
  • do not use -m beg with domain names; (as for example whatever.mydomain.co.uk won’t be matched;) (use instead -m dom if I remember correctly;)
  • I don’t think SSH would work this way (unless you have something that proxies between HTTP and SSH);

Well, looks like I have some homework to do! With ACLnames you’re absolutely right and it soon spiralled, changing them is on the list! The rest appears appears to be a combination of tutorials I followed and the options availale in the PFsense package (eg. “host matches”). As for the SSH, I installed an SSH client in docker that serves a web interface, so I can use that to SSH on my lan (as the container makes the requests). I’ll go and do some research in that case, disappointing that it wasn’t a quick fix! Thanks for your time though, appreciated.