daemontools is a collection of tools for managing UNIX services.
These are a collection of best practices I’ve found useful when working with Daemontools. Use as you see fit, and please, tell me if you find a factual error or want to improve the list. There is also the comment form at the bottom of this page.
There is no need for each daemon to know how to drop privileges, unless the daemon must do privileged operations, such as opening port 80. When the daemon can be brought up with the correct credentials, things are much simpler. In other words, use setuidgid liberally.
You should be aware that
setuidgid sets both the user and group.
Logging STDOUT / STDERR safely
Daemontools knows how to pipe
stdout from the daemon to another process, the latter being a logging daemon. Because daemontools looks for
log/run, the logging tool will be supervised as well, ensuring it will always run. A simple and dumb example of
/service/carbon/log/run would be:
1 #!/bin/bash 2 PATH=/usr/local/bin:/usr/bin:/bin 3 exec cat > /var/log/carbon.log
It’s simple because it works: you can tail the file from outside and know if things are running well. It’s a dumb unless you setup logrotate, because the file will be unbounded. It’s also a dumb because
cat may be signaled at any time and will stop immediately, rather than delaying until it’s found a newline, and may thus lose data. Instead, you’re better off using
1 #!/bin/bash 2 PATH=/usr/local/bin:/usr/bin:/bin 3 exec multilog t s10485760 n5 '!tai64nlocal' /var/log/carbon
This isolates the log file to
multilog also keeps metadata about it’s log files in the same directory. Of course, this implies the directory already exists. We can remedy that:
1 #!/bin/bash 2 PATH=/usr/local/bin:/usr/bin:/bin 3 mkdir -p /var/log/carbon 4 exec multilog t s10485760 n5 '!tai64nlocal' /var/log/carbon
And now, the only problem left is
multilog is running as root. Again, let’s remedy the situation:
1 #!/bin/bash 2 PATH=/usr/local/bin:/usr/bin:/bin 3 mkdir -p /var/log/carbon 4 chown -R carbon:carbon 5 exec setuidgid carbon multilog t s10485760 n5 '!tai64nlocal' /var/log/carbon
The strange incantations to
multilog represent a script. In this case, it’s a simple script, but
multilog supports writing to multiple files and log rotations at different sizes for different directories.
The script I’ve shown above breaks down like this:
t means to prepend a TAI timestamp on each line;
s10485760 n5 means to rotate the log file every 10 MiB, and keep 5 history files around;
!tai64nlocal (escaped because we’re in a Shell script, and
! has special meaning in the shell) means that on rotation, run the file through the named program.
tai64nlocal program simply reads
stdin and replaces TAI timestamps with human-readable ones. If you want to gzip the file on rotation, prepend
'!gzip' to the directory and
multilog will take care of it.
If your daemon also logs to
stderr, you may redirect
1 #!/bin/bash 2 PATH=/usr/local/bin:/usr/bin:/bin 3 mkdir -p /var/log/carbon 4 chown -R carbon:carbon /var/log/carbon 5 exec 2>&1 6 exec setuidgid carbon multilog t s10485760 n5 '!tai64nlocal' /var/log/carbon
The magic happens with
exec 2>&1. This is Bash-speak for
redirect , which we can then handle with
multilog. This may be a problem because most programs write to STDOUT in a buffered manner, while they write to STDERR with no buffering. This may interleave the output of both streams in the final log file.
Secure your environment variables
Your environment variables will contain passwords, and you don’t want those files to be world-readable. Set your environment’s directory permissions to 0700, and the individual files to 0600. Then, ensure you always setuidgid last in your
run scripts (as illustrated above).
multilog’s documentation is rather sparse, to say the least.