Edit this page | Blame

Guix system containers and how we use them

Our preferred way to deploy long-running services is to use Guix system containers. Note that Guix system containers are different from guix shell containers (and the older guix environment containers). guix shell containers are meant for interactive use and are a poor fit for long running services. Other non-Guix ways such as running long-running processes in tmuxes, running long-running services from your development repository, etc. are a quick dirty way to get things done.

Guix system containers are fully described by a configuration file that, among other things, specifies the services run in it. These scheme configuration files are built using `guix system container' and produce a script. This script, when run, starts the described container.

$ guix system container foo.scm

One cool aspect is that system containers can be easily tested on your own laptop. A great tutorial can be found at

A system container comes with a running shepherd process and running services are explicitly configured.

Our most important containers are defined in

Share network with the host

Usually, we want the container to share the network with the host. So, we add the --network flag.

$ guix system container --network foo.scm

Adding state to Guix system containers

Guix system containers are completely ephemeral, that is, they have no persistent state. But often, we have services that need to retain some state. Think a database server needing to persist its database directory, a web server needing to persist its logs, etc. To allow this persistence, we expose (read-only) or share (read-write) directories from the host into the container.

$ guix system container --network --share=/var/lib/foo foo.scm

systemd services to manage the container processes

Now, running these container scripts directly from the command-line, probably from within a tmux, makes for a very fragile deployment. So, we symlink the script into /usr/local/bin and set up a systemd service to manage the container process.

# ln --force --symbolic $(guix system container --network --share=/var/lib/foo foo.scm) /usr/local/bin/foo-container

A systemd service file foo-container.service for this container should be put at /etc/systemd/system/.

Description = Run foo container

ExecStart = /usr/local/bin/foo-container

WantedBy = multi-user.target

This allows us to start, stop and enable (for starting at boot time) the container easily.

# guix system start foo-container
# guix system stop foo-container
# guix system enable foo-container

With our service enabled to start at boot time, we need not worry about reboots. All our containers, and the services contained therein, start up smoothly on boot.

Register as garbage collector root

Finally, we must also tell Guix not to accidentally garbage collect our container or any of its dependencies. To this end, we symlink it into /var/guix/gcroots.

# ln --force --symbolic /usr/local/bin/foo-container /var/guix/gcroots


On tux02 we run CI/CD system containers. The systemd config is simple:

Description = Run genenetwork development container

ExecStart = /usr/local/bin/genenetwork-development-container

WantedBy = multi-user.target

where /usr/local/bin/genenetwork-development-container -> /gnu/store/8rkh8yjzqhcr3s5zl9mw8y4jh44fr5pr-run-container

The code is currently running from Arun's $HOME from the git repo at

Probably worth reading the

Here we focus on the production server setup running on test01:

Debugging and development


(made with skribilo)