Links

Manual setup

Operating System

Please do not use an OctoPi image, as it can cause unforeseen (avoidable) problems.
Don’t forget to enable SSH and configure a network if using Wi-Fi.
It is recommended to use a clean Raspberry Pi OS 32-bit Lite image. If you don't use a Raspberry Pi as SBC, every default Debian Buster / Bullseye (recommended) should also fit with this guide.
We recommend you follow the Raspberry Pi OS official documentation to flash and install the operating system to your SD card.
Once you have finished the installation and are connected via SSH, you can continue.

Requirements

Install the required packages and update the system:
Debian 11 (Bullseye)
Debian 10 (Buster)
sudo apt update && sudo apt upgrade -y
sudo apt install git unzip
sudo apt update --allow-releaseinfo-change && sudo apt upgrade --yes
sudo apt install git unzip

Klipper

Installation

At first we have to install some OS dependencies:
Debian 11 (Bullseye)
Debian 10 (Buster)
sudo apt install python3-virtualenv python3-dev python3-dev libffi-dev build-essential libncurses-dev avrdude gcc-avr binutils-avr avr-libc stm32flash dfu-util libnewlib-arm-none-eabi gcc-arm-none-eabi binutils-arm-none-eabi libusb-1.0-0 libusb-1.0-0-dev
sudo apt install python3-virtualenv python3-dev python3-dev libffi-dev build-essential libncurses-dev libusb-dev avrdude gcc-avr binutils-avr avr-libc stm32flash dfu-util libnewlib-arm-none-eabi gcc-arm-none-eabi binutils-arm-none-eabi libusb-1.0
The following commands will clone Klipper to an appropriate directory in HOME.
cd ~
git clone https://github.com/KevinOConnor/klipper
Then we can initialize the python virtual environment and install the python dependencies:
cd ~
virtualenv -p python3 ./klippy-env
./klippy-env/bin/pip install -r ./klipper/scripts/klippy-requirements.txt

Configuration & startup service

After Klipper is installed, you will need to create the file structure vor Klipper & Moonraker.
mkdir ~/printer_data/
mkdir ~/printer_data/config
mkdir ~/printer_data/logs
mkdir ~/printer_data/gcodes
mkdir ~/printer_data/systemd
mkdir ~/printer_data/comms
touch ~/printer_data/config/printer.cfg
To create a service file for Klipper use:
sudo nano /etc/systemd/system/klipper.service
fill in these lines:
[Unit]
Description=Klipper 3D Printer Firmware SV1
Documentation=https://www.klipper3d.org/
After=network-online.target
Before=moonraker.service
Wants=udev.target
​
[Install]
Alias=klippy
WantedBy=multi-user.target
​
[Service]
Type=simple
User=pi
RemainAfterExit=yes
WorkingDirectory=/home/pi/klipper
EnvironmentFile=/home/pi/printer_data/systemd/klipper.env
ExecStart=/home/pi/klippy-env/bin/python $KLIPPER_ARGS
Restart=always
RestartSec=10
Save the file with CTRL+O and close the editor with CTRL+X.
Next step, you have to create an Klipper environment file in your printer_data:
nano ~/printer_data/systemd/klipper.env
fill in these line:
KLIPPER_ARGS="/home/pi/klipper/klippy/klippy.py /home/pi/printer_data/config/printer.cfg -l /home/pi/printer_data/logs/klippy.log -I /home/pi/printer_data/comms/klippy.serial -a /home/pi/printer_data/comms/klippy.sock"
Save the file with CTRL+O and close the editor with CTRL+X.
Please check and modify the username! If you do not use the user pi, you must replace it in each path and in the variable User in the service file.
To enable and start the Klipper service execute these commands:
sudo systemctl enable klipper.service
After your config is in place, restart Klipper with sudo systemctl start klipper.

Moonraker

Moonraker is a web server that exposes APIs which lets Mainsail interact with Klipper.

Installation

At first we have to install some OS dependencies:
Debian 11 (Bullseye)
Debian 10 (Buster)
sudo apt install python3-virtualenv python3-dev libopenjp2-7 python3-libgpiod curl libcurl4-openssl-dev libssl-dev liblmdb-dev libsodium-dev zlib1g-dev libjpeg-dev packagekit wireless-tools
sudo apt install python3-virtualenv python3-dev libopenjp2-7 python3-libgpiod curl libcurl4-openssl-dev libssl-dev liblmdb-dev libsodium-dev zlib1g-dev libjpeg-dev packagekit wireless-tools
Clone Moonraker into your HOME directory:
cd ~
git clone https://github.com/Arksine/moonraker.git
Then we can initialize the python virtual environment and install the python dependencies:
cd ~
virtualenv -p python3 ./moonraker-env
./moonraker-env/bin/pip install -r ./moonraker/scripts/moonraker-requirements.txt

