Save a file β It appears on your printer. That's it.
β οΈ Platform Support:
- β Ubuntu 24.04 LTS: Fully tested by maintainer
- π Other Linux distros: Should work, testers needed (report here)
- π Windows (WSL2): Documented but untested, testers needed
- π macOS: Documented but untested, testers needed
Example configs exist for multiple platforms (see examples/), but only Ubuntu 24.04 has been validated. Help us expand support by testing and reporting results!
Automatically sync .gcode files wirelessly to your 3D printer through a Raspberry Pi configured as a USB mass storage device. No SD card swapping, no manual transfers, no printer reboots.
Before: Save file β Unmount SD card β Walk to printer β Insert SD card β Wait for menu refresh β Navigate to file β Print
After: Save file β Print (file appears in 10 seconds)
Tired of the "SD card shuffle"? This project eliminates the most tedious part of 3D printing: getting gcode files onto your printer. Set it up once, forget about it forever.
- π Automatic File Monitoring - Watches your desktop for new gcode files
- β‘ Fast Transfers - 21x speed improvement over basic setups (optimized networking)
- π USB Gadget Mode - Raspberry Pi acts as a USB mass storage device
- π Auto-Refresh - Printer sees new files instantly without rebooting Pi
- π Optimized Performance - Network tuning achieves 5-10 MB/s for real files
- π¦ Complete Solution - Includes both local monitor and Pi server scripts
- π οΈ Easy Setup - Automated installation scripts included
- Raspberry Pi Zero W or Pi Zero 2W (recommended for better performance)
- Other Pi models work but require USB OTG adapter
- Micro-USB cable (data-capable, not just power)
- SD card (8GB minimum, 16GB+ recommended)
- 3D Printer with USB mass storage support
- WiFi network (2.4GHz minimum, 5GHz if Pi supports it)
- Operating System: Ubuntu 20.04+ or any modern Linux distro
- Required Packages:
inotify-tools(for Bash monitor) ORpython3+watchdog(for Python monitor)rsync- Efficient file transferopenssh-client- SSH connectivitysystemd- Service management (usually pre-installed)
- Network: SSH access to Raspberry Pi (passwordless key auth recommended)
- Operating System: Raspberry Pi OS (Lite or Desktop)
- Kernel: 4.9+ with USB gadget support
- Required:
- USB gadget kernel modules (
dwc2,libcompositeorg_mass_storage) - 2GB+ FAT32 image file for USB storage
- SSH server enabled
- NetworkManager (for WiFi power management optimization)
- USB gadget kernel modules (
- Network: WiFi configured and connected to same network as local machine
- Both devices on same network/subnet
- SSH connectivity between local machine and Pi
- CRITICAL: WiFi power management must be disabled (provides 20x speed boost!)
The project runs natively on Linux today. Windows and macOS users can follow the platform-specific guides below to get equivalent functionality.
git clone https://github.com/mlugo-apx/pi-gcode-server.git
cd pi-gcode-server
cp config.example config.local
nano config.local # Configure WATCH_DIR, REMOTE_* values
./install_and_start.sh # Installs dependencies, runs a sync test
./deploy.sh # Installs/refreshes the systemd service
# Smoke test
cp path/to/file.gcode ~/Desktop/
tail -f ~/.gcode_sync.logβΉοΈ See Pi Setup Guide for configuring the Raspberry Pi USB gadget environment. NEW: Automated Pi Setup eliminates manual configuration steps! The Linux desktop component is already hardened with systemd sandboxing and security validation.
π‘ Install uv for faster, reproducible Python dependency management (
curl -Ls https://astral.sh/uv/install.sh | sh). The installer will auto-detect and useuvwhen available.
- Enable WSL2 and install Ubuntu (
wsl --installon Windows 11). - Inside Ubuntu:
git clone https://github.com/mlugo-apx/pi-gcode-server.git cd pi-gcode-server cp config.example config.local ./install_and_start.sh ./deploy.sh - Configure Windows to launch the monitor at login (e.g., PowerShell script
calling
wsl -d Ubuntu ./deploy.sh).
π Detailed instructions and bootstrap ideas live in Cross-Platform Support. The Raspberry Pi still performs the USB gadget duties; WSL only runs the desktop monitor.
- Install prerequisites via Homebrew:
brew install python rsync openssh
- Clone and configure the project:
git clone https://github.com/mlugo-apx/pi-gcode-server.git cd pi-gcode-server cp config.example config.local ./install_and_start.sh - Create a
launchdplist (example template forthcoming indocs/CROSS_PLATFORM_SUPPORT.md) that runsmonitor_and_sync.pyat login. - Tail
~/.gcode_sync.logto confirm end-to-end syncs.
π macOS uses FSEvents under the hood via
watchdog, so the Python monitor works natively. Replace systemd sandboxing with the appropriatelaunchdoptions (as documented in the cross-platform guide).π‘
uvis also supported on macOS. Install it via Homebrew (brew install uv) or the official installer; the setup script will pick it up automatically.
Regardless of platform, the Raspberry Pi setup remains the same. After the Pi is prepared, confirm the desktop monitor reaches the Pi:
cp test.gcode ~/Desktop/
tail -f ~/.gcode_sync.log
ssh your_user@your_pi_ip "ls -lh /mnt/usb_share/"- Quick Start Guide - Get up and running fast
- Detailed Pi Setup - Complete Raspberry Pi configuration
- Network Optimization - Achieve 21x speed improvements!
- Troubleshooting - Common issues and solutions
- Architecture - How the system works
Before Optimization:
- Transfer speed: ~260 KB/s
- 55MB file: ~3 minutes 30 seconds
After Optimization:
- Transfer speed: ~5.5 MB/s
- 55MB file: ~10 seconds β‘
- 21x faster!
See Network Optimization Results for details on how we achieved this.
Works with any 3D printer that supports USB mass storage mode, which includes most modern printers.
| Printer Model | Status | Notes | Tested By |
|---|---|---|---|
| AnyCubic Kobra 2 Max | β Verified | USB mass storage fully supported, files appear immediately | @mlugo-apx |
These printers support USB mass storage and should work, but haven't been tested by the maintainer yet:
Creality Series:
- Ender 3 / Ender 3 V2 / Ender 3 Pro
- CR-10 / CR-10 V2
- CR-6 SE, CR-30, Ender 5 series
Prusa Series:
- i3 MK3S / MK3S+ / MK4
- Mini, XL (with USB port)
AnyCubic Series:
- Kobra (standard)
- Vyper
- Mega series
Other Brands:
- Artillery: Sidewinder, Genius
- Elegoo: Neptune series
- Sovol: SV01, SV02, SV06
- Any printer with USB mass storage support
π Have you tested this? Report your printer compatibility β
Your printer must have:
- β USB-A port (usually on front panel or side)
- β USB mass storage support (can read files from USB flash drive)
- β FAT32 filesystem support (standard for USB drives)
- β Menu system to browse and select files
Your printer does not need:
- β Network connectivity (WiFi/Ethernet)
- β Special firmware modifications
- β OctoPrint or other server software
- β Touchscreen (basic LCD is fine)
If your printer can read files from a USB flash drive, this project will work:
- Creality: CR-6, CR-30, Ender 5, Ender 5 Pro, Ender 7
- Prusa: Mini, XL (with USB port)
- AnyCubic: Mega series, Photon Mono (FDM models)
- Artillery: Sidewinder, Genius
- Elegoo: Neptune series
- Sovol: SV01, SV02, SV06
- Monoprice: Select Mini, Maker series
- FlashForge: Adventurer, Creator series
- QIDI: X-Plus, X-Max
- Any printer with USB mass storage support
- Network-only printers without USB ports
- Proprietary USB protocols (rare, mostly industrial printers)
- Resin printers without USB mass storage (some only support network)
Help expand this list! If you've tested this with your printer:
- Open an issue with your printer model
- Include: Model name, firmware version (if known), and whether it worked
- We'll add it to the compatibility matrix above
Example config files available in examples/ directory:
config.ender3- Creality Ender 3 seriesconfig.prusa- Prusa MK3S/MK3S+/MK4config.wsl2- Windows + WSL2 setupconfig.macos- macOS setup
See examples/README.md for usage instructions.
Raspberry Pi Requirements:
- Raspberry Pi Zero W/2W (recommended for space/cost)
- Raspberry Pi 3/4 (works but overkill for this task)
- Must support USB OTG (USB gadget mode)
- See docs/PI_SETUP.md for configuration
This uses direct USB connection through the Raspberry Pi, so your printer doesn't need network capabilities. The Pi acts as a "smart USB drive" that auto-updates.
Yes! The watch directory is fully configurable via WATCH_DIR in config.local. Monitor any folder you want.
Unfortunately, this solution requires USB mass storage support. If your printer only has an SD card slot, you'll need to stick with SD cards.
Yes, but you'll need a USB OTG adapter since they don't have built-in USB gadget support via micro-USB. Pi Zero W/2W are recommended for simplicity.
Yes. The project includes 8 layers of security:
- Input validation (path traversal prevention, symlink rejection)
- TOCTOU mitigation (race condition prevention)
- Command injection prevention
- Network restrictions (local subnet only via systemd)
- Filesystem protection (read-only system directories)
- System call filtering
- Resource limits (memory, CPU, process count)
- Capability dropping (zero Linux capabilities)
See the Security Architecture section for details.
- Raspberry Pi Zero W: ~$10-15
- Micro-USB cable (if you don't have one): ~$3-5
- Total: Under $20
Yes, though the USB gadget mode will occupy the USB port. Other services (web servers, monitoring, etc.) can run simultaneously.
Yes, the file monitor runs on your computer and syncs files when they're created. The Pi stays on 24/7 connected to your printer.
- File Monitor watches your configured directory for
.gcodefiles usinginotifywaitor Python'swatchdog - rsync efficiently transfers new files to the Raspberry Pi over SSH
- USB Gadget Refresh Script on the Pi unbinds/rebinds the USB gadget, forcing the printer to re-enumerate
- 3D Printer sees the new files immediately without any reboot!
Local Dir β inotify/watchdog β rsync β Raspberry Pi β USB gadget β 3D Printer
(monitors) (transfers) (serves) (refreshes) (prints!)
pi-gcode-server/
βββ monitor_and_sync.sh # Bash file monitor (simple)
βββ monitor_and_sync.py # Python file monitor (recommended, security-hardened)
βββ gcode-monitor.service # Systemd service file (sandboxed)
βββ config.example # Configuration template
βββ requirements.txt # Python dependencies with SHA256 hashes
βββ .editorconfig # Code style configuration
βββ install_and_start.sh # Automated installation script
βββ run_tests.sh # Test suite runner
βββ lib/ # Shared libraries
β βββ error_handler.sh # Centralized error handling for shell scripts
βββ tests/ # Test suite
β βββ unit/ # Unit tests
β β βββ test_validation.py # Validation logic tests
β βββ security/ # Security tests
β β βββ test_security.py # OWASP Top 10 vulnerability tests
β βββ integration/ # Integration tests
β βββ test_integration.py # End-to-end workflow tests
βββ pi_scripts/ # Raspberry Pi server scripts
β βββ diagnose_usb_gadget.sh # Diagnostic tool
β βββ refresh_usb_gadget.sh # Universal USB refresh (auto-detects)
β βββ refresh_usb_gadget_configfs.sh
β βββ refresh_usb_gadget_module.sh
βββ docs/ # Documentation
βββ QUICKSTART.md
βββ PI_SETUP.md
βββ NETWORK_OPTIMIZATION_RESULTS.md
βββ TROUBLESHOOTING.md
βββ ARCHITECTURE.md
This project implements defense-in-depth security with multiple layers of protection against common attacks.
- Path Traversal Prevention: All file paths validated using Python
Path().resolve().relative_to()to prevent../escapes - Symlink Attack Prevention: Files validated as regular files, symlinks rejected before processing
- Extension Validation: Only
.gcodefiles processed (case-sensitive) - File Size Limits:
- Minimum 1 byte (prevents empty file DoS)
- Maximum 1 GB (prevents disk exhaustion DoS)
- Warning threshold at 500 MB for large files
- Shell Variable Quoting: All shell variables properly quoted in
monitor_and_sync.shandtest_sync.sh - No User-Controlled Commands: File paths never used in shell execution contexts
- Error Handler Library: Centralized error handling (
lib/error_handler.sh) with strict mode (set -euo pipefail)
- Re-validation Before Use: Files re-validated immediately before rsync execution
- Minimal TOCTOU Window: <20 lines of code between validation and use
- Three-Layer Validation:
- Initial validation (extension, size, type)
- Re-validation (symlink, file type, extension)
- Execution (rsync with timeout)
- Systemd Sandboxing:
RestrictAddressFamilies=AF_INET AF_INET6(network-only)IPAddressAllow=192.168.1.0/24(local subnet only)IPAddressDeny=any(deny by default)
- SSH Key Authentication: Passwordless authentication required
- Encrypted Transport: All data transfer over SSH
- Timeout Protection: Network operations have configured timeouts
- Systemd Restrictions:
ProtectSystem=strict(immutable system directories)ProtectHome=tmpfs(isolated home directory)BindReadOnlyPaths(read-only bind mounts)NoNewPrivileges=true(prevents privilege escalation)
- Path Bounds Checking: Files must be within configured watch directory
- Forbidden Paths:
/etc,/var,/usr,/bin,/sbin,/bootblocked
- Systemd Syscall Filtering:
SystemCallFilter=@system-service(allowlist approach)SystemCallFilter=~@privileged @resources @obsolete(deny dangerous calls)SystemCallArchitectures=native(no foreign architectures)
- Retry Logic: Exponential backoff for transient failures (2s, 4s, 8s delays)
- Dynamic Timeouts: Timeout scales with file size (baseline 2min + 1min per 100MB)
- Resource Limits:
MemoryMax=500M(memory limit)CPUQuota=50%(CPU throttling)TasksMax=20(process limit)
- Dependency Hashing:
requirements.txtincludes SHA256 hashes - Version Pinning: All dependencies pinned to specific versions
- Minimal Dependencies: Only
watchdog==3.0.0for file monitoring
| Attack Vector | Mitigation | Layer |
|---|---|---|
| Command Injection | Quoted variables, no shell execution | Input Validation |
| Path Traversal | Bounds checking, relative_to() validation | Input Validation |
| Symlink Attacks | islink() checks, realpath validation | Input Validation |
| TOCTOU Races | Re-validation before use | Process |
| File Size DoS | MIN/MAX size limits, dynamic timeouts | Resource Limits |
| Network Attacks | Systemd IP restrictions, SSH encryption | Network |
| Privilege Escalation | NoNewPrivileges, capability dropping | Systemd |
| Syscall Exploits | SystemCallFilter allowlist | Systemd |
Comprehensive test suite validates security controls:
- Unit Tests (
tests/unit/): Validation logic, retry behavior - Security Tests (
tests/security/): OWASP Top 10, injection, traversal - Integration Tests (
tests/integration/): End-to-end workflows
Run tests with:
./run_tests.sh- SSH Keys: Store private keys with permissions
0600, never commit to version control - config.local: Git-ignored to prevent credential exposure
- Log Files: Do not log sensitive data (credentials, file contents)
- Network Isolation: Run on trusted local network only (not internet-facing)
- Principle of Least Privilege: Service runs as non-root user with minimal capabilities
Please report security vulnerabilities privately via GitHub Security Advisories or email maintainers directly. Do not open public issues for security bugs.
Contributions are welcome! Here's how you can help:
- Printer Compatibility Reports: Test with your printer and report results
- Documentation: Improve setup guides, add troubleshooting tips
- Bug Reports: Found an issue? Open an issue
- Feature Requests: Have an idea? Share it in Discussions
- Code Improvements: Security enhancements, performance optimizations, bug fixes
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes and add tests if applicable
- Run the test suite:
./run_tests.sh - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request with a clear description
- Python: Follow PEP 8, use type hints
- Bash: Use shellcheck, follow Google Shell Style Guide
- Security: All inputs must be validated, no shell injection vulnerabilities
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by the need to eliminate manual file transfers to 3D printers
- Built with Raspberry Pi USB gadget mode (ConfigFS)
- Optimized through systematic network performance analysis
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Use the bundled health check to verify the service and logs are fresh:
./check_gcode_monitor.shFor periodic checks, add a cron entry (every 15 minutes shown):
*/15 * * * * /home/your_username/pi-gcode-server/check_gcode_monitor.sh >> /home/your_username/pi-gcode-server/logs/health_check.log 2>&1The script validates:
gcode-monitor.serviceis active~/.gcode_sync.loghas been updated within the last 30 minutes- The systemd journal has no recent errors for the service
Happy Printing! π¨οΈβ¨