{"id":193,"date":"2011-01-13T17:00:57","date_gmt":"2011-01-14T01:00:57","guid":{"rendered":"http:\/\/porkrind.org\/missives\/?p=193"},"modified":"2015-02-20T23:30:06","modified_gmt":"2015-02-21T07:30:06","slug":"introducing-daemon-manager","status":"publish","type":"post","link":"https:\/\/porkrind.org\/missives\/introducing-daemon-manager\/","title":{"rendered":"Introducing Daemon Manager"},"content":{"rendered":"<p>The idea for Daemon Manager came about when I was converting a web  site from Apache to Nginx. Nginx doesn&#8217;t launch FastCGI programs  itself\u2014it only connects to FastCGI sockets and so it requires that you manage  the FastCGI server yourself.<\/p>\n<p>For a simple web site it might be OK to manually create an \/etc\/init.d script, but even for <a href=\"http:\/\/greenfelt.net\/\">our relatively simple solitaire site<\/a> we ended having about 5 separate FastCGI servers (between the blog, the  forum, and our test servers). At home I host virtual servers for  various members of my family and so there&#8217;s a ton of accounts and blogs  and forums and other random stuff. I just can&#8217;t abide copy and pasting  20 \/etc\/init.d scripts and then managing them all as they slowly fork  away from each other over time. Not to mention that ordinary users can&#8217;t manage \/etc\/init.d scripts themselves (without compromising system security) and if the script does any sort of setuid() calls then they can&#8217;t even restart their FastCGI servers without there being some sort of arcane <em>sudo<\/em> configuration.<\/p>\n<p>I also ran into a problem with PHP. I wanted to run WordPress on Nginx which meant I had to run the &#8220;php-cgi&#8221; FastCGI server. The problem is that &#8220;php-cgi&#8221; seems to just die randomly which means I needed some sort of watchdog that starts it back up when it fails.<\/p>\n<p>What I really wanted is a  program that lets  non-privileged users launch and respawn their own daemons securely and very simply.<\/p>\n<p>Daemon Manager is the result.<\/p>\n<h2>Design<\/h2>\n<p>The main principles of Daemon Manager&#8217;s design were:<\/p>\n<ol>\n<li>It must be possible for a user to set up and configure their  daemons\u2014no root access must be required for a user to create a new daemon or  restart one of their daemons.<\/li>\n<li>It must be secure\u2014users should not be allowed to control other users&#8217; daemons (unless they are given explicit permission).<\/li>\n<li>It should allow for good security practices\u2014users should be allowed  to launch a daemon as a user other than themselves if root has  explicitly allowed it. This is so you can run your FastCGI server as a  &#8220;nobody&#8221; style user.<sup class='footnote'><a href='#fn-193-1' id='fnref-193-1' onclick='return fdfootnote_show(193)'>1<\/a><\/sup><\/li>\n<li>It should restart the daemons if they crash (I&#8217;m looking at you, php-cgi).<\/li>\n<li>It should be easy to use\u20141 config file per daemon and a simple command line interface to interact with the running daemons.<\/li>\n<\/ol>\n<p>There are programs out there that do parts of that list, but none that do everything:<\/p>\n<ul>\n<li><a href=\"http:\/\/cr.yp.to\/daemontools.html\">daemon tools<\/a>:  I&#8217;ve used it before and I really like its philosophy of being small and  simple. But it seems to really want to run as root which means you have  to be root to control it. Also, setting up new daemons is kind of a  pain.<\/li>\n<li><a href=\"http:\/\/upstart.ubuntu.com\/\">Upstart<\/a>:  It&#8217;s very similar and it makes setting up a new daemon pretty easy but  since it&#8217;s an &#8220;init&#8221; replacement it doesn&#8217;t seems very adept at running  programs meant for non-root users. I&#8217;ve done it before but there was a  lot of &#8220;sudo&#8221; configuration and it wasn&#8217;t easy. Also the config files are  stored in \/etc\/init and only root can write new ones.<\/li>\n<li><a href=\"http:\/\/fedoraproject.org\/wiki\/Features\/systemd\">Systemd<\/a>: I really love systemd. Or the idea of it, really\u2014some day it will make it into Debian and I&#8217;ll start actually using it. But <a href=\"http:\/\/0pointer.de\/blog\/projects\/systemd.html\">its philosophy<\/a> is great. But again, being an &#8220;init&#8221; replacement gives it most of the same downsides as upstart.<\/li>\n<\/ul>\n<h2>Implementation<\/h2>\n<p>From those ideas Daemon Manager was born. I prototyped it in Perl in  about 8 hours. The idea seemed sound but I was unhappy with the memory  requirements of Perl. I wanted it to be something really small and lean, without any external dependencies.  So I rewrote it in C++. It now takes up hardly any RAM which makes it  suitable for smaller or embedded environments. The main loop just poll()s on the control sockets and calls wait() when necessary,  occasionally restarting a crashed daemon.<\/p>\n<p>I tried to think about security because if it&#8217;s insecure then nobody  is going to want to use it seriously. Daemon Manager will refuse to read  config files that don&#8217;t have the right permissions. It uses Unix domain  sockets to communicate with users (1 socket for each user in  ~\/.daemon-manager\/command.sock) and makes sure that each socket has the  correct permissions when it starts\u2014this way user authentication is handled by the operating system&#8217;s filesystem permissions layer. By default users of the  system are not allowed to run anything\u2014root must authorize each user and  specify which users their daemons can be run as.<\/p>\n<h2>A Quick Tutorial Through Examples<\/h2>\n<h3>Master config: \/etc\/daemon-manager.conf<\/h3>\n<pre><code class=\"language-ini\">[runs_as]\r\ndavid: www-data\r\nmichaelc: www-data\r\namy: www-data\r\njoann: www-data\r\njim:\r\ngreenfelt: www-data\r\n\r\n[manages]\r\ndavid: michaelc,amy,joann,greenfelt\r\nmichaelc: amy, joann\r\nbill: joann\r\njim: greenfelt<\/code><\/pre>\n<p>The  main section is the &#8220;runs_as&#8221; section. This section tells Daemon  Manager which users are allowed to start daemons and which users the  daemons can be run as. In the above example, &#8220;david&#8221;, &#8220;michaelc&#8221;, &#8220;amy&#8221;,  &#8220;joann&#8221;, and &#8220;greenfelt&#8221; can launch daemons as themselves and also  &#8220;www-data&#8221;. &#8220;jim&#8221; is only allowed to launch daemons as himself. No  other users on the system are allowed to launch daemons at all  because they weren&#8217;t listed.<\/p>\n<p>The &#8220;manages&#8221; section is a little  experimental at this point, but the idea is that &#8220;david&#8221; is allowed to  manage (start, stop, or restart) the daemons of &#8220;michaelc&#8221;, &#8220;amy&#8221;,  &#8220;joann&#8221;, and &#8220;greenfelt&#8221; in addition to his own daemons. This is so you  can have help desk type users who can stop or restart other users&#8217;  daemons even though they may not have read or write access to the users&#8217;  home directories.<\/p>\n<h3>Daemon: deluged.conf<\/h3>\n<pre><code class=\"language-ini\">dir=\/home\/david\r\nstart=exec deluged -d<\/code><\/pre>\n<p>This  is a simple Daemon Manager config file that launches the deluge  bittorrent client daemon. &#8220;dir&#8221; and &#8220;start&#8221; are the only required  entries in the file. &#8220;dir&#8221; is the working directory and &#8220;start&#8221; is a one  line shell script to run. Because it is a shell script it <em>needs<\/em> to &#8220;exec&#8221;, otherwise Daemon Manager can&#8217;t manage it properly.<sup class='footnote'><a href='#fn-193-2' id='fnref-193-2' onclick='return fdfootnote_show(193)'>2<\/a><\/sup><\/p>\n<h3>Daemon: wordpress.conf<\/h3>\n<pre><code class=\"language-ini\">dir=\/home\/user\/wordpress\r\nuser=www-data\r\nstart=exec php-cgi -q -b wordpress.socket<\/code><\/pre>\n<p>This starts a PHP FastCGI daemon in a WordPress directory and starts it running with as the &#8220;www-data&#8221; user.<\/p>\n<h3>Daemon: greenfelt.conf<\/h3>\n<pre><code class=\"language-ini\">dir=\/var\/www\/greenfelt.net\r\nuser=www-data\r\nstart=exec .\/script\/greenfelt_fastcgi.pl -l greenfelt.socket -n 1\r\noutput=log<\/code><\/pre>\n<p>This is a paraphrase of the config file that runs <a href=\"http:\/\/greenfelt.net\/\">greenfelt.net<\/a> which is a <a href=\"http:\/\/www.catalystframework.org\/\">Catalyst<\/a> app. The &#8220;output&#8221; parameter  tells Daemon Manager to collect the stdout and stderr of the daemon and  save it to a log file in the &#8220;~\/.daemon-manager\/logs\/&#8221; directory.<\/p>\n<h2>Controlling Daemon Manager<\/h2>\n<p>Daemon Manager is controlled using the &#8220;dmctl&#8221; command. It is  relatively simple at this point, allowing you to start, stop and restart  daemons. It also lets you scan for new conf files and query for daemon statistics. Here&#8217;s an example output the &#8220;status&#8221; command:<\/p>\n<pre><code>$ dmctl status\r\ndaemon-id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 state\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 pid respawns cooldown\u00a0\u00a0 uptime\u00a0\u00a0\u00a0 total\r\ndavid\/deluge-web\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 running\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2948\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0 3w3d\u00a0\u00a0\u00a0\u00a0 3w3d\r\ndavid\/deluged\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 running\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2950\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0 3w3d\u00a0\u00a0\u00a0\u00a0 3w3d\r\ndavid\/greenfelt\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 stopped\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\r\ndavid\/minecraft\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 stopped\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\r\ndavid\/moviefile\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 running\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2951\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0 3w3d\u00a0\u00a0\u00a0\u00a0 3w3d\r\ndavid\/pytivo\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 running\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22905\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0 4d7h\u00a0\u00a0\u00a0\u00a0 4d7h\r\ndavid\/streamium\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 running\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2958\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0\u00a0\u00a0 3w3d\u00a0\u00a0\u00a0\u00a0 3w3d\r\ndavid\/wordpress\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 running\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 27012\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 33\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0s\u00a0\u00a0 12h57m\u00a0\u00a0\u00a0\u00a0 3w3d<\/code><\/pre>\n<p>Notice that the wordpress server (good old php-cgi) has crashed 33 times (and has been automatically respawned by Daemon Manager). Also notice that despite FastCGI being the impetus for creating Daemon Manager, most of my running daemons are not actually FastCGI servers.<\/p>\n<h2>Download and Use<\/h2>\n<p>Daemon Manager is licensed under the <a href=\"http:\/\/www.gnu.org\/licenses\/gpl.html\">GPL<\/a> and <a href=\"http:\/\/porkrind.org\/daemon-manager\/\">can be downloaded here<\/a> (the <a href=\"https:\/\/github.com\/caldwell\/daemon-manager\">source is also available on github<\/a>). If you use Debian there&#8217;s a <a href=\"https:\/\/github.com\/caldwell\/daemon-manager\/tree\/debian\">Debian branch<\/a> available for building a package. The version as of this writing is 0.9 which means that there are some obvious things that need to be fixed<sup class='footnote'><a href='#fn-193-3' id='fnref-193-3' onclick='return fdfootnote_show(193)'>3<\/a><\/sup> and that I&#8217;m not sure it&#8217;s 100% secure or bug free yet, though I have boldly started using it on a couple sites and so far it&#8217;s been working great.<\/p>\n<div class='footnotes' id='footnotes-193'>\n<div class='footnotedivider'><\/div>\n<ol>\n<li id='fn-193-1'> That way, if there is a security hole in your code the attacker doesn&#8217;t get access to your main login account. <span class='footnotereverse'><a href='#fnref-193-1'>&#8617;<\/a><\/span><\/li>\n<li id='fn-193-2'> I would like to change that but I&#8217;m having trouble getting dash   (\/bin\/sh on my Debian system) to pass signals onto its child processes. Bash seems to work correctly and so the exec is not needed if \/bin\/sh is bash on your system. <span class='footnotereverse'><a href='#fnref-193-2'>&#8617;<\/a><\/span><\/li>\n<li id='fn-193-3'> The dmctl commands and arguments should be reversed. &#8220;dmctl wordpress stop&#8221; instead of the current &#8220;dmctl stop wordpress&#8221;. <span class='footnotereverse'><a href='#fnref-193-3'>&#8617;<\/a><\/span><\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The idea for Daemon Manager came about when I was converting a web site from Apache to Nginx. Nginx doesn&#8217;t launch FastCGI programs itself\u2014it only connects to FastCGI sockets and so it requires that you manage the FastCGI server yourself. For a simple web site it might be OK to manually create an \/etc\/init.d script, &hellip; <a href=\"https:\/\/porkrind.org\/missives\/introducing-daemon-manager\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Introducing Daemon Manager<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3,10],"tags":[],"class_list":["post-193","post","type-post","status-publish","format-standard","hentry","category-software","category-sysadmin"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/193","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/comments?post=193"}],"version-history":[{"count":57,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/193\/revisions"}],"predecessor-version":[{"id":502,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/193\/revisions\/502"}],"wp:attachment":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/media?parent=193"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/categories?post=193"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/tags?post=193"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}