I bricked and had to rebuild my 3D printer controller (a raspberry pi clone) and figured I would document the entire journey.
This is starting from a minimal install of Armbian (Debian based OS on a Raspberry Pi clone) that gives us a good foundation point to begin from (see my earlier post 2026-01-06 Armbian Trixie on how I got that ready).
Let’s start by setting some goals
- We want Klipper to run automatically
- We want it be isolated as much as possible
- We want minimal dependency
- Use Mainsail as Web-UI (requires Moonraker API layer)
We will use the Manual instructions from Mainsail to guide us, with a few small modifications to suit our environment
Setup a User account for services
We will run everything in its own account and we’ll create a suitable home folder for it all
1
| sudo useradd -G tty,dialout -m -d /opt/klipper klipper
|
We need tty and dialout if we want serial access
We will also need a few utilities that may not be installed in a minimal configuration
1
| sudo apt-get install zip unzip gzip
|
Install dependencies
1
| sudo apt-get install virtualenv python3-dev python3-venv git build-essential libffi-dev libncurses-dev libusb-dev avrdude gcc-avr binutils-avr avr-libc stm32flash libnewlib-arm-none-eabi gcc-arm-none-eabi binutils-arm-none-eabi libusb-1.0
|
Klipper
Now we have our base sytem ready, we can switch to the Klipper user and download sources and make the configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| sudo su klipper -
cd ~
# Configure directories for Mainsail
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
#Configure venv
python3 -m venv klippy-venv
source klippy-venv/bin/activate
pip install pip --upgrade
deactivate
exit
|
Install Klipper
Now we can install Klipper
1
2
3
4
5
6
7
| sudo su klipper -
cd ~
git clone https://github.com/KevinOConnor/klipper
source klippy-venv/bin/activate
pip install -r klipper/scripts/klippy-requirements.txt
deactivate
exit
|
We will need the environment to be defined for our systemd service
1
| vi ~/printer_data/systemd/klipper.env
|
1
2
| #/opt/klipper/printer_data/systemd/klipper.env
KLIPPER_ARGS="$/opt/klipper/klipper/klippy/klippy.py /opt/klipper/printer_data/config/printer.cfg -l /opt/klipper/printer_data/logs/klippy.log -I /opt/klipper/printer_data/comms/klippy.serial -a /opt/klipper/printer_data/comms/klippy.sock"
|
1
| sudo vi /etc/systemd/system/klipper.service
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| #/etc/systemd/system/klipper.service
#Systemd service file for klipper
[Unit]
Description=Starts klipper on startup
Documentation=https://www.klipper3d.org/
After=network-online.target
Wants=udev.target
[Install]
WantedBy=multi-user.target
[Service]
Type=simple
User=klipper
RemainAfterExit=yes
EnvironmentFile=/opt/klipper/printer_data/systemd/klipper.env
WorkingDirectory=/opt/klipper/klipper
ExecStart=$KLIPPER_HOME/klippy-venv/bin/python $KLIPPER_ARGS
Restart=always
RestartSec=10
|
1
2
3
| sudo systemctl daemon-reload
sudo systemctl enable klipper.service
sudo systemctl restart klipper
|
Moonraker
Install Moonraker
1
2
3
4
5
6
7
| sudo su klipper -
cd ~
git clone https://github.com/Arksine/moonraker.git
python3 -m venv ./moonraker-env
source moonraker-env/bin/activate
pip install -r ./moonraker/scripts/moonraker-requirements.txt
deactivate
|
Setup moonraker config
1
| vi ~/printer_data/config/moonraker.conf
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| #/opt/klipper/printer_data/config/moonraker.conf
[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:
*://*.local.lan
trusted_clients:
127.0.0.0/8
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
|
1
2
3
| sudo su klipper -
cd ~
vi ~/printer_data/systemd/moonraker.env
|
1
2
| #/opt/klipper/printer_data/systemd/moonraker.env
MOONRAKER_ARGS="/opt/klipper/moonraker/moonraker/moonraker.py -d /home/pi/printer_data"
|
1
| sudo vi /etc/systemd/system/moonraker.service
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| #/etc/systemd/system/moonraker.service
#Systemd moonraker Service
[Unit]
Description=API Server for Klipper
Requires=network-online.target
After=network-online.target
[Install]
WantedBy=multi-user.target
[Service]
Type=simple
User=klipper
SupplementaryGroups=moonraker-admin
RemainAfterExit=yes
WorkingDirectory=/opt/klipper/moonraker
EnvironmentFile=/opt/klipper/printer_data/systemd/moonraker.env
ExecStart=/opt/klipper/moonraker-venv/bin/python $MOONRAKER_ARGS
Restart=always
RestartSec=10
|
1
2
| sudo systemctl enable moonraker
sudo systemctl start moonraker
|
Mainsail
Start by setting up NGINX
Install Nginx
1
2
3
4
| sudo apt-get install nginx
sudo touch /etc/nginx/sites-available/mainsail
sudo touch /etc/nginx/conf.d/upstreams.conf
sudo touch /etc/nginx/conf.d/common_vars.conf
|
1
| sudo vi /etc/nginx/conf.d/upstreams.conf
|
1
2
3
4
5
6
7
8
9
10
11
12
| # /etc/nginx/conf.d/upstreams.conf
upstream apiserver {
ip_hash;
server 127.0.0.1:7125;
}
## Example mjpegstreamer upstreams:
#upstream mjpgstreamer1 {
# ip_hash;
# server 127.0.0.1:8080;
#}
|
1
| sudo vi /etc/nginx/conf.d/common_vars.conf
|
1
2
3
4
5
| #/etc/nginx/conf.d/common_vars.conf
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
|
Configure Mainsail site-available
1
| sudo vi /etc/nginx/sites-available/mainsail
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| # /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 /opt/klipper/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;
}
## Upstream Webcam
#location /webcam/ {
# postpone_output 0;
# proxy_buffering off;
# proxy_ignore_headers X-Accel-Buffering;
# access_log off;
# error_log off;
# proxy_pass http://mjpgstreamer1/;
#}
}
|
Setup the Mainsail folder in the Klipper directory
1
2
3
4
5
6
| sudo su klipper -
mkdir ~/mainsail
cd ~/mainsail
wget -q -O mainsail.zip https://github.com/mainsail-crew/mainsail/releases/latest/download/mainsail.zip && unzip mainsail.zip && rm mainsail.zip
exit
sudo chown -R klipper:www-data /opt/klipper/mainsail
|
Enable the Mainsail site
1
2
3
| sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/mainsail /etc/nginx/sites-enabled
sudo systemctl restart nginx
|
With that, we should now be able to access our Mainsail webserver - test by accessing http://<sbc-ip> in your web browser