When upgrading MainsailOS to Debian Trixie (aarch64) or copying an old /home/pi backup onto a fresh Trixie install, Klipper, Moonraker, and Crowsnest will all fail to start. The root cause is the same for everything: the old install was 32-bit ARM with Python 3.9, the new image is 64-bit aarch64 with Python 3.13. Every virtualenv, compiled .so, and native binary from the old install is incompatible.
This guide covers the full process: backing up your old install, flashing the new image, restoring your data, and fixing all compatibility issues.
SSH into your Pi and compress the entire home directory:
sudo tar czf /tmp/pi-backup.tar.gz /home/pi/
Then pull the backup to your computer:
Linux / macOS:
scp pi@<your-pi-ip>:/tmp/pi-backup.tar.gz .
Windows (PowerShell):
scp pi@<your-pi-ip>:/tmp/pi-backup.tar.gz $HOME\Downloads\pi-backup.tar.gz
sudo shutdown -h now
Remove the SD card from the Pi.
Use Raspberry Pi Imager or dd to burn the MainsailOS Trixie image onto your SD card. If you're on Windows, you can also use Rufus.
Before inserting the SD card, mount the /boot/firmware partition on your computer and configure as usual:
- Set up WiFi (if not using ethernet) via
network-configorwpa_supplicant.conf - Enable SSH by placing an empty
sshfile in the boot partition - Any other hardware-specific config in
config.txt
On Windows: Insert the SD card — Windows will automatically mount the boot partition (it shows up as a drive in File Explorer). Open it and make your changes there. To create the empty ssh file: right-click in the folder, select New > Text Document, name it ssh (no extension), and confirm when Windows warns about changing the extension. Edit config.txt with Notepad or any text editor.
Insert the SD card, power on the Pi, and SSH in:
ssh pi@<your-pi-ip>
sudo -i
From your computer, push the backup to the Pi:
scp pi-backup.tar.gz pi@<your-pi-ip>:/home/
Then on the Pi (as root):
cd /home
rm -rf pi/
tar xzf pi-backup.tar.gz --strip-components=1
chown -R pi:pi pi/
rm pi-backup.tar.gz
exit
You're now back as the pi user with your old config, macros, and printer data restored. But everything is broken because the binaries and virtualenvs are from the old 32-bit Python 3.9 system.
sudo systemctl stop klipper moonraker crowsnest
cd /home/pi
rm -rf klippy-env
python3 -m venv klippy-env
klippy-env/bin/pip install -r klipper/scripts/klippy-requirements.txt
cd /home/pi
rm -rf moonraker-env
python3 -m venv moonraker-env
moonraker-env/bin/pip install -r moonraker/scripts/moonraker-requirements.txt
rm -f /home/pi/klipper/klippy/chelper/c_helper.so
mkdir -p /home/pi/printer_data/systemd
cat > /home/pi/printer_data/systemd/klipper.env << 'EOF'
KLIPPER_ARGS="/home/pi/klipper/klippy/klippy.py /home/pi/klipper_config/printer.cfg -l /home/pi/klipper_logs/klippy.log -a /home/pi/printer_data/comms/klippy.sock"
EOF
Note: Adjust paths if your config lives in
/home/pi/printer_data/config/instead of/home/pi/klipper_config/.
grep -q klippy_uds_address /home/pi/klipper_config/moonraker.conf || \
sed -i '/^\[server\]/a klippy_uds_address: /home/pi/printer_data/comms/klippy.sock' /home/pi/klipper_config/moonraker.conf
The service file incorrectly calls /bin/python3 but crowsnest is a bash script:
sudo sed -i 's|ExecStart=/bin/python3 $CROWSNEST_ARGS|ExecStart=/bin/bash /home/pi/crowsnest/crowsnest $CROWSNEST_ARGS|' /etc/systemd/system/crowsnest.service
sudo systemctl daemon-reload
sudo apt install -y libevent-dev libjpeg-dev libbsd-dev
cd /home/pi/crowsnest/bin/ustreamer
make clean && make -j4
sudo systemctl restart klipper moonraker crowsnest
sudo systemctl status klipper moonraker crowsnest
All three services should show active (running). Mainsail should be accessible at http://<your-pi-ip> with Klipper connected and webcam streaming.
After restore, sonar.service enters a crash-restart loop with:
sonar.service: Failed to load environment files: No such file or directory
sonar.service: Failed to spawn 'start' task: No such file or directory
sonar.service: Failed with result 'resources'.
The systemd unit references /home/pi/printer_data/systemd/sonar.env, which was not recreated on restore. The unit runs Sonar as /usr/bin/python3 $SONAR_ARGS, and this version of Sonar takes the config path as a positional argument (no -c / -l flags).
Recreate the env file, make sure the config exists under printer_data/config/, and enable Sonar:
# Recreate the missing env file (positional config path — no flags)
cat > /home/pi/printer_data/systemd/sonar.env << 'EOF'
SONAR_ARGS="/home/pi/sonar/sonar.py /home/pi/printer_data/config/sonar.conf"
EOF
# Make sure sonar.conf lives where the env file points at
mkdir -p /home/pi/printer_data/config
[ -f /home/pi/printer_data/config/sonar.conf ] || \
cp /home/pi/sonar/resources/sonar.conf /home/pi/printer_data/config/sonar.conf
# Flip `enable` to true so Sonar actually runs (defaults to false in the template)
sed -i 's/^enable: .*/enable: true/' /home/pi/printer_data/config/sonar.conf
# Fix ownership, clear the failure counter, restart
chown pi:pi /home/pi/printer_data/systemd/sonar.env /home/pi/printer_data/config/sonar.conf
sudo systemctl reset-failed sonar.service
sudo systemctl restart sonar.service
sudo systemctl status sonar.service --no-pager
Verify:
systemctl is-active sonar.service # → active
systemctl show sonar.service -p NRestarts # → NRestarts=0 (stays flat)
journalctl -u sonar.service -n 15 --no-pager
The journal should show Configuration loaded: followed by enable: True and then stay quiet — no "Sonar is disabled… Exiting" line, no restart-counter climb.
Why it matters: a crash-looping Sonar fires systemd every ~5 s. On a Pi 3B+ that background jitter is enough to contribute to Klipper "Timer too close" MCU shutdowns on long prints.
- OS: MainsailOS 3.0.0-alpha2 (Debian Trixie)
- Arch: aarch64 (64-bit)
- Python: 3.13.5
- Hardware tested: Raspberry Pi 3 Model B+ (Voron with CANbus)
sudo systemctl stop klipper moonraker crowsnest && \
cd /home/pi && \
rm -rf klippy-env && python3 -m venv klippy-env && klippy-env/bin/pip install -r klipper/scripts/klippy-requirements.txt && \
rm -rf moonraker-env && python3 -m venv moonraker-env && moonraker-env/bin/pip install -r moonraker/scripts/moonraker-requirements.txt && \
rm -f klipper/klippy/chelper/c_helper.so && \
mkdir -p printer_data/systemd && \
cat > printer_data/systemd/klipper.env << 'ENVEOF'
KLIPPER_ARGS="/home/pi/klipper/klippy/klippy.py /home/pi/klipper_config/printer.cfg -l /home/pi/klipper_logs/klippy.log -a /home/pi/printer_data/comms/klippy.sock"
ENVEOF
grep -q klippy_uds_address klipper_config/moonraker.conf || \
sed -i '/^\[server\]/a klippy_uds_address: /home/pi/printer_data/comms/klippy.sock' klipper_config/moonraker.conf && \
sudo sed -i 's|ExecStart=/bin/python3 $CROWSNEST_ARGS|ExecStart=/bin/bash /home/pi/crowsnest/crowsnest $CROWSNEST_ARGS|' /etc/systemd/system/crowsnest.service && \
sudo systemctl daemon-reload && \
sudo apt install -y libevent-dev libjpeg-dev libbsd-dev && \
cd crowsnest/bin/ustreamer && make clean && make -j4 && \
cat > /home/pi/printer_data/systemd/sonar.env << 'SONAREOF'
SONAR_ARGS="/home/pi/sonar/sonar.py /home/pi/printer_data/config/sonar.conf"
SONAREOF
[ -f /home/pi/printer_data/config/sonar.conf ] || cp /home/pi/sonar/resources/sonar.conf /home/pi/printer_data/config/sonar.conf && \
sed -i 's/^enable: .*/enable: true/' /home/pi/printer_data/config/sonar.conf && \
chown pi:pi /home/pi/printer_data/systemd/sonar.env /home/pi/printer_data/config/sonar.conf && \
sudo systemctl reset-failed sonar.service && \
sudo systemctl restart klipper moonraker crowsnest sonar && \
sudo systemctl status klipper moonraker crowsnest sonar