Multiple OctoPrint Instances using systemd

This is a “work in progress”, which I have only tested for a few days. It workes fine, but there could be issues not yet found.

This article is based on my other article about setting up OctoPrint on a regular (x86_64) computer system running Ubuntu (Server) Linux.

Recently, I got a second 3D printer and since OctoPrint works very nicely with the first one, I wanted the same for both of them. Officially OctoPrint doesn’t support using multiple printers at the same time. Still, it is possible to run multiple instances of the (Python-based) OctoPrint software using different directories and port numbers. The main goal is to keep them separated from each other.

There is a very detailed article from Thomas Messmer about running multiple OctoPrint instances on an OctoPi image/installation on a Raspberry Pi 4. Even if you don’t use a RasPi, I still recommend to check it out, since most changes are the same for a regular system! Here, I will only concentrate on the systemd part, since OctoPi doesn’t use it by default and therefore it isn’t explained in the article.

systemd unit file templates

systemd supports running multiple instances of the same software, by using so called Template Unit Files. These files only differ from regular unit files by using an instance parameter (%i). The unit files using such a parameter, are named, for example, octoprint@.service (Note the @ right before the file name extension!). Actual instances of these units need to use an unique identifier, like a name or a number. They are simply created by enabling a new service:

# systemctl enable --now octoprint@foo.service
(This will create a systemd symlink for this service)

In this example, every %i, inside the unit file, will be replaced by foo.

OctoPrint unit template

The pattern I want to implement looks like this. Note, that the suffix for the directory and the last digit of the port number are the same:

  1. Instance #1 uses folder .octoprint1 and runs on port 5001
  2. Instance #2 uses folder .octoprint2 and runs on port 5002
  3. Instance #3 uses folder .octoprint3 and runs on port 5003
  4. […]

First the running “single” OctoPrint service should be stopped and removed, since it will get a new unit file:

# systemctl stop octoprint.service
# systemctl disable octoprint.service

You may also remove the octoprint.service file in /etc/systemd/system (or rename and reuse it, see below).

To keep things simple, my basic idea was to use incrementing integer numbers as parameters and simply run these different instances, starting at port 5001 (or 5000 with 0 as the first number). To do this, it’s necessary to explicitly set a individual base dir path and a path to the individual configuration file (config.yaml), as well as a unique port number for instance to bind to. This is the template file I came up with. The parameter %i will be replaced by a individual number, when the service is created/started:

[Unit]
Description=OctoPrint (Instance #%i) - Open Source Printing Interface for 3D Printers 
Documentation=https://docs.octoprint.org
After=network.target

[Service]
User=octoprint
Environment=HOME=/home/octoprint
WorkingDirectory=/home/octoprint/.octoprint%i
ExecStart=/usr/bin/python2 /home/octoprint/.local/bin/octoprint --basedir /home/octoprint/.octoprint%i --config /home/octoprint/.octoprint%i/config.yaml --port 500%i serve
Restart=always
RestartSec=120

[Install]
WantedBy=multi-user.target

For this to work, I renamed the existing .octoprint configuration directory in /home/octoprint to .octoprint1 and then made a copy of the same folder for a second instance called .octoprint2:

# cd /home/octoprint
# mv .octoprint .octoprint1
# cp -R .octoprint1 .octoprint2
[...]
# chown -R octoprint:octoprint .octoprint*

For more than two instances, I would simply create more copies of this directory and enable more services (see below) using the same number suffix.

After that, the actual instances can be created/enabled and started:

# systemctl enable --now octoprint@1.service
(This will create a link and start the service.)
# systemctl enable --now octoprint@2.service
(The same thing for the second instance.)
# systemctl status octoprint@1.service
(Optional. Will show some information about the service #1)

If everything else is setup correctly, the multiple OctoPrint services should be available at ports 5001 and 5002. You should login and change the printer configuration, name and default serial port and maybe also select a individual theme color for the GUI, to keep them apart more easily.

If the service is allowed to restart itself, the command entered in the OctoPrint configuration menu needs to be changed and the sudoers file needs to be updated accordingly:

octoprint ALL = NOPASSWD: /bin/systemctl start octoprint@[0-9].service
octoprint ALL = NOPASSWD: /bin/systemctl stop octoprint@[0-9].service
octoprint ALL = NOPASSWD: /bin/systemctl restart octoprint@[0-9].service
[...]

This will allow the user octoprint to start, restart and stop up to ten instances of OctoPrint (nine, if you don’t count the zero).

Possible Issues

For now, this setup works fine for me. One minor issue I found, is, that all instances share the same Python installation and libraries. So if a Plug-In is installed or updated, the other won’t know about this and will (re)install the same package(s) again. I also don’t know yet what happens if OctoPrint itself gets updated.

Leave a Reply

Your email address will not be published. Required fields are marked *