When I push my application to production I often want to know more about it. Google Analytics helps me to learn more about my users. Sometimes it’s interesting for me but not as much as for my product owner and managers. I often want to know more about our software, boxes and processes. Cacti and Monit help me to know about that. Monit is good enough to notify me about problems with our Lighttpd, Mysql and Memcached servers. Cacti helps to understand where the problem is or even more. From time to time I can know when the possible problem is going to be a pain.

Occasionally I want to play more with Cacti. For one our project I asked myself – “What kind of request does our Lighttpd serve?”. That application has several dynamic pages and a bunch of static content like images, javascript and stylesheet files. All these resources are served by single web server. I wanted to get the answer to my question and changed nothing into application sources.

After small brainstorming I decided to use HaProxy. You probably know about this load balancer. Of course it’s mostly used for high loading applications but you can use it for small one. It’s very easy to install and configure. And it is very lightweight and it helped me to solve my problem.

So I installed HaProxy and configured it to have one frontend and two backends. Both backends were pointed to the same web server. Using acl rules I splited all request and redirected them to a special backend. For example, I created acl rule for image requests and redirected them to image backend. Look at the part of my configuration for HaProxy.

frontend http-in
        acl url_image path_end .jpg .png
        use_backend image if url_image
        default_backend default
    backend default
        balance roundrobin
        server singlesrv2 localhost:81 
    backend image
        balance roundrobin
        server imagesrv2 localhost:81

It looks simple, doesn’t?

I restarted my Lighttpd and HaProxy daemons. I integrated HaProxy and Cacti with Dmytro Shteflyuk’s help at last (I really hate to create something new for Cacti…) and I looked at a new graph. I was so happy for a moment…


It looks like our Lightttpd is too busy serving images to our users and somebody has a new problem to solve :)

Here is a very simple script

     if (!isset($called_by_script_server)) {
         include_once(dirname(__FILE__) . "/../include/config.php");
         print call_user_func_array("ss_haproxy_stats", $_SERVER["argv"]);

    function ss_haproxy_stats($url = 'http://localhost/my_stats;csv', $action = 'FRONTEND', $sername = 'http-in'){
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_BINARYTRANSFER, 0);
      curl_setopt($ch, CURLOPT_CRLF, 1);
      curl_setopt($ch, CURLOPT_HEADER, 0);
      //http base auth
      // curl_setopt($ch, CURLOPT_USERPWD, "user:password");
      $stat = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      if ($http_code == 200) {
          $tmp=explode("\n", $stat);
          $tmpp = explode(',', $tmp[0]);
          foreach ($tmp as $item) {
              $values = explode(",", $item);
              if ($values[1] == $action) {
                  if ( $values[0] == $sername) {
                      print "fake:0 " . "scurrent:" . $values[4] . " stotal:" . $values[7] . " weight:" . $values[18] . "\n";

I put it into {$CACTi_HOME}/scripts/ss_haproxy_stats.php. I created a new Data Input Methods with
Input Type: Script/Command
Input String: -q /scripts/ss_haproxy_stats.php <haproxyurl>
Input Fields: haproxy_url : http://localhost/my_stats;csv
Also, I put several output fields which have the same names as server names and frontend in my haproxy.cfg. Little work with Data Template and Graph template and you will have it.