Configuration

Please pay attention to the following steps! A very common source of errors are improperly configured trusted_clients.
For Moonraker you’ll need to create a separate config file.
nano ~/printer_data/config/moonraker.conf
Insert the following part:
[server]
host: 0.0.0.0
port: 7125
# The maximum size allowed for a file upload (in MiB). Default 1024 MiB
max_upload_size: 1024
# Path to klippy Unix Domain Socket
klippy_uds_address: ~/printer_data/comms/klippy.sock
​
[file_manager]
# post processing for object cancel. Not recommended for low resource SBCs such as a Pi Zero. Default False
enable_object_processing: False
​
[authorization]
cors_domains:
*://my.mainsail.xyz
*://*.local
*://*.lan
trusted_clients:
10.0.0.0/8
127.0.0.0/8
169.254.0.0/16
172.16.0.0/12
192.168.0.0/16
FE80::/10
::1/128
​
# enables partial support of Octoprint API
[octoprint_compat]
​
# enables moonraker to track and store print history.
[history]
​
# this enables moonraker announcements for mainsail
[announcements]
subscriptions:
mainsail
​
# this enables moonraker's update manager
[update_manager]
refresh_interval: 168
enable_auto_refresh: True
​
[update_manager mainsail]
type: web
channel: stable
repo: mainsail-crew/mainsail
path: ~/mainsail
This is a very basic config For more options and detailed explanations you should follow Moonraker’s instructions.
Trusted Clients - read carefully A list of newline separated IP addresses and/or IP ranges that are trusted. Trusted clients are given full access to the API. Both IPv4 and IPv6 addresses and ranges are supported. Ranges must be expressed in CIDR notation (see CIDR for more info). For example, an entry of 192.168.1.0/24 will authorize IP addresses in the range of 192.168.1.1 - 192.168.1.254. Note that when specifying IPv4 ranges the last segment of the IP address must be 0. The default is no clients or ranges are trusted.
Save the file with CTRL+O and close the editor with CTRL+X.

Startup service

To edit this file type:
sudo nano /etc/systemd/system/moonraker.service
fill in these lines:
#Systemd moonraker Service
​
[Unit]
Description=API Server for Klipper SV1
Requires=network-online.target
After=network-online.target
​
[Install]
WantedBy=multi-user.target
​
[Service]
Type=simple
User=pi
SupplementaryGroups=moonraker-admin
RemainAfterExit=yes
WorkingDirectory=/home/pi/moonraker
EnvironmentFile=/home/pi/printer_data/systemd/moonraker.env
ExecStart=/home/pi/moonraker-env/bin/python $MOONRAKER_ARGS
Restart=always
RestartSec=10
Save the file with CTRL+O and close the editor with CTRL+X.
Next step, you have to create an Klipper environment file in your printer_data:
nano ~/printer_data/systemd/moonraker.env
fill in these lines:
MOONRAKER_ARGS="/home/pi/moonraker/moonraker/moonraker.py -d /home/pi/printer_data"
Save the file with CTRL+O and close the editor with CTRL+X.
Please check and modify the username! If you do not use the user pi, you must replace it in each path and in the variable user in the service file.
To enable Moonraker service execute these commands:
sudo systemctl enable moonraker.service
Then we have also to add some Moonraker PolicyKit rules. Moonraker already provides a script for these:
./moonraker/scripts/set-policykit-rules.sh
After your config is in place, start Moonraker with sudo systemctl start moonraker.
Open the following URL with your printers IP in your browser
http://<printer-ip>:7125/server/info
If everything has been set up successfully, a message like this should appear:
{"result": {"klippy_connected": false, "klippy_state": "disconnected", "components": ["klippy_connection", "application", "websockets", "internal_transport", "dbus_manager", "database", "file_manager", "klippy_apis", "secrets", "template", "shell_command", "machine", "data_store", "proc_stats", "job_state", "job_queue", "http_client", "announcements", "webcam", "extensions", "authorization", "octoprint_compat", "history", "update_manager"], "failed_components": [], "registered_directories": ["config", "logs", "gcodes"], "warnings": [], "websocket_count": 0, "moonraker_version": "v0.7.1-747-g779997c", "missing_klippy_requirements": [], "api_version": [1, 0, 5], "api_version_string": "1.0.5"}}

Mainsail

Install web server & reverse proxy (NGINX)

