4.7 Service Examples

The configuration file of the shepherd command (see Invoking shepherd) defines, registers, and possibly starts services. Each service specifies other services it depends on and how it is started and stopped. The configuration file contains Scheme code that uses the programming interface of the (shepherd service) module (see Services).

Let’s assume you want to define and register a service to start mcron, the daemon that periodically executes jobs in the background (see Introduction in GNU mcron Manual). That service is started by invoking the mcron command, after which shepherd should monitor the running process, possibly re-spawning it if it stops unexpectedly. Here’s the configuration file for this one service:

(define mcron
  (service
    '(mcron)
    ;; Run /usr/bin/mcron without any command-line arguments.
    #:start (make-forkexec-constructor '("/usr/bin/mcron"))
    #:stop (make-kill-destructor)
    #:respawn? #t))

(register-services (list mcron))

You can write the snippet above in the default configuration file—~/.config/shepherd/init.scm if you run shepherd as an unprivileged user. When you launch it, shepherd will evaluate that configuration; thus it will define and register the mcron service, but it will not start it. To start the service, run:

herd start mcron

Alternatively, if you want mcron to be started automatically when shepherd starts, you can add this snippet at the end of the configuration file:

(start-in-the-background '(mcron))

Now let’s take another example: sshd, the secure shell daemon of the OpenSSH project. We will pass sshd the -D option so that it does not “detach”, making it easy for shepherd to monitor its process; we also tell shepherd to check its PID file to determine once it has started and is ready to accept connections:

(define sshd
  (service
    '(sshd ssh-daemon)  ;for convenience, give it two names
    #:start (make-forkexec-constructor
             '("/usr/sbin/sshd" "-D")
             #:pid-file "/etc/ssh/sshd.pid")
    #:stop (make-kill-destructor)
    #:respawn? #t))

(register-services (list sshd))
(start-in-the-background '(sshd))

Alternatively, we can start sshd in inetd mode: in that case, shepherd listens for connection and spawns sshd only upon incoming connections. The inetd mode is enabled by passing the -i command-line option:

(define sshd
  (service
    '(sshd ssh-daemon)
    #:start (make-inetd-constructor
             '("/usr/sbin/sshd" "-D" "-i")
             (list (endpoint
                    (make-socket-address AF_INET INADDR_ANY 22))
                   (endpoint
                    (make-socket-address AF_INET6 IN6ADDR_ANY 22)))
             #:max-connections 10)
    #:stop (make-inetd-destructor)
    #:respawn? #t))

(register-services (list sshd))
(start-in-the-background '(sshd))

The make-socket-address procedure calls above return the listening addresses (see Network Socket Address in GNU Guile Reference Manual). In this case, it specifies that shepherd will accept connections coming from any network interface (“0.0.0.0” in IPv4 notation and “::0” for IPv6) on port 22. The endpoint calls wrap these addresses in endpoint records (see endpoints). When a client connects, shepherd accepts it and spawns sshd -D -i as a new transient service, passing it the client connection. The #:max-connections parameter instructs shepherd to accept at most 10 simultaneous client connections.

In these examples, we haven’t discussed dependencies among services—the #:requires keyword of <service>—nor did we discuss systemd-style services. These are extensions of what we’ve seen so far. See Services, for details.

If you use Guix System, you will see that it contains a wealth of Shepherd service definitions. The nice thing is that those give you a complete view of what goes into the service—not just how the service is started and stopped, but also what software package is used and what configuration file is provided. See Shepherd Services in GNU Guix Reference Manual, for more info.