Complex HAProxy Setup with HTTP2 and HTTP1 togather - haproxy

We have a complex haproxy setup, where one https frontend were used with multiple backend based on path, host name, subdomians, sni, ssl termination etc. Now in one of our case we need to use http2 with all those http backends. and most importantly it should be support host name based routing to different backends. Our backend support both http2 and http1 we just need to forward traffic there after terminating ssl based on hostname.
Couldn't find much more examples related to http2 in Haproxy. All those i found used mode tcp in frontend like this. I am afraid using mode tcp could break my http routings.
So how could i may accomplish this?
Our Haproxy version is 1.7.1
OS Ubuntu16.04
originally asked on discourse.haproxy.org

Related

Docker: run multiple container on same tcp ports with different hostname

Is there a way to run multiple docker containers on the same ports? For example, I have used the ports 80/443 (HTTP), 3306 (TCP/MySQL) and 22 (TCP/SSH) in my docker-compose file. Now I want to run this docker-compose for different hostnames on the same ip address on my machine.
- traffic from example1.com (default public ip) => container1
- traffic from example2.com (default public ip) => container2
I have already found a solution only for the HTTP traffic by using an additional nginx/haproxy as a proxy on my machine. But unfortunately, this can't handle other TCP ports.
This isn't possible in the general (non-HTTP) case.
At a lower level, if I connect to 10.20.30.40:3306, the Linux kernel selects a single process that's listening on that port and sends the request there. You're not allowed to bind(2) a second process to the same port. (This is also why you get an error if you try to docker run -p picking a host port that's already in use.)
In the case of HTTP, there's the further detail that the host-name part of the URL is also sent in an HTTP Host: header: the Web browser both does a DNS lookup for e.g. stackoverflow.com and connects to its IP address, and also sends a Host: stackoverflow.com HTTP header. That's the specific mechanism that lets you run a proxy on port 80, and then forward to some other backend service via a virtual-host setup.
That mechanism is very specific to HTTP, though, and doesn't work for other protocols that don't have support for it. I don't think either MySQL or ssh have similar mechanisms in their wire protocol.
(In the particular situation you describe this is probably relatively easy to handle. You wouldn't want to make either your internal database or an sshd visible publicly, so delete their ports: from your docker-compose.yml file, and then just worry about proxying the HTTP service. It's pretty unusual and a complex setup to run sshd in Docker so you also might remove that and simplify your stack a little.)

Proxy requests to backend using h2c

Re-asking the question from HA-Proxy discourse site here in the hopes of getting more eyes on it.
I am using HA-Proxy version 1.9.4 2019/02/06 for proxying HTTP traffic to a h2c backend. I am however seeing HA-Proxy set the :scheme to https (and from as far as I can tell uses SSL in the request) when proxying the request. When I hit the backend directly, the :scheme is set to http and the request is non-SSL as expected. I have verified this HA-Proxy behavior using wireshark.
Any suggestions on what I should change in my configuration so that I can set to make sure that the :scheme gets set to http while proxying the request to the backend?
I am using curl 7.54.0 to make requests:
$ curl http://localhost:9090
where HA-Proxy is listening on port 9090.
My HA-Proxy config file:
global
maxconn 4096
daemon
defaults
log global
option http-use-htx
timeout connect 60s
timeout client 60s
timeout server 60s
frontend waiter
mode http
bind *:9090
default_backend local_node
backend local_node
mode http
server localhost localhost:8080 proto h2
It's not supported yet. The client=>haproxy connection can be HTTP/2, the haproxy=>server connection cannot.
https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#1.1
HTTP/2 is only supported for incoming connections, not on connections
going to servers.
Just add proto h2 to the server definition.
Cite from example:
server server1 192.168.1.13:80 proto h2
It's an experimental feature of haproxy-1.9, you must enable option http-use-htx to use it.
option http-use-htx is enabled by default since haproxy-2.0-dev3.
This was reported as an issue in haproxy github and has been fixed in version 2.0.

Deploy http2 to l7 load balanced pool of webservers

I have to implement http2 on a website and going through the implementation plan.
The infrastructure is as such :
Users ( connecting over tcp 443 only )
|
V
asa fw
|
V
l7 lb ( ssl/tls terminates here and least connection load balancing )
/ \ encrypted communication using self signed cert between
V V lb and web servers
web01 web02
Question is :
in order to have the wesite fully http2 compliant ( https, multiplexing, server push, and the like ... ) do both lb and web servers have to support http2 ? Or only the web servers ?
I belive both of them need to support http2, for reasons such as : a) this is a layer7 lb hence http protocol aware b) the termination happens on the lb c) the full journey visitor to webserver must be http2 compliant.
But as I am not an expert on the subject, I'd like if anyone out there could share their personal experience.
Thanks
You need to support HTTP2 where the HTTPS terminates.
Not sure why you think you NEED to be fully HTTP2 compliant - most of the benefits, at least at present until server push becomes more mainstream are gained by being HTTP/2 at end point. See here for more info:
HTTP2 with node.js behind nginx proxy

