High Availability - Reverse Proxy with nginx
name: High availability violating HTTP/1.1 RFC; issues when attempting to use nginx as a reverse proxy
about: When attempting to use the high availability library with nginx acting as a reverse proxy to Kea CA a HTTP 400 error code is returned as the requests are missing a valid "Host" header.
Describe the bug I am evaluating using Kea as the DHCP server for my network in a Docker container. For the high availability setup I have Kea Control listening on port 8081 with nginx acting as a reverse proxy on port 8080. I am running it with nginx as I cannot see a way to bind the control agent to all available interfaces/IP's; the IP's being used at run time will be random and I would prefer being able to use all available interfaces. The nginx configuration is very simple:
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
location / {
proxy_pass http://127.0.0.1:8081;
}
}
The high availability library makes HTTP/1.1 requests without using a "Host" header which results in messages like these from nginx:
2018/12/17 03:57:57 [info] 20#20: *32 client sent HTTP/1.1 request without "Host" header while reading client request headers, client: 192.168.155.34, server: _, request: "POST / HTTP/1.1"
The HA hook that runs to send the heartbeat also fails as nginx returns a 400 error:
2018-12-17 03:57:59.732 WARN [kea-dhcp4.ha-hooks/19] HA_HEARTBEAT_COMMUNICATIONS_FAILED failed to send heartbeat to dhcp1 (http://192.168.155.34:8080/): unable to parse the body of the HTTP response: error: unexpected character < in <string>:1:2 : current state: [ 1 END_ST ] next event: [ 3 FAIL_EVT ]
A failing HTTP request looks like this:
POST / HTTP/1.1
Content-Length: 53
Content-Type: application/json
{ "command": "ha-heartbeat", "service": [ "dhcp4" ] }
And for the response:
HTTP/1.1 400 Bad Request
Server: nginx
Date: Mon, 17 Dec 2018 04:12:39 GMT
Content-Type: text/html
Content-Length: 166
Connection: close
<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx</center>
</body>
</html>
According to RFC7230 this is a violation of HTTP/1.1:
A client MUST send a Host header field in all HTTP/1.1 request messages. If the target URI includes an authority component, then a client MUST send a field-value for Host that is identical to that authority component, excluding any userinfo subcomponent and its "@" delimiter (Section 2.7.1). If the authority component is missing or undefined for the target URI, then a client MUST send a Host header field with an empty field-value.
Since the Host field-value is critical information for handling a request, a user agent SHOULD generate Host as the first header field following the request-line.
To Reproduce Steps to reproduce the behavior:
- Run Kea CA (doesn't matter where you bind to, the next step is the important part) + Kea4 or Kea6 with the high availability hook
- Install nginx and configure it to act as a reverse proxy to Kea CA
- Configure the HA hooks to send the health checks to the listening IP/port for nginx (which in turn proxies them back to Kea CA)
- Kea CA is unable to sync any leases or send heartbeats as nginx will return a HTTP 400 error
Expected behavior Kea CA should not violate the HTTP/1.1 spec, attempting to run it behind a reverse proxy results in a non-working high availability setup.
Environment:
- Kea version: 1.5.0
- OS: Debian Stretch x64
- Which features were compiled in (in particular which backends):
./configure --with-mysql --with-openssl --enable-shell
- If/which hooks where loaded in: libdhcp_lease_cmds.so, libdhcp_ha.so
Additional Information Covered above
Some initial questions
- Are you sure your feature is not already implemented in the latest Kea version? Yes
- Are you sure what you would like to do is not possible using some other mechanisms? There are other ways around this problem, but for my specific situation this is the most elegant. As I am running nginx in the container which is bound to all IP's (to provide a web UI) I would like to be able to use it as a reverse proxy as well; if that is not possible and there is a way to configure Kea CA to listen on all interfaces (eg. using a wildcard like it is possible in kea4/kea6) I could potentially use that as a work around.
- Have you discussed your idea on kea-users or kea-dev mailing lists? No
Is your feature request related to a problem? Please describe. Ability to run nginx as a reverse proxy for Kea CA.
Describe the solution you'd like Either:
- Ability to configure Kea CA to bind to all available interfaces/IP's. With Kea4/Kea6 it is possible to define the interfaces in the following format, but it is not possible with Kea CA:
"Dhcp4": {
"interfaces-config": {
// Listen on all interfaces
"interfaces": [ "*" ],
// Traffic to this server is sent via a DHCP relay, the server will listen on a UDP socket rather than raw socket
"dhcp-socket-type": "udp"
},
- Ability to configure a "Host" header for requests the high availability library sends