NGINX is important to mount all components on port 80 and host the static files from Mainsail. To install NGINX you only need to execute:
sudo apt install nginx
now we create the config files with:
sudo touch /etc/nginx/sites-available/mainsail
sudo touch /etc/nginx/conf.d/upstreams.conf
sudo touch /etc/nginx/conf.d/common_vars.conf
Each file can be filled with the following content:
sudo nano /etc/nginx/conf.d/upstreams.conf
# /etc/nginx/conf.d/upstreams.conf
​
upstream apiserver {
ip_hash;
server 127.0.0.1:7125;
}
​
upstream mjpgstreamer1 {
ip_hash;
server 127.0.0.1:8080;
}
​
upstream mjpgstreamer2 {
ip_hash;
server 127.0.0.1:8081;
}
​
upstream mjpgstreamer3 {
ip_hash;
server 127.0.0.1:8082;
}
​
upstream mjpgstreamer4 {
ip_hash;
server 127.0.0.1:8083;
}
Save the file with CTRL+O and close the editor with CTRL+X.
sudo nano /etc/nginx/conf.d/common_vars.conf
# /etc/nginx/conf.d/common_vars.conf
​
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
Save the file with CTRL+O and close the editor with CTRL+X.
sudo nano /etc/nginx/sites-available/mainsail
# /etc/nginx/sites-available/mainsail
​
server {
listen 80 default_server;
# uncomment the next line to activate IPv6
# listen [::]:80 default_server;
​
access_log /var/log/nginx/mainsail-access.log;
error_log /var/log/nginx/mainsail-error.log;
​
# disable this section on smaller hardware like a pi zero
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_proxied expired no-cache no-store private auth;
gzip_comp_level 4;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/x-javascript application/json application/xml;
​
# web_path from mainsail static files
root /home/pi/mainsail;
​
index index.html;
server_name _;
​
# disable max upload size checks
client_max_body_size 0;
​
# disable proxy request buffering
proxy_request_buffering off;
​
location / {
try_files $uri $uri/ /index.html;
}
​
location = /index.html {
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
​
location /websocket {
proxy_pass http://apiserver/websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 86400;
}
​
location ~ ^/(printer|api|access|machine|server)/ {
proxy_pass http://apiserver$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
}
​
location /webcam/ {
postpone_output 0;
proxy_buffering off;
proxy_ignore_headers X-Accel-Buffering;
access_log off;
error_log off;
proxy_pass http://mjpgstreamer1/;
}
​
location /webcam2/ {
postpone_output 0;
proxy_buffering off;
proxy_ignore_headers X-Accel-Buffering;
access_log off;
error_log off;
proxy_pass http://mjpgstreamer2/;
}
​
location /webcam3/ {
postpone_output 0;
proxy_buffering off;
proxy_ignore_headers X-Accel-Buffering;
access_log off;
error_log off;
proxy_pass http://mjpgstreamer3/;
}
​
location /webcam4/ {
postpone_output 0;
proxy_buffering off;
proxy_ignore_headers X-Accel-Buffering;
access_log off;
error_log off;
proxy_pass http://mjpgstreamer4/;
}
}
Save the file with CTRL+O and close the editor with CTRL+X.
Create the directory for static files and active NGINX config:
mkdir ~/mainsail
sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/mainsail /etc/nginx/sites-enabled/
sudo systemctl restart nginx
Now you can recheck the API to see if it works with the reverse proxy. Open the URL http://<printer-ip>/server/info in your browser. If you see content like this:
{"result": {"klippy_connected": false, "klippy_state": "disconnected", "components": ["klippy_connection", "application", "websockets", "internal_transport", "dbus_manager", "database", "file_manager", "klippy_apis", "secrets", "template", "shell_command", "machine", "data_store", "proc_stats", "job_state", "job_queue", "http_client", "announcements", "webcam", "extensions", "authorization", "octoprint_compat", "history", "update_manager"], "failed_components": [], "registered_directories": ["config", "logs", "gcodes"], "warnings": [], "websocket_count": 0, "moonraker_version": "v0.7.1-747-g779997c", "missing_klippy_requirements": [], "api_version": [1, 0, 5], "api_version_string": "1.0.5"}}
Now we can install Mainsail.

Install httpdocs

Now you can download the current Mainsail static data.
cd ~/mainsail
wget -q -O mainsail.zip https://github.com/mainsail-crew/mainsail/releases/latest/download/mainsail.zip && unzip mainsail.zip && rm mainsail.zip
Now it should be possible to open the interface: http://<printer-ip>/.

Important macros

If you want the whole experience with Mainsail and Klipper virtual_sdcard print, you should use these macros or use them as templates for your own.
​Macro Link​

Use hostname instead of IP to open Mainsail (optional)

To use the hostname instate of the IP, you can install the avahi-daemon:
sudo apt install avahi-daemon
And you can config your hostname:
sudo raspi-config
In 2 Network Options > N1 Hostname, you can edit the hostname of your Raspberry Pi. After a reboot, you can use http://<hostname>.local/ to open the web interface.