Pingfederate SSO on port 9031

Why do SSO providers like Ping Federate run on ports that aren't well-known like 9031. Does this enhance security? It seems like it just increases connectivity issues in organizations with strict firewall rules.
That's just a default semi-random port so that it doesn't clash with existing services on the same machine and is a high port so that the server can run under a non-privileged user account.
For production usage one would typically change it to 443 and/or run a reverse-proxy/loadbalancer in front of the SSO server (on port 443).
Generally security is managed at the perimeter of a network. For deployments I have been involved, port 443 is predominately used for SSO (e.g. PingFederate) at the perimeter. For the internal network, I have seen two models, mainly (i) change the HTTPS port in PingFederate to 443, or (ii) utilize load balancer port forwarding from 443 to 9031. I usually see item (i) for Windows deployments and item (ii) for Linux deployments where reserved ports are avoided. There really isn't a true security enhancement for either pattern.
As Hans points out, PingFederate utilizes 9031 as a default so that conflict with other processes on a server are avoided when first deploying the technology. As the SSO capability matures into an environment, the proper port for the service can be managed. The default port avoids issues when first installing that can be frustrating to folks new to the technology.

Combine HAProxy stats?

I have two instances of HAProxy. Both instances have stats enabled and are working fine.
I am trying to combine the stats from both instances into one so that I can use a single HAProxy to view the front/backends stats. I've tried to have the stats listener on the same port for both haproxy instances but this isn't working. I've tried using the sockets interface but this only reports on one of the interfaces as well.
Any ideas?
My one haproxy config file looks like this:
global
daemon
maxconn 256
log 127.0.0.1 local0 debug
log-tag haproxy
stats socket /tmp/haproxy
defaults
log global
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:8000
default_backend servers
log global
option httplog clf
backend servers
balance roundrobin
server ws8001 localhost:8001
server ws8002 localhost:8002
log global
listen admin
bind *:7000
stats enable
stats uri /
The other haproxy config is the same except the front/backend server IPs are different.
While perhaps not an exact answer to this specific question, I've seen this kind of question enough that I think it deserves to be answered.
When running with nbproc greater than 1, the Stack Exchange guys have a unique solution. They have a listen section that receives SSL traffic and then uses send-proxy to 127.0.0.1:80. They then have a frontend that binds to 127.0.0.1:80 like this: bind 127.0.0.1:80 accept-proxy. Inside of that frontend they then bind that frontend, e.g. bind-process 1 and in the globals section the do the following:
global
stats socket /var/run/haproxy-t1.stat level admin
stats bind-process 1
The advantage of this is that they get multiple cores for SSL offloading and then a single core dedicated to load balancing traffic. All traffic ultimately flows through this frontend and therefore they can accurately measure stats from that frontend.
This can't work. Haproxy keeps stats separated in each process. It has no capabilities to combine stats of multiple processes.
That said, you are of course free to use external monitoring tools like (munin, graphite or even nagios) which can aggregate the CSV data from multiple stats sockets and display them in unified graphs. These tools are however out-of-scope of core haproxy.