{"id":2460,"date":"2015-07-17T19:58:56","date_gmt":"2015-07-17T19:58:56","guid":{"rendered":"http:\/\/www.garysieling.com\/blog\/?p=2460"},"modified":"2015-07-17T19:58:56","modified_gmt":"2015-07-17T19:58:56","slug":"using-hubot-for-home-server-monitoring","status":"publish","type":"post","link":"https:\/\/www.garysieling.com\/blog\/using-hubot-for-home-server-monitoring\/","title":{"rendered":"Using Hubot for Home Server Monitoring"},"content":{"rendered":"<p>I set up\u00a0Hubot to do some simple server administration &#8211; this allows me to do a few common operations tasks while I&#8217;m travelling. I&#8217;ve previously tried SSH on my phone, but that seems unsafe in general, and it&#8217;s hard to use &#8211; this fixes a big frustration for me, if this site goes down and I&#8217;m not able to do anything.<\/p>\n<p><b>Installation<\/b><br \/>\nHubot responds to chat messages and calls into custom Javascript classes, so you first need to install Node \/ npm:<\/p>\n<pre>sudo apt-get update\nsudo apt-get install nodejs npm\n<\/pre>\n<p>Then follow the hubot install instructions:<\/p>\n<pre>npm install -g yo generator-hubot\nuseradd hubot\nsudo su - hubot\n<\/pre>\n<p><b>Chat<\/b><\/p>\n<p>Since I want this for travelling, I need a chat integration that works on my phone, that is also relatively secure.<\/p>\n<p>The\u00a0Hubot documentation recommends several options. \u00a0One caution from what I learned doing this,&#8221;Let&#8217;s chat&#8221; doesn&#8217;t seem to allow you to lock down who can create accounts, and SSL between my Linode Server and Heroku is completely broken (it seems to be a defect in Socket.io). For the time being I landed on Campfire, which works on a phone (barely). It looks like a lot of people use Hipchat, but for now I&#8217;m trying to run this on the cheap.<\/p>\n<p><b>Plugins<\/b><\/p>\n<p>I like the reminder plugin &#8211; this has a semi-natural language interface to remind yourself of things later. To add this, add &#8220;hubot-remind-her&#8221;: &#8220;^0.4.1&#8221; to package.json, and do npm.install. Even though it matches a lot of date formats, it&#8217;s still pretty flaky and you have to get used to what it wants.<\/p>\n<p>For simple administration, I added a memory check plugin that I wrote:<\/p>\n<pre lang=\"coffeescript\">module.exports = (robot) -&gt;\n robot.respond \/memory( (.+))?\/i, (msg) -&gt;\n    q = msg.match[1]\n    @exec = require('child_process').exec\n    command = \"top -b -n 1 \"\n    if (!!q &amp;&amp; q.length &gt; 0)\n      command = command + ' | grep \"' + q.match(\/[^_\\W]+\/g).join(' ') + '\"\n\n    msg.send \"Memory usage:\"\n\n    @exec command, (error, stdout, stderr) -&gt;\n      msg.send error\n      msg.send stdout\n      msg.send stderr\n<\/pre>\n<p>As well as a disk space checker:<\/p>\n<pre lang=\"coffeescript\">module.exports = (robot) -&gt;\n robot.respond \/disk (usage|use|space)\/i, (msg) -&gt;\n    q = msg.match[1]\n    @exec = require('child_process').exec\n    command = \"df -h \"\n\n    msg.send \"Disk free space:\"\n\n    @exec command, (error, stdout, stderr) -&gt;\n      msg.send error\n      msg.send stdout\n      msg.send stderr\n<\/pre>\n<p>To be able to effect change, I made it so I can\u00a0restart mysql:<\/p>\n<pre lang=\"coffeescript\">module.exports = (robot) -&gt;\n robot.respond \/restart mysql\/i, (msg) -&gt;\n    hostname = msg.match[1]\n    @exec = require('child_process').exec\n    command = \"sudo \/etc\/init.d\/mysql restart\"\n\n    msg.send \"Restarting mysql service on linode\"\n\n    @exec command, (error, stdout, stderr) -&gt;\n      msg.send error\n      msg.send stdout\n      msg.send stderr\n<\/pre>\n<p>You can do some entertaining things to make Hubot feel more like interacting with a person:<\/p>\n<pre lang=\"coffeescript\"> robot.respond \/thanks(.*)\/i, (msg) -&gt;\n    msg.send \"you're welcome!\"\n\n robot.respond \/sorry(.*)\/i, (msg) -&gt;\n    msg.send \"no problem!\"\n\n robot.respond \/(status|how are you)(.*)\/i, (msg) -&gt;\n    msg.send \"outstanding!\"\n<\/pre>\n<p>To show how this looks, this is a conversation I had with hubot:<\/p>\n<table class=\"chat\">\n<tbody id=\"chat\">\n<tr id=\"message_1494308933\" class=\"message you text_message\">\n<td class=\"person\"><strong>Gary:<\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">@linode: status<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494308938\" class=\"text_message message user_1635548\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling+linodehubot@gmail.com\" data-name=\"Linode\">Linode:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">outstanding!<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494308945\" class=\"message you text_message\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling@gmail.com\" data-name=\"Gary Sieling\">Gary:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">@linode: memory mysql<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494308972\" class=\"text_message message user_1635548\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling+linodehubot@gmail.com\" data-name=\"Linode\">Linode:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">Memory usage:<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494308980\" class=\"paste_message message user_1635548\">\n<td class=\"person\"><\/td>\n<td class=\"body\">\n<div class=\"body\">\n<pre><code> 2973 mysql     20   0  306m 123m 9.9m <\/code><\/pre>\n<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494309008\" class=\"message you text_message\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling@gmail.com\" data-name=\"Gary Sieling\">Gary:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">@linode: restart mysql<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494309010\" class=\"text_message message user_1635548\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling+linodehubot@gmail.com\" data-name=\"Linode\">Linode:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">Restarting mysql service on linode<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494309021\" class=\"paste_message message user_1635548\">\n<td class=\"person\"><\/td>\n<td class=\"body\">\n<div class=\"body\">\n<pre><code>mysql stop\/waiting\nmysql start\/running, process 14261<\/code><\/pre>\n<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494309039\" class=\"message you text_message\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling@gmail.com\" data-name=\"Gary Sieling\">Gary:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">@linode: remind me on monday to fix mysql<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494309041\" class=\"text_message message user_1635548\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling+linodehubot@gmail.com\" data-name=\"Linode\">Linode:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">I&#8217;ll remind you to fix mysql Monday at 12:00 PM<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494309170\" class=\"message you text_message\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling@gmail.com\" data-name=\"Gary Sieling\">Gary:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">thanks!<\/div>\n<\/td>\n<\/tr>\n<tr id=\"message_1494309180\" class=\"text_message message user_1635548\">\n<td class=\"person\"><strong><span class=\"author\" data-avatar=\"http:\/\/cdn.37img.com\/global\/missing\/avatar.gif?r=3\" data-email=\"gary.sieling+linodehubot@gmail.com\" data-name=\"Linode\">Linode:<\/span><\/strong><\/td>\n<td class=\"body\">\n<div class=\"body\">you&#8217;re welcome!<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><b>Security<\/b><\/p>\n<p>The code for the\u00a0above commands shows some of the risks of this &#8211; you don&#8217;t want Hubot to be able to do everything, even though it should only be getting commands through the chat, because you&#8217;re constantly a step away from giving someone full control of the box that runs hubot, and anything it can access.<\/p>\n<p>To make this safer, I escaped the grep input in the memory command, and require hubot to sudo to restart mysql. This specific command is granted to the hubot user in sudoers, so at least it limits it&#8217;s ability to cause damage:<\/p>\n<pre>hubot        ALL = NOPASSWD: \/etc\/init.d\/mysql restart\n<\/pre>\n<p>Generally I would audit any code you install for Hubot, because the script-writing community seems more interested in meme-generation than secure code. Even though the default meme\/image generation plugins are cute, I would remove them.<\/p>\n<p><strong>Daemonizing Hubot<\/strong><\/p>\n<p>Follow these instructions:<br \/>\n<a href=\"https:\/\/gist.github.com\/1394520\/ed2c32663ae61038d85b1cae1e2f10c105f07576\">https:\/\/gist.github.com\/1394520\/ed2c32663ae61038d85b1cae1e2f10c105f07576<\/a><\/p>\n<p>All of the chat settings should go in a configuration file &#8211; the trick to this is getting the paths all correct.<\/p>\n<p>Once you get it to work, make it start on boot:<\/p>\n<pre>update-rc.d Hubot defaults\n<\/pre>\n<p><b>Future Ideas<\/b><\/p>\n<p>In the future, I&#8217;m planning to extend this setup so that each of my machines (laptop, desktop) has a Hubot as well. This will for instance allow me to search for vacation photos or specific files while travelling, or to see if the power is on at home \/ in the office.<\/p>\n<p>I&#8217;m also looking to add some database commands (tell me the status of a user, extend an account, etc) to see how the experience works. I suspect that if you use a Google docs integration for Hubot, you could get access to a lot of applications that have Zapier APIs, but this will require some investigation.<\/p>\n<p>I also need to find a more suitable chat client (hopefully installable on a server), but security is challenging.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I set up\u00a0Hubot to do some simple server administration &#8211; this allows me to do a few common operations tasks while I&#8217;m travelling. I&#8217;ve previously tried SSH on my phone, but that seems unsafe in general, and it&#8217;s hard to use &#8211; this fixes a big frustration for me, if this site goes down and &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.garysieling.com\/blog\/using-hubot-for-home-server-monitoring\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Using Hubot for Home Server Monitoring&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[24],"tags":[280,302,410],"aioseo_notices":[],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/posts\/2460"}],"collection":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/comments?post=2460"}],"version-history":[{"count":0,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/posts\/2460\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/media?parent=2460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/categories?post=2460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/tags?post=2460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}