This is a duplicate of my SO question. You can answer there too, to get the reputation. Hope this doesn’t violate some rule.
I wanted to setup HAProxy for two servers - one with passthroug one with termination. I was able to do it with no previous experience of HAProxy, but I am unable to make HTTPS redirect for the terminating one - I get 502. Here is the config:
#Upgrades the passthrough and check for Let's Encrypt
frontend http_front
bind :80
option forwardfor
acl host_s1 hdr(host) -i s1.example.com
acl path_le path_beg -i /.well-known/acme-challenge/
redirect scheme https code 301 if host_s1 !path_le
use_backend acmetool if path_le
default_backend http-back
#Handles the passthrough and loopsback to itself for other domains
frontend passthrough
mode tcp
bind :443
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend service1 if { req_ssl_sni -i s1.example.com }
default_backend https-back
#Loopback to handle the termination domains
frontend https-front
bind 127.0.0.1:8443 ssl crt s2.example.com.pem
option forwardfor
reqdel X-Forwarded-Proto
reqadd X-Forwarded-Proto:\ https if { ssl_fc }
use_backend service2 if { req_ssl_sni -i s2.example.com }
default_backend service2
#returns for second pass from HTTP
backend http-back
server https-front 127.0.0.1:8443
#returns for second pass from HTTPS
backend https-back
mode tcp
server https-front 127.0.0.1:8443
backend service1
mode tcp
server service1 127.0.0.1:8888
backend service2
#redirect scheme https code 301 if !{ ssl_fc }
server server2 server2:80
backend acmetool
server acmetool 127.0.0.1:81
Not sure if I need those reqdel/reqadd in https-front. Or if I have to do tcp-request again on the second pass for HTTPS.
Uncommenting the redirect on the backend does not help either.
I also had send-proxy-v2 to the initial backends with no change in the result. I am not experienced enough in either Linux or HAproxy to know hoe to use sockets, so I replaced them with ports for the loop-back. Would love to know if there is any difference in efficiency between them.
Share the entire configuration please; we need to know what default and global settings are set.
Also enable logging and provide the output when the requests fails.
A few comments:
the backend http-back makes no sense, what are you trying to achieve there? You are sending cleartext traffic (HTTP) to a HTTPS port, that’s not going to work
in frontend https-front the fetch must be ssl_fc_sni instead of req_ssl_sni, because your terminating SSL here. But the entire use_backend statement is unnecessary anyway, default_backend is enough unless you have other needs
can you confirm server2 responds to HTTP request on port 80?
I used the default settings of the installation:
global
maxconn 64
chroot /var/lib/haproxy
stats socket /run/haproxy.sock mode 660 level admin
stats timeout 30s
user root
group root
daemon
I am not sure how to enable the logging as I am using a customized Debian distro (DietPi.com) that don’t seem to have rsyslog enabled by default. Is there a way to monitor the output without logging service?
As for the comments:
backend http-back is required since I am using different modes in frontend http_front and backend https-back so I cannot use just one.
I thought looping back like this would be possible workaround. I also thought that the HTTP will get upgraded when sent to the frontend that terminates the connection. This is the main problem I have redirecting both types of connections - terminating and passthrough.
Thanks, updated it. It’s not needed now, but I would possibly have other services in the future, so I’m preparing it. This way I won’t have to search again for the required setup
it does work when accessed from the local network and also when accessed with a portforward from the internet. It also works when accessing directly with https://s2.example.com
You log it to some destination IP and trace the syslog message with tcpdump or wireshark. Use the capture filter udp port 514.
My problem is that I don’t know what you would like to do here. Can you explain? Would you like to encapsulate this to HTTPS and keep using HTTP on the frontend?
Then modify your backend like this:
#returns for second pass from HTTP
backend http-back
server https-front 127.0.0.1:8443 ssl verify none
Sorry for not being able to explain my problem properly. I’ll try again:
I have two services s1.example.com and s2.example.com pointed to this HAProxy.
S1 is handling TLS itself so I use passthrough for it (frontend passthrough) and I also have:
Which redirects any HTTP to HTTPS for this server. This works fine and without errors.
S2 cannot handle TLS itself, so i have to terminate on the HAProxy with frontend https-front. I created additional backend https-back and frontend https-front to handle the loopback for the second pass. Due to the difference in the modes, I had to create additional backend http-back or I get error in the configuration.
This though is insufficient since I get 502 when accessing HTTP. But HTTPS works fine.
Your suggestion partially fixed my issue - now when I access s2.example.com on HTTP, I am do not get the 502 error message. But it does not get redirected to HTTPS either - I just get HTTP traffic.
So my question is where could I do another redirect/upgrade of the connection so it will automatically go to HTTPS when accessing S2 over HTTP?
P.S. after writing this I tested with:
backend http-back
redirect scheme https code 301 if !{ ssl_fc }
server https-front 127.0.0.1:8443 ssl verify none
and this seems to do the redirect properly.
I would appreciate any further comments if something is not done properly. And if there is any advantage if using sockets instead of ports for the loopback.
I understand. I did it like this because I merged two separate configs found online and did not understood the loopback idea and the redirect clause quite well. Now, after your help, it’s more clear
Here is the final setup for anyone interested with updated names to better reflect the logic behind them:
#Upgrades to HTTPS unless it's Let's Encrypt
frontend http
bind :80
option forwardfor
redirect scheme https code 301 if !{ path_beg -i /.well-known/acme-challenge/ }
default_backend acmetool
#Handles the passthrough and loopsback for termination
frontend passthrough
mode tcp
bind :443
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend service1 if { req_ssl_sni -i s1.example.com }
default_backend loopback
#Handles the termination domains on second pass
frontend termination
bind 127.0.0.1:8443 ssl crt s2.example.com.pem
option forwardfor
reqdel X-Forwarded-Proto
reqadd X-Forwarded-Proto:\ https if { ssl_fc }
use_backend service2 if { ssl_fc_sni -i s2.example.com }
default_backend service2
#Loopback for second pass
backend loopback
mode tcp
server https-front 127.0.0.1:8443
backend service1
mode tcp
server service1 127.0.0.1:8888
backend service2
server server2 server2:80
backend acmetool
server acmetool 127.0.0.1:81
Thanks again for the help with understanding the logic