In this post we will talk about why and how to put kibana behind haproxy. First thing I am thinking is to be able to have multiple kibana setups and either do loadbalancing between them or use them as active - backup setup. This is how I will be using in this post. This option will also enable you the possibility to enable ssl and add simple http authentication in case you don't want to pay for x-pack security feature.
Also this post will assume that you already have kibana and haproxy installed on your system.
For being able to browse kibana as https://example.com/kibana you need to edit the following line in kibana.yml:

server.basePath: "/kibana"

After you have enabled that you need to restart kibana which would take some time because the kibana will regenerate the styles and scripts.
Since that is done now it is time to configure haproxy. First we will be configuring the global section of the haproxy. In order to configure it we need to edit the /etc/haproxy/haproxy.cfg:

global
	log /dev/log	local1 notice
	chroot /var/lib/haproxy
	stats socket /run/haproxy/admin.sock mode 660 level admin
	stats timeout 30s
	user haproxy
	group haproxy
	daemon
	maxconn 20000

If you want to configure the ssl then append the following lines to the config global section

	tune.ssl.default-dh-param 2048
	# Default SSL material locations
	ca-base /etc/ssl/certs
	crt-base /etc/ssl/private

	ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
	ssl-default-bind-options no-sslv3

For the following we are adding to the global section the configuration of the userlist which will contain the list of users which will be able to authenticate:

	userlist UsersAuth
        user elastic password $6$eGBvJDX0$VrPLT4dNCm...AsEpd1
        user scott insecure-password elgato

As it can be seen the users can be added with encrypted passwords also with human readable format. The supported encryption methods are MD5, SHA-256, SHA-512 and of course classic, DES-based methods.
The default section is pretty much standard and out of the box so we will not touch it in this tutorial.
Next step is to configure the frontends. First thing first is to configure a http frontend which will be forwarding the request to https by adding the following settings:

frontend http-in
  mode http
  bind 172.16.0.9:80
  redirect scheme https code 301 if !{ ssl_fc }

Now we will create a frontend to https by adding the following settings to haproxy.cfg:

frontend https-in
    bind 172.16.0.9:443 ssl crt /etc/ssl/certificates.pem
    reqadd X-Forwarded-Proto:\ https
    acl acl_kibana path_beg /kibana
    use_backend kibana if acl_kibana

Now that the frontend it is configured we will be configuring the related backend by adding the following settings:

backend kibana
    option redispatch
    option forwardfor
    option httpchk GET /
    acl AuthOkay_UsersAuth http_auth(UsersAuth)
    http-request auth realm UserAuth if !AuthOkay_UsersAuth
    reqrep ^([^\ :]*)\ /kibana/(.*) \1\ /\2
    server mgt1 172.16.99.5:5601 check inter 1000 fastinter 500 rise 2 fall 1
    server mgt2 172.16.99.6:5601 check inter 1000 fastinter 500 rise 2 fall 1 backup

option redispatch mean that if the first backend will become unavailable instead of throwing an error 500 redispatch the requet to the backup nodes.
option forwardfor will forward the request to the backends instead of creating a new request.
option httpchk GET / will make the healthchecks to be done on http://172.16.99.5:5601/ instead of http://172.16.99.5:5601/kibana
the acl will tell that if the user is not authenticated then to as for username and password from the user.
reqrep ^([^\ :]*)\ /kibana/(.*) \1\ /\2 is a tricky thing. Since we have kibana configured with basePath: /kibana we would assume that the request will have to be sent as /kibana but in reality the requests have to sent as /. Therefore we need to remove the /kibana from the request which will be done by this rule.
And the last two lines are the configuration of the backend servers. As you see we did not specified the balancing method therefore we configure a active-backup setup. The first node will be the active one and if that will be turned off then the first backup will take the connections until the active node will come alive again.

As a bonus you can configure the status page into the defaults section by adding the following lines:

stats enable
stats hide-version
stats uri /admin?stats
stats realm Haproxy\ Statistics
stats auth admin:somerandompassword
stats refresh 10s

If this is enabled you can browse the https://yourdomain.com/admin?stats which will ask you to authenticate. For the authentication you need to use the credentials configured at the stats auth line.