Running Rocrail as a systemd service
A systemd unit that starts the Rocrail server at boot, restarts it if it dies, and runs it as an unprivileged user.
Rocrail launched from a terminal dies with the terminal and does not survive a reboot. On a machine whose whole job is controlling a layout, it should start itself and stay started.
The unit file
Create /etc/systemd/system/rocrail.service:
[Unit]
Description=Rocrail model railway control server
Documentation=https://wiki.rocrail.net/
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=rocrail
Group=rocrail
WorkingDirectory=/opt/rocrail
ExecStart=/opt/rocrail/rocrail -l /opt/rocrail -w /opt/rocrail
Restart=on-failure
RestartSec=10
# Rocrail needs nothing beyond its own directory, so give it nothing else.
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/opt/rocrail
[Install]
WantedBy=multi-user.target
Adjust WorkingDirectory, ExecStart and ReadWritePaths to wherever your installation
actually lives.
Why these settings
After=network-online.target rather than plain network.target. Rocrail opens a TCP
connection to the command station at startup; starting before the network is genuinely up
means that connection fails and Rocrail sits there unhappy. network-online.target waits for
an actual usable network.
Restart=on-failure with RestartSec=10. If Rocrail exits with an error it comes back ten
seconds later. The delay matters — without it, a service that fails instantly gets restarted in
a tight loop and systemd eventually gives up and leaves it stopped.
A dedicated rocrail user. There is no reason for this to run as root. It needs its own
directory and a network socket, nothing more.
The Protect* lines. Standard systemd hardening: no access to home directories, read-only
system directories, private /tmp. ReadWritePaths then punches through ProtectSystem=full
for the one directory Rocrail genuinely needs to write to.
Setting it up
Create the user and hand over the directory:
sudo useradd --system --home-dir /opt/rocrail --shell /usr/sbin/nologin rocrail
sudo chown -R rocrail:rocrail /opt/rocrail
Then enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now rocrail
Checking it works
systemctl status rocrail
You want active (running) and enabled. Enabled is the half people forget — a service can be
running perfectly and still not come back after a reboot.
Follow the log as it starts:
journalctl -u rocrail -f
You are looking for the command station connecting and reporting its firmware version. If it does not, the problem is the controller settings rather than systemd — see Rocrail and DCC-EX.
Actually reboot the machine and confirm Rocrail comes back on its own. A unit file that looks
correct and a unit file that works are not the same thing, and the gap between them is usually
a missing enable or a permissions problem on the working directory.
If it will not start
status=203/EXEC— the path inExecStartis wrong, or the binary is not executable.- Permission denied in the log — the
rocrailuser cannot write to its working directory. Check thechown, and checkReadWritePathscovers it. - Starts then immediately exits — run the same
ExecStartcommand by hand as therocrailuser and read what it prints. systemd will not show you a message that Rocrail wrote to a terminal before exiting.