For one of our SAAS platforms, Backtobasics selected DigitalOcean Singapore as our data center. I can say, without reservation, that DigitalOcean delivers an excellent service at a very competitive price. We are very happy with DigitalOcean.
Our SAAS consists of a cloud platform built on Laravel and sitting behind Apache2. A standard setup.
To ensure our ability to scale, we front our platform hosts with a DO load balancer. One of the features of the load balancer is the “health check” of attached servers to determine which servers are available for processing requests. The health check configuration provides two protocol choices: TCP and HTTP.
When we first brought up the load balancer, our server was immediately marked as “dead”. Which was confusing, as we were able to access the server directly and the website was fully functional. So, we tried creating a specific path for the health check that returned an empty page with HTTP status 200. This did not work either.
Searching the web, we were unable to find an article that specifically answered why this was happening. All we did find were articles suggesting to use the TCP protocol for the health check. This did resolve the problem, because as soon as we reconfigured the load balancer to use the TCP health check, the server was marked as “healthy”.
However, this did not suit our desires. The TCP check was only opening port 80 to see if it was alive, which of course it was. However, this did not confirm that Apache was responsive, nor did it confirm what our Laravel platform was responsive. Specifically, we want the health check to be served by the Laravel platform, which can then also make checks on resources such as the database, file servers, our CDN and more. Thus, we were disappointed that the HTTP health check was not working.
Not giving up, we dug deeper. Checking Apache log files, we finally discovered the problem. The DO load balancer, making an HTTP request, needs to include the “Host” header line, which indicates the domain name of the website being accessed. This is how HTTP servers, such as Apache, know where to direct an HTTP request when they are hosting multiple domains. The log revealed that the hostname being sent in the Host header was in fact “cloud.digitalocean.com”.
This was the problem. Fortunately, we were not using virtual hosts in Apache, as we are serving only one application, so Apache was happily sending along the request to our Laravel application. The problem was that our Laravel routing was setup using “Route::domain” to allow us to service subdomains. Because of our use of domain routing in Laravel, the request did not match any of our route, and thus the response was a 404, which caused the load balancer to mark the server as “dead”.
Once we added a route that was not tied to the domain name, our HTTP health checks began to succeed, and all was well.
So, if you are having trouble with your DigitalOcean load balancer marking your servers as dead when using the HTTP protocol for the health check, there are two likely causes of this problem.
- If you are using Apache, and your websites are all defined as virtual hosts, then you will need to add a “ServerAlias” configuration for “cloud.digitalocean.com” to one of your virtual host configurations, or make sure that the process serving the default virtual host properly handles the path you have configured for the health check.
- If you are using Laravel domain routing, as in our case, or any other platform that is specifically considering the hostname provided by the HTTP request in it’s routing, you need to ensure that there is a route that can respond to the domain “cloud.digitalocean.com”.
In other words, the most likely source of the problem is that some process in your HTTP processing chain is not dealing with the hostname coming from the load balancer.
For WordPress users, this may not be fixable, since WordPress will redirect an incoming request for a domain that does not match the configured website’s domain name (the Site Address in Settings -> General). The redirect will point to the domain name that the WordPress website is configured to be serving, which makes sense. However, this redirect will come back to the load balancer as a 301 or 302 redirect, which the load balancer may or may not handle properly. The obvious solution, if you are using Apache, is to define a virtual host for the domain “cloud.digitalocean.com” and setup a process to return a page with status 200.
It would be nice if the folks at DigitalOcean could add one more item to the HTTP health check configuration to allow the specification of the domain name being passed to the server down stream, since there may be cases where handling the domain name being sent currently is not practical.