Created
September 7, 2026 23:20
-
-
Save tapickell/df131f22c4a0bf834da1205abce24de4 to your computer and use it in GitHub Desktop.
printer_setup_x220.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # Ender 3 / Klipper host bootstrap | |
| # Target: Debian 13 x86_64 | |
| # | |
| # Installs: | |
| # - Klipper | |
| # - Moonraker | |
| # - Mainsail | |
| # - Crowsnest | |
| # - nginx | |
| # - required Python/system packages | |
| # | |
| # Does NOT install printer.cfg or flash the SKR. | |
| # We will migrate those from the existing Pi afterward. | |
| # | |
| set -Eeuo pipefail | |
| KLIPPER_REPO="https://github.com/Klipper3d/klipper.git" | |
| MOONRAKER_REPO="https://github.com/Arksine/moonraker.git" | |
| CROWSNEST_REPO="https://github.com/mainsail-crew/crowsnest.git" | |
| MAINSAIL_URL="https://github.com/mainsail-crew/mainsail/releases/latest/download/mainsail.zip" | |
| PRINTER_DATA="$HOME/printer_data" | |
| log() { | |
| printf '\n\033[1;32m==> %s\033[0m\n' "$*" | |
| } | |
| die() { | |
| printf '\n\033[1;31mERROR: %s\033[0m\n' "$*" >&2 | |
| exit 1 | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Sanity checks | |
| # --------------------------------------------------------------------------- | |
| if [[ $EUID -eq 0 ]]; then | |
| die "Run this as your normal user, NOT as root. The script will use sudo." | |
| fi | |
| command -v sudo >/dev/null 2>&1 || | |
| die "sudo is not installed." | |
| case "$(uname -m)" in | |
| x86_64) | |
| ;; | |
| *) | |
| die "Expected x86_64 Debian host; found $(uname -m)" | |
| ;; | |
| esac | |
| # --------------------------------------------------------------------------- | |
| # Base OS packages | |
| # --------------------------------------------------------------------------- | |
| log "Updating Debian packages" | |
| sudo apt update | |
| sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y | |
| log "Installing dependencies" | |
| sudo apt install -y \ | |
| git \ | |
| curl \ | |
| wget \ | |
| unzip \ | |
| nginx \ | |
| python3 \ | |
| python3-dev \ | |
| python3-venv \ | |
| python3-pip \ | |
| python3-setuptools \ | |
| python3-wheel \ | |
| build-essential \ | |
| libffi-dev \ | |
| libncurses-dev \ | |
| libusb-dev \ | |
| libusb-1.0-0-dev \ | |
| pkg-config \ | |
| avrdude \ | |
| gcc-avr \ | |
| binutils-avr \ | |
| avr-libc \ | |
| stm32flash \ | |
| dfu-util \ | |
| virtualenv \ | |
| policykit-1 \ | |
| zlib1g-dev \ | |
| libjpeg-dev | |
| # --------------------------------------------------------------------------- | |
| # User permissions | |
| # --------------------------------------------------------------------------- | |
| log "Adding $USER to serial-device groups" | |
| sudo usermod -aG dialout "$USER" | |
| # --------------------------------------------------------------------------- | |
| # Printer data layout | |
| # --------------------------------------------------------------------------- | |
| log "Creating printer_data directories" | |
| mkdir -p \ | |
| "$PRINTER_DATA/config" \ | |
| "$PRINTER_DATA/gcodes" \ | |
| "$PRINTER_DATA/logs" \ | |
| "$PRINTER_DATA/comms" \ | |
| "$PRINTER_DATA/systemd" | |
| # --------------------------------------------------------------------------- | |
| # Klipper | |
| # --------------------------------------------------------------------------- | |
| log "Installing Klipper" | |
| if [[ ! -d "$HOME/klipper/.git" ]]; then | |
| git clone "$KLIPPER_REPO" "$HOME/klipper" | |
| else | |
| log "Klipper repository already exists -- updating" | |
| git -C "$HOME/klipper" pull --ff-only | |
| fi | |
| python3 -m venv "$HOME/klippy-env" | |
| "$HOME/klippy-env/bin/pip" install --upgrade pip wheel | |
| "$HOME/klippy-env/bin/pip" install \ | |
| -r "$HOME/klipper/scripts/klippy-requirements.txt" | |
| # --------------------------------------------------------------------------- | |
| # Moonraker | |
| # --------------------------------------------------------------------------- | |
| log "Installing Moonraker" | |
| if [[ ! -d "$HOME/moonraker/.git" ]]; then | |
| git clone "$MOONRAKER_REPO" "$HOME/moonraker" | |
| else | |
| log "Moonraker repository already exists -- updating" | |
| git -C "$HOME/moonraker" pull --ff-only | |
| fi | |
| python3 -m venv "$HOME/moonraker-env" | |
| "$HOME/moonraker-env/bin/pip" install --upgrade pip wheel | |
| "$HOME/moonraker-env/bin/pip" install \ | |
| -r "$HOME/moonraker/scripts/moonraker-requirements.txt" | |
| # --------------------------------------------------------------------------- | |
| # Klipper systemd service | |
| # --------------------------------------------------------------------------- | |
| log "Creating Klipper systemd service" | |
| sudo tee /etc/systemd/system/klipper.service >/dev/null <<EOF | |
| [Unit] | |
| Description=Klipper 3D Printer Firmware | |
| Documentation=https://www.klipper3d.org/ | |
| After=network-online.target | |
| Wants=network-online.target | |
| [Service] | |
| Type=simple | |
| User=$USER | |
| WorkingDirectory=$HOME/klipper | |
| ExecStart=$HOME/klippy-env/bin/python \ | |
| $HOME/klipper/klippy/klippy.py \ | |
| $PRINTER_DATA/config/printer.cfg \ | |
| -l $PRINTER_DATA/logs/klippy.log \ | |
| -I $PRINTER_DATA/comms/klippy.serial \ | |
| -a $PRINTER_DATA/comms/klippy.sock | |
| Restart=always | |
| RestartSec=10 | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| # --------------------------------------------------------------------------- | |
| # Moonraker systemd service | |
| # --------------------------------------------------------------------------- | |
| log "Creating Moonraker systemd service" | |
| sudo tee /etc/systemd/system/moonraker.service >/dev/null <<EOF | |
| [Unit] | |
| Description=Moonraker API Server | |
| After=network-online.target klipper.service | |
| Wants=network-online.target | |
| [Service] | |
| Type=simple | |
| User=$USER | |
| WorkingDirectory=$HOME/moonraker | |
| ExecStart=$HOME/moonraker-env/bin/python -m moonraker \ | |
| -d $PRINTER_DATA | |
| Restart=always | |
| RestartSec=10 | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| # --------------------------------------------------------------------------- | |
| # Mainsail | |
| # --------------------------------------------------------------------------- | |
| log "Installing Mainsail" | |
| sudo mkdir -p /var/www/mainsail | |
| TMP_MAINSAIL="$(mktemp -d)" | |
| curl -L "$MAINSAIL_URL" \ | |
| -o "$TMP_MAINSAIL/mainsail.zip" | |
| sudo rm -rf /var/www/mainsail/* | |
| sudo unzip -q "$TMP_MAINSAIL/mainsail.zip" \ | |
| -d /var/www/mainsail | |
| rm -rf "$TMP_MAINSAIL" | |
| sudo chown -R www-data:www-data /var/www/mainsail | |
| # --------------------------------------------------------------------------- | |
| # nginx | |
| # --------------------------------------------------------------------------- | |
| log "Configuring nginx" | |
| sudo tee /etc/nginx/sites-available/mainsail >/dev/null <<'EOF' | |
| server { | |
| listen 80 default_server; | |
| listen [::]:80 default_server; | |
| root /var/www/mainsail; | |
| index index.html; | |
| client_max_body_size 1G; | |
| location / { | |
| try_files $uri $uri/ /index.html; | |
| } | |
| location /websocket { | |
| proxy_pass http://127.0.0.1:7125/websocket; | |
| proxy_http_version 1.1; | |
| proxy_set_header Upgrade $http_upgrade; | |
| proxy_set_header Connection "Upgrade"; | |
| proxy_set_header Host $host; | |
| } | |
| location ~ ^/(printer|api|access|machine|server)/ { | |
| proxy_pass http://127.0.0.1:7125; | |
| proxy_set_header Host $host; | |
| proxy_set_header X-Real-IP $remote_addr; | |
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
| } | |
| } | |
| EOF | |
| sudo rm -f /etc/nginx/sites-enabled/default | |
| sudo ln -sf \ | |
| /etc/nginx/sites-available/mainsail \ | |
| /etc/nginx/sites-enabled/mainsail | |
| sudo nginx -t | |
| sudo systemctl restart nginx | |
| # --------------------------------------------------------------------------- | |
| # Crowsnest | |
| # --------------------------------------------------------------------------- | |
| log "Installing Crowsnest" | |
| if [[ ! -d "$HOME/crowsnest/.git" ]]; then | |
| git clone "$CROWSNEST_REPO" "$HOME/crowsnest" | |
| else | |
| log "Crowsnest repository already exists -- updating" | |
| git -C "$HOME/crowsnest" pull --ff-only | |
| fi | |
| # | |
| # Crowsnest's own installer handles its multimedia dependencies and service. | |
| # | |
| if [[ -x "$HOME/crowsnest/tools/pkglist.sh" ]]; then | |
| sudo "$HOME/crowsnest/tools/pkglist.sh" || true | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Initial Moonraker config | |
| # --------------------------------------------------------------------------- | |
| if [[ ! -f "$PRINTER_DATA/config/moonraker.conf" ]]; then | |
| log "Creating initial Moonraker configuration" | |
| cat > "$PRINTER_DATA/config/moonraker.conf" <<EOF | |
| [server] | |
| host: 0.0.0.0 | |
| port: 7125 | |
| klippy_uds_address: $PRINTER_DATA/comms/klippy.sock | |
| [file_manager] | |
| enable_object_processing: True | |
| [authorization] | |
| trusted_clients: | |
| 127.0.0.0/8 | |
| 192.168.0.0/16 | |
| 10.0.0.0/8 | |
| 172.16.0.0/12 | |
| cors_domains: | |
| http://*.local | |
| http://* | |
| https://* | |
| [history] | |
| [octoprint_compat] | |
| [update_manager] | |
| enable_auto_refresh: True | |
| [update_manager mainsail] | |
| type: web | |
| channel: stable | |
| repo: mainsail-crew/mainsail | |
| path: /var/www/mainsail | |
| EOF | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Enable services | |
| # --------------------------------------------------------------------------- | |
| log "Enabling services" | |
| sudo systemctl daemon-reload | |
| # | |
| # Klipper will probably fail until we copy printer.cfg over. | |
| # That's expected. | |
| # | |
| sudo systemctl enable klipper | |
| sudo systemctl enable moonraker | |
| sudo systemctl enable nginx | |
| sudo systemctl restart moonraker || true | |
| # --------------------------------------------------------------------------- | |
| # Disable sleep/suspend/hibernate | |
| # --------------------------------------------------------------------------- | |
| log "Disabling automatic sleep/hibernate" | |
| sudo systemctl mask \ | |
| sleep.target \ | |
| suspend.target \ | |
| hibernate.target \ | |
| hybrid-sleep.target | |
| # --------------------------------------------------------------------------- | |
| # Finish | |
| # --------------------------------------------------------------------------- | |
| IP_ADDR="$(hostname -I | awk '{print $1}')" | |
| printf '\n' | |
| printf '============================================================\n' | |
| printf ' Klipper host bootstrap complete\n' | |
| printf '============================================================\n' | |
| printf '\n' | |
| printf 'Host: %s\n' "$(hostname)" | |
| printf 'IP: %s\n' "${IP_ADDR:-unknown}" | |
| printf 'Mainsail: http://%s/\n' "${IP_ADDR:-HOST-IP}" | |
| printf 'Printer data: %s\n' "$PRINTER_DATA" | |
| printf '\n' | |
| printf 'IMPORTANT:\n' | |
| printf ' 1. Log out/reboot so dialout group membership takes effect.\n' | |
| printf ' 2. We still need to migrate printer.cfg and Moonraker config.\n' | |
| printf ' 3. Do NOT reflash the SKR Mini E3 V3 yet.\n' | |
| printf ' 4. The existing Klipper MCU firmware should remain usable.\n' | |
| printf '\n' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment