Installation guide ==================== .. contents:: Table of Contents On the munin2smartphone + static html server -------------------------------------------- Note that this guide: * Uses nginx as a static web server and reverse proxy, * Stores static HTML pages to :samp:`/var/lib/munin2smartphone`, * Serves those pages on URL :samp:`https://your.fqdn.example.htmlreports`, * Makes *munin2smartphone* listen on address :samp:`127.0.0.1` and port :samp:`8765`, * Receives data on URL :samp:`https://your.fqdn.example/pushdatahere`. Build the Public Key Infrastructure ................................... We are going to authenticate our data broker with an HTTPS-client certificate. Here is a step-by-step using Debian 10 and easy-rsa 3 as a crypto-tools wrapper. Feel free to adapt (hopefully this is accurate). .. code-block:: bash sudo apt install easy-rsa mkdir munin2smartphone-pki cd munin2smartphone-pki cp /usr/share/easy-rsa/easyrsa . ./easyrsa init-pki ./easyrsa build-ca Deploy the CA to nginx: .. code-block:: bash sudo mkdir -p /etc/nginx/client_certs/ sudo cp ./pki/ca.crt /etc/nginx/client_certs/ Build the client cert (you will be prompted for a password, which you will need later): .. code-block:: bash ./easyrsa build-client-full httpmunin .. _client_ssl: You want to transfer :samp:`./pki/private/httpmunin.key`, :samp:`./pki/issued/httpmunin.crt` and :samp:`./pki/ca.crt` to the munin host. You may safely delete :samp:`./pki/private/httpmunin.key` from this place. Configure 2 nginx locations ........................... We will serve the static pages and forward ssl-verified requests to *munin2smartphone* through `nginx `_. We need to add 2 location directives and specify the ssl CA, something like: .. code-block:: NGINX server { index index.html index.htm index.nginx-debian.html; server_name your.fqdn.example; # [...] # ------ Copy-paste and adapt below ------ # Here, the static html location location ~ ^/htmlreports(/.*)$ { alias /var/lib/munin2smartphone$1; } # Now, make client ssl verification optional # and define the forwarding location # client certificate ssl_client_certificate /etc/nginx/client_certs/ca.crt; # make verification optional, so we can display a 403 message # to those who fail authentication (= forbidden) ssl_verify_client optional; location /pushdatahere/ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; if ($ssl_client_verify != SUCCESS) { return 403; } proxy_pass http://127.0.0.1:8765; } # ------ End of the new sections ------ # [...] } Install `munin2smartphone` .......................... You probably want to use a virtualenv with Python 3.8 (3.6 at least) and .. code-block:: bash pip install munin2smartphone Now test-run `munin2smartphone` in a terminal! Real system installation: To be documented (help welcome). I plan on: * using a systemd unit to start the daemon, * creating a debian package of *munin2smartphone* and deps. Run munin2smartphone with relevant options and configuration ............................................................ This is covered in another section of the documentation: `options_config`. On the munin host ----------------- HTTPS POST with curl .................... At the :ref:`end of the PKI step-by-step`, we transfered 3 files to this host. Now ensure that their names and location match the script below, that is: * :samp:`/etc/munin/{httpmunin-ca.crt}` (initially :samp:`ca.crt`) * :samp:`/etc/munin/{httpmunin.crt}` * :samp:`/etc/munin/{httpmunin.key}` .. code-block:: bash :caption: ``/usr/local/bin/push-munin.sh`` - This file should be readable and executable by the user ``munin``. #!/bin/bash # We'll receive data from stdin (piped into this script). sed "s,/,\\/,g" | \ /usr/bin/curl \ --cacert /etc/munin/httpmunin-ca.crt \ --cert /etc/munin/httpmunin.crt \ --key /etc/munin/httpmunin.key \ --pass superpass \ https://your.fqdn.example/pushdatahere/ \ -d @- .. _scheduled_munin_limits: Call to munin-limits every 5 minutes .................................... Let's code a very simple daemon. ``munin-limits`` will evaluate the state of every known check and take the configured action. .. code-block:: python :caption: ``/usr/local/bin/call-munin-limits.py`` - This file should be readable and executable by the user ``munin``. #!/usr/bin/python3 import time import subprocess INTERVAL = 300 # seconds = 5 minutes COMMAND = [ "/usr/share/munin/munin-limits", "--contact", "widget", "--force", "--always-send", "warning,critical", ] def main(): while True: print("Calling {}".format(' '.join(COMMAND))) process = subprocess.Popen(COMMAND) process.wait() print("Exit code: {}".format(process.returncode)) time.sleep(INTERVAL) if __name__ == "__main__": main() Configure the service ...................... .. code-block:: INI :caption: ``/etc/systemd/system/push-munin.service`` [Unit] Description=Triggers a push of all munin states in json [Service] ExecStart=/usr/local/bin/call-munin-limits.py User=munin [Install] WantedBy=multi-user.target Then run .. code-block:: bash systemctl daemon-reload systemctl enable push-munin systemctl start push-munin 2. Add a contact in munin, and specify the concatenated JSON format .. _munin_conf: .. This is not bash but bash can highlight somehow .. code-block:: bash contact.widget.command /usr/local/bin/push-munin.sh contact.widget.text \ { \ "group":"${var:group}", \ "host":"${var:host}", \ "graph_category":"${var:graph_category}", \ "graph_title":"${var:graph_title}", \ "warning":[ ${loop<,>:wfields { \ "label":"${var:label}", \ "value":"${var:value}", \ "w":"${var:wrange}", \ "c":"${var:crange}", \ "extra":"${var:extinfo}" \ } } ], \ "critical":[ ${loop<,>:cfields { \ "label":"${var:label}", \ "value":"${var:value}", \ "w":"${var:wrange}", \ "c":"${var:crange}", \ "extra":"${var:extinfo}" \ } } ], \ "unknown":[ ${loop<,>:ufields { \ "label":"${var:label}", \ "value":"${var:value}", \ "w":"${var:wrange}", \ "c":"${var:crange}", \ "extra":"${var:extinfo}" \ } } ] \ } .. _smartphone_install: On the smartphone ................. On android, you can use this `widget `_. Configure a view to your static web pages with an automatic reload. Notes ----- .. topic:: on the refresh interval I chose to use a 5 minutes interval everywhere. 5 minutes is the default polling interval for munin. Should you wish to change this, you need to change the interval in: * munin update (cron or systemd timer), * :ref:`call-munin-limits.py`, * your web viewer (browser or :ref:`smartphone `). .. topic:: on the munin contact name We are going to configure a contact named "*widget*" in ``munin``. This contact will trigger a shell script pushing data over HTTPS with curl. Every 5 minutes, we will shoot an event so that munin processes the data and sends it to our ``munin2smartphone`` daemon. Should you want to use another name than *widget* for the contact, change it * in the :ref:`munin config ` * and in :ref:`call-munin-limits.py`,