Build the J1S Pi image¶
The snapmaker_moonraker repo ships a CI pipeline that builds a turnkey Raspberry Pi 3 SD card image with Mainsail, the bridge, and (optionally) klipper-nfc-daemon pre-installed.
What's on the image¶
| Software | Role |
|---|---|
| Raspberry Pi OS Lite (Bookworm, 32-bit) | Base OS |
| nginx | Serves Mainsail on port 80, proxies /server and /websocket to the bridge |
| Latest upstream Mainsail release | Web UI |
snapmaker_moonraker |
Bridge to the J1S, systemd unit snapmaker-moonraker.service |
klipper-nfc-daemon |
Optional NFC daemon, nfc-spoolman.service |
| SSH enabled | pi / temppwd — change before exposing to a network |
Build with the Jenkins agent¶
The CI pipeline uses a Docker image with all build deps. Build it locally with:
cd snapmaker_moonraker
docker build --network=host -t snapmaker-jenkins-agent -f image/Dockerfile.jenkins-agent .
Inside the agent, the pipeline:
- Cross-compiles the bridge for armv7
- Mounts a base Pi OS Lite image in QEMU
- Runs
image/chroot-install.shto install Mainsail, the bridge, the NFC daemon, and the nginx config - Compresses the result to
snapmaker-moonraker-rpi3-YYYYMMDD.img.xz
Build locally (without Jenkins)¶
# Cross-compile
GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 \
go build -ldflags="-s -w" -o snapmaker_moonraker-armv7 .
# Build the image (requires sudo for loop mount / chroot)
sudo image/build-image.sh snapmaker_moonraker-armv7
Output: snapmaker-moonraker-rpi3-YYYYMMDD.img.xz in the working
directory.
Flash and boot¶
# Decompress
xz -d snapmaker-moonraker-rpi3-YYYYMMDD.img.xz
# Flash (replace /dev/sdX with your SD card)
sudo dd if=snapmaker-moonraker-rpi3-YYYYMMDD.img of=/dev/sdX bs=4M status=progress
sync
Insert into the Pi, boot, find it on the network at hostname
snapmaker (mDNS) or via your router.
First-boot configuration¶
SSH in:
- Change the password:
passwd - Point at your J1S:
Set
printer.ipandprinter.token(the J1S HMI prompts on first connect). - Restart the bridge:
sudo systemctl restart snapmaker-moonraker - Point at Spoolman (if running):
Set
[spoolman] url. - Restart the NFC daemon:
sudo systemctl restart nfc-spoolman
Verify¶
# Bridge talking to printer
curl -s http://localhost:7125/printer/info | jq .
# Mainsail loading
curl -sI http://localhost/ | head -1
# NFC daemon healthy
journalctl -u nfc-spoolman -n 50
Open a browser to http://<pi-ip>/. Mainsail should connect and start
showing live status from the J1S.
Logs and recovery¶
| What | Where |
|---|---|
| Bridge stdout/stderr | journalctl -u snapmaker-moonraker (note SyslogIdentifier) |
| NFC daemon | journalctl -u nfc-spoolman + ~/printer_data/logs/nfc_spoolman.log |
| nginx access/error | /var/log/nginx/access.log, /var/log/nginx/error.log |
| Mainsail console | Browser devtools |
Common gotchas¶
- Token mismatch → bridge logs
auth failed. Re-enter the token inconfig.yamland restart. - OOM kills on uploads → fixed in v1.6.0 (streaming pipeline). If you're on an older build, upgrade — see J1S upload workflow.
- Mainsail says "Disconnected" → check
systemctl status snapmaker-moonraker; the bridge probably can't reach the J1S (network change, J1S off).