Skip to content

Deploying on systemd

This target suits a server with no platform. PostgreSQL and a front end such as nginx are yours to set up, if you want them. This guide uses an application named guestbook.

Export the units

$ myxo export layouts/app.toml systemd --name guestbook --out units
units/guestbook-migrate.service
units/guestbook@.service
units/guestbook.target
units/env.example
File What it does
guestbook-migrate.service a one-shot unit that runs the migrations
guestbook@.service a template that runs each process, once the migrations are done
guestbook.target starts every process
guestbook@PROCESS.service.d/privileges.conf the sandbox, for each process with privileges = "reduced"
env.example the variables the layout reads

The units expect the layout at /etc/guestbook/layout.toml, and myxo at /opt/guestbook/bin/myxo. --path and --command change these.

Every unit has /var/lib/guestbook as its working directory. Only the application's user can open that directory, which lasts across reboots. Every unit therefore finds a relative SQLite file, or a relative Unix socket, in the same place.

Prepare what you deliver

The server needs an environment with Myxo and your application in /opt/guestbook. To build one, E10 made a tarball with its own interpreter, in a Linux container at that same path. The script is experiments/e10_targets/systemd/build.sh.

Compile the bytecode

Install with --compile-bytecode. The service's user cannot write .pyc files under /opt, so an install without them compiles every module at each start. E10 measured 6.7 to 8.3 s per process without them, against 0.6 s with them.

Install

Run these as root, from a directory holding the tarball, the layout and the units:

# useradd --system --no-create-home --shell /usr/sbin/nologin guestbook
# tar -xzf guestbook.tar.gz -C /opt
# install -D -m 644 layout.toml /etc/guestbook/layout.toml
# install -m 600 units/env.example /etc/guestbook/env
# cp -r units/*.service units/*.target /etc/systemd/system/
# systemctl daemon-reload
# systemctl enable --now guestbook.target

Fill in /etc/guestbook/env before the last command, since it holds your secrets. Uncomment what you set: DATABASE_URL=postgresql://..., for one. If the layout has reduced processes, copy their *.service.d directories too.

Operate it

# systemctl status 'guestbook@*'
# journalctl -u guestbook@web -f
# systemctl restart guestbook@worker

systemd restarts a process that dies, after 2 s. Inside each process, the runtime restarts its services. A process that gives up on a service exits with status 1, and systemd starts it again.

Limits

  • One instance of each process: the export refuses more.
  • The script experiments/e10_targets/systemd/install.sh is the form these commands were tested in, on a fresh Debian 13 machine.
  • The sandbox was only partly checked. The system-call filter applied, while OrbStack's containers turn ProtectSystem and NoNewPrivileges off for every service. Check it on your machine with systemd-analyze security guestbook@worker.