Why keep port 80 and 443 open, and how can I customize a direct ip hit response?

So, every site as far as I can tell keeps port 80 open for some odd reason.

Stackpath does 151.139.128.11:80 and 151.139.128.11:443

Port 80 sends about 500 bytes of headers for a response, and 443 is actually not sending back any response (0 bytes)

Limelight 68.142.68.1:80 68.142.68.1:443

Both send responses, 443 sends the nginx response, 80 sends just header response

Why keep port 80 open if you’re gonna serve https traffic?

I might have just found the answer as I was writing this-- is it because by default browsers go to http and not https, so it needs to use port 80 to redirect to port 443? Like if I type google.com, it’s gonna go to www.google.com then make it https.

Is there really a benefit of doing so besides people being able to type the domain in the browser? It actually seems like there is, so then what’s the most efficient way of doing this? Can it be done with HAProxy?

This brings me to my next question–

How can I efficiently send back 0 bytes of response with HAProxy when someone requests the IP with port 80 or 443 of the HAProxy server while using ACLs with more than 1 domain? I’m trying to make HAProxy use the least amount of cpu as possible while preventing mass spam against the web protocol. HTTP silent drop is great, but I think there’s another one that would probably be a better use case while being slightly less efficient, or more efficient.

Finally, if you have time, can someone give me an example config that uses HAProxy cache? I looked at the blog post and around the web and couldn’t find a way to get it to work. Seems like a way better solution than using varnish if the site has little content.

Thank you so much! If it helps, I’m essentially trying to mimic a commercial CDN service, but run it locally so I don’t have to pay high fees, have lower latency and full control over how I want things to work.

Hi
I hope I understand you correctly.

From what I know, there is two reasons to keep Port 80 listening:

  • For convenience - Browsers connecting to http: will be automatically redirected to https: rather than getting a connection error
  • If you want your HAProxy or any backend servers to get Let’s Encrypt certificates using HTTP challenge

You could of course close port 80 on the firewall and not listen on it, but as already mentioned, Browsers connecting to http: will in this case get a connection error, and regular users will believe that your site is broken, rather than understanding they have to modify the request in their Browser by inserting https: into the request URL.

If your frontend is redirecting http: to https:, haproxy is in this case sending a http redirection back to Browsers, which is a small http header sending a return code 301 (or 302) back, with the correct URL to re-request.

A http redirection could be considered “0” (zero) bytes in the context of the http protocol, as there is no http payload. Of course, in the context of TCP/IP, it is not zero bytes.

If you are concerned about DDoS attacks, optimizing the amount of bytes on port 80 is hardly gonna help.

In other words, listening on port 80 only makes sense, if you are prepared to send http redirections back to browsers. If you don’t want to send http redirections, you may prefer to send HSTS http response headers over https: and block/not listen on port 80.

I hope this is the answer you were looking for?

Yep, that’s exactly what I was looking for in all honesty.
Let’s say I own these 2 domains:

The HAProxy server IP is 4.4.4.4
google.com requests backend is 10.0.1.0
bing.com backend is 10.0.2.0

Connecting to either domains with http (port 80) will send a redirect header to go to https (port 443) for the appropriate domain.

If someone were to connect to 4.4.4.4 directly by IP with port 80 or 443, how can I effectively block or respond with 0 bytes of data?

It doesn’t seem to be very important, because almost every single CDN I know of actually responds with an HTML response for some reason, but If I wanted to send absolutely no response at all to limit the DDoS vulnerable surface, how should I do that? Should I map or use ACLs? Is there an specific efficient way that this should be done in the config?

HAProxy doesn’t have the best documentation which is why I’m here–

Thanks

Hello trent

It’s a good question!
I think I understand now that you actually want to filter out bad requests from good requests in the most efficient way?

Notice, that mode http (layer 7) offers more ways to detect bad requests than mode tcp (layer 4), but layer 7 (in general) may use slightly more system resources. So it’s a trade-off, but layer 7 filtering is mostly the better deal, if the checks are simple.

Also notice, that DDoS attacks may saturate the internet link - in such cases your haproxy cannot mitigate/prevent the DDoS attack, and a solution must be found upstream.

What “components” could be used to filter bad requests?

Plaintext, Port 80

  1. Source IP (layer 4) → Use ACL’s to block/allow IP whitelists/blacklists/GeoIP
  2. Malformed HTTP request (e.g. tcp scan without any HTTP) → HAProxy should automatically block these in mode http
  3. Content of HTTP “Host:” header → Use ACL’s to block requests for “Host:” which don’t exist on your Load Balancer
  4. Redirect everything to https (optionally: except Let’s Encrypt HTTP Challenges) → Use ACL (optionally: with exception)

Encrypted, Port 443
5. Source IP (layer 4) → same as 1.
6. TLS negotiation (layer 6) → Configure tight cipher suites (some bad requests will be blocked by TLS errors), you may want to add the TLS negotiation result to the custom log
7. SNI header (layer 6) → Use ACL’s. Block requests with SNI that don’t exist on your Load Balancer
8. Content of HTTP “Host:” header → (same as 3.)
9. Content of HTTP “User-Agent:” header → Use ACL’s to block requests based on “User-Agent:” blacklist/whitelist (e.g. Python etc.) Add the “User-Agent” to custom log
10. Content of HTTP Request URL → Use ACL’s to block known attack patterns (e.g. Log4shell) or patterns you don’t host (e.g. Wordpress)
11. Bots, clients that consistently behave badly → Use Stick-Tables

OK, that’s above the scope that you initially asked.
To get back to your question, one way to go about it is:

Create a file /etc/haproxy/acls/mysites.acl with contents:

www.site-a.net
www.site-b.net
www.site-c.net

And reference this file in your haproxy config (the ! is a logical not):

frontend WEB
  mode http
  bind 10.11.12.13:80  name 10.11.12.13:80
  bind 10.11.12.13:443 name 10.11.12.13:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
  http-request deny           if !{ hdr(host) -i -f /etc/haproxy/acls/mysites.acl }
  redirect code 301 scheme https if !{ ssl_fc }
  use_backend www.site-a.net  if { hdr(host) -i www.site-a.net }
  use_backend www.site-b.net  if { hdr(host) -i www.site-b.net }
  use_backend www.site-c.net  if { hdr(host) -i www.site-c.net }

backend www.site-a.net
   mode http
   ...

This could be one possible approach. But it could be done in many different ways.

Hope this helps?
Toni

Thank you! That worked perfectly. Exactly what I was looking for. I ended up just doing “http-request reject” for port 80 just for now if anyone tries to directly connect to the HAProxy instance by a domain that doesn’t exist. Is there a more efficient way to be doing this? It doesn’t respond with any bytes, so there’s no HTTP request being completed, but I still feel like this could be vulnerable.

Should I be using a tcp request reject or something? I want to block all requests in the most efficient way possible.

Would a silent-drop be ideal?

HTTP request reject sends chrome browser ERR_EMPTY_RESPONSE, but I feel like there’s a way to say ERR_CONNECTION_REFUSED or ERR_CONNECTION_RESET. HAProxy CDN sends back ERR_INVALID_RESPONSE which I’m gonna assume is also efficient. There seems to be many ways to do this, and I’m just looking for the way to do it most efficiently with HAProxy alone, and not involve IP tables. http reject works really well though, so I’m not complaining.

At this stage, you may want to read some of the excellent blogs and documentation! :slight_smile:
This blog expands on some of your questions:

Official documentation (pick your version of haproxy):
https://cbonte.github.io/haproxy-dconv/2.4/configuration.html#4.2-http-request
You are interested in all blocking options of http-request and maybe tcp-request.

Keep in mind, you may also want to fine-tune the values in the default section, if you need to be obsessed about efficiency. Allow pools to be large, so that haproxy can consume all your hardware, and keep timeouts as short as possible.

Using the most recent LTS version of haproxy may also perform better, and automatically make better use of hardware resources. You may or may not need to self-compile, rather than using your distro’s version.

1 Like