Daemontools

As i was running Linux-VServer, i couldn’t use runit (that is, i couldn’t figure how to do it); so i was using daemontools.

As inittab doesn’t work within a vserver, you need an init script (see attachment attachment:svscan) to start svscan; i used http://flounder.net/qmail/svscan-init as a template for that (i don’t know how google found that, as it seems no site links this file, and the site seems down now).

Services

The basic idea is always the same; you have a daemon and a log daemon; the start scripts are named “run”.

I maintain the services in /etc/sv/, and symlink the services i want to run to /etc/service.

You could use different log users, i chose to just use always the same user log and to put the logs into /var/log/sv/*/:

1
$ adduser --system --home /nonexistent --no-create-home --disabled-password --disabled-login log

Base setup for $service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
cd /etc/sv/
mkdir "$service"
cd "$service"
vim run
chmod +x run
mkdir -p log

# put log files into /var/log/sv/$service
mkdir -p "/var/log/sv/$service"
ln -s "/var/log/sv/$service" log/main

echo -e '#!/bin/bash\nexec setuidgid log multilog t ./main\n' > log/run
chmod +x log/run
chown log:nogroup log/run log/main

# let it create supervise dirs into /var/run/
ln -s "/var/run/sv.$service" supervise
ln -s "/var/run/sv.$service.log" log/supervise

# start it now
ln -s "/etc/sv/$service" /etc/service

The examples below will only describe the main run and additional files.

spawn-fcgi

You will need the spawn-fcgi program; you can use the one from http://cgit.stbuehler.de/gitosis/spawn-fcgi/about/ (“version 2.0”, debian packages are in my repo http://debian.stbuehler.de), or version 1.6.x from http://redmine.lighttpd.net/projects/spawn-fcgi (which doesn’t support the -l option yet, so you have to set limits directly via ulimit if you want them).

Don’t use the one from older lighttpd versions (1.4 and 1.5), as it doesn’t support some important options (-U, -G), and you need an extra wrapper script of the following form (e.g. as ./php in your service directory):
If you have to, you can use something like this (i really recommend using 1.6.x or 2.0):

1
2
3
4
5
6
#!/bin/sh

# chown socket so webserver can access it
chown www-data:www-data /var/run/lighttpd/yourphpsocketname.sock
# change user for target application
exec setuidgid yourphpuser /usr/bin/php5-cgi

And use a run script like this:

1
2
3
4
5
#!/bin/sh

exec 2>&1
# do not change user here, as we need to be root to chown the socket!
exec /usr/sbin/spawn-fcgi -f./php -s /var/run/lighttpd/yourphpsocketname.sock -n

Examples

The examples assume you are using my spawn-fcgi, read previous section for details.

spawn-fcgi options:

  • “-u” username: change user for target application (and use his primary group)
  • “-s” socket: bind to specified socket file (use this filename in lighttpd config)
  • “-n” : don’t fork
  • “-f fcgiapp”: run fcgiapp as application. Not used in the following examples, as you can specify it after -- too with params for the target application.

The following two are not supported by lighty’s spawn-fci 1.4/1.5:

  • -U username: change user of the unix-domain socket (and use his primary group)
  • -l : use limits for the user specified with -u from /etc/security/limits.conf (this is only supported in 2.0)

PHP

To restart a php service use svc -t $service instead of svc -h $service (at least that is how it works for me)

$service/run:

1
2
3
4
#!/bin/sh

exec 2>&1
exec /usr/bin/spawn-fcgi -s /var/run/lighttpd/php-webuser.sock -n -u webuser -U www-data -l -- /usr/bin/php5-cgi

The lighttpd config for this looks like this:

1
2
3
4
        fastcgi.server = (
            ".php" =>
                ( "local" => ( "socket" => "/var/run/lighttpd/yourphpsocketname.sock" ) ),
        )

Rails (redmine in my case)

$service/run:

1
2
3
4
5
6
7
8
#!/bin/sh

exec 2>&1

export RAILS_ENV=production
export LANG=en_US.UTF-8

exec /usr/bin/spawn-fcgi -s /var/run/lighttpd/rails-user.sock -n -u railsuser -U www-data -l -- /path/to/railapp/dispatch.fcgi

Lighttpd config part (needs http://nordisch.org/cleanurl.lua from http://nordisch.org/):

1
2
3
4
5
6
7
8
        server.document-root = "/path/to/railapp/public"
        magnet.attract-physical-path-to = ( "/etc/lighttpd/cleanurl-v5.lua" )
        fastcgi.server    = ( "dispatch.fcgi" =>
                ((
                        "socket" => "/var/run/lighttpd/rails-user.sock",
                        "broken-scriptfilename" => "enable"
                ))
        )

TurboGears

$service/run:

1
2
3
4
5
6
#!/bin/sh

exec 2>&1

cd /path/to/project
exec /usr/bin/spawn-fcgi -s /var/run/lighttpd/project-user.sock -n -u tguser -U www-data -l -- /path/to/project/start-project-fcgi.py prod.cfg

You need a fastcgi starter (/path/to/project/start-project-fcgi.py) for turbogears, i use something like that (replace project with your project name):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
import pkg_resources
import cherrypy
import sys

cherrypy.lowercase_api = True

pkg_resources.require("TurboGears")

from cherrypy._cpwsgi       import wsgiApp
from flup.server.fcgi       import WSGIServer
from os.path                import *

import turbogears

if len(sys.argv) > 1:
    configfile = sys.argv[1]
elif exists(join(dirname(__file__), "setup.py")):
    configfile = "dev.cfg"
else:
    configfile = "prod.cfg"

turbogears.update_config(configfile=configfile, modulename="project.config")

from project.controllers import Root

cherrypy.root = Root()

cherrypy.server.start(initOnly=True, serverClass=None)

WSGIServer(application=wsgiApp).run()

lighttpd config part:

1
2
3
4
5
6
7
8
        fastcgi.server = (
                "/" =>
                ( "local" => (
                        "socket" => "/var/run/lighttpd/project-user.sock",
                        "check-local" => "disable",
                        "broken-scriptfilename" => "enable",
                ) ),
        )

git-daemon

Share the gitosis repositories, if they are configured as “daemon=yes” (there is a git-daemon-run package in debian; it doesn’t use the gitosis user of course).

$service/run:

1
2
3
4
5
6
7
#!/bin/sh

exec 2>&1
exec $(git --exec-path)/git-daemon \
        --user=gitosis --group=gitosis \
        --reuseaddr \
        --base-path=/var/cache/gitosis/repositories

Generated using nanoc and bootstrap - Last content change: 2012-11-24 16:14