Deploying CNCjs
CNCjs is a full-featured web-based interface for CNC controllers running Grbl, Marlin, Smoothieware, or TinyG firmware. Built with Node.js and JavaScript, CNCjs provides a responsive web interface for controlling CNC milling machines, allowing you to operate your CNC equipment from any device with a web browser. Whether you’re running a small hobby CNC, a production milling machine, or a Raspberry Pi-based system, CNCjs delivers comprehensive control capabilities with intuitive user experience.
The platform supports multiple CNC controller types including Grbl, Grbl-Mega, Marlin, Smoothieware, TinyG, and g2core, making it compatible with a wide range of CNC machines and hobby projects. CNCjs runs on Linux, macOS, Windows, and Raspberry Pi devices, connecting to your CNC controller via USB serial port, Bluetooth serial module, or wireless connections. With features like 3D visualization, tool path preview, real-time position monitoring, custom widgets, and pendant support, CNCjs provides professional-grade CNC control software.
Key Features
- Multi-Controller Support: Compatible with Grbl, Grbl-Mega, Marlin, Smoothieware, TinyG, and g2core firmware
- 3D Tool Path Visualization: Preview G-code tool paths before execution with 3D visualization
- Responsive Web Interface: Works on desktop browsers, tablets, and mobile devices
- 6-Axis Digital Readout (DRO): Real-time position display and monitoring
- Multiple Simultaneous Connections: Allow multiple clients to connect to the same serial port
- Customizable Workspace: Personalize the interface with custom layouts and widgets
- Custom Widgets: Extend functionality with custom widget development
- G-Code Editor: Built-in editor for G-code files with syntax highlighting
- File Upload: Upload and manage G-code files directly from the interface
- Tool Change Support: Automated or manual tool change workflows
- Z-Probe: Automatic workpiece height detection and zeroing
- Keyboard Shortcuts: Comprehensive keyboard shortcuts for rapid operation
- Contour ShuttleXpress: Hardware pendant support for Contour design devices
- Commands: Programmable commands for custom macros and operations
- Events: Trigger custom actions based on CNC events
- Multi-Language Support: Interface available in multiple languages (Chinese, Czech, Dutch, English, French, German, Hungarian, Italian, Japanese, Portuguese, Russian, and more)
- Watch Directory: Automatically load G-code files from monitored directories
- Pendant Support: Hardware pendant control via USB, Bluetooth, or GPIO
- Desktop Application: Native desktop apps available for Linux, macOS, and Windows
- Access Control: User authentication and permission management
- Configuration File: Persistent configuration with .cncrc JSON file
- Remote Access: Enable remote access for off-site CNC operation
- Console Output: Real-time console for monitoring CNC controller communication
Prerequisites
To deploy CNCjs on Klutch.sh, ensure you have the following:
- An active Klutch.sh account with access to the dashboard at klutch.sh/app
- A GitHub repository for version control
- Node.js 14 or higher runtime environment (provided by Klutch.sh Docker image)
- Understanding of CNC terminology and G-code concepts
- Knowledge of serial port communication and USB device configuration
- Familiarity with Docker and containerization
- CNC machine with compatible controller (Grbl, Marlin, Smoothieware, TinyG, or g2core)
Important Considerations
Deployment Steps
Create the Dockerfile
Create a
Dockerfilein the root directory of your repository:FROM node:18-alpine# Install build dependencies for node-serialportRUN apk add --no-cache \python3 \make \g++ \udev# Set working directoryWORKDIR /app# Install CNCjs globallyRUN npm install -g cncjs@latest# Create non-root user for running CNCjsRUN addgroup -g 1000 cncjs && \adduser -D -u 1000 -G cncjs cncjs# Create necessary directoriesRUN mkdir -p /home/cncjs/.cncrc.d && \mkdir -p /app/gcode && \chown -R cncjs:cncjs /home/cncjs && \chown -R cncjs:cncjs /app# Switch to non-root userUSER cncjs# Expose CNCjs default portEXPOSE 8000# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \CMD wget --quiet --tries=1 --spider http://localhost:8000 || exit 1# Start CNCjs serverCMD ["cncjs", "--host", "0.0.0.0", "--port", "8000", "--allow-remote-access"]This Dockerfile creates a Node.js-based CNCjs environment with proper user permissions and port configuration.
Create CNCjs Configuration File
Create a
.cncrcconfiguration file for CNCjs settings:{"watchDirectory": "/app/gcode","accessTokenLifetime": "30d","allowRemoteAccess": true,"baudrates": [115200, 250000, 230400, 57600, 38400, 19200, 9600],"state": {"checkForUpdates": true,"controller": {"exception": {"ignoreErrors": false}}},"commands": [{"title": "Check CNCjs Version","commands": "cncjs -V"},{"title": "Restart Server","commands": "pkill -f cncjs; sleep 2; cncjs --allow-remote-access"}],"events": [],"macros": [{"id": "home-all","title": "Home All Axes","commands": "$H"},{"id": "unlock","title": "Unlock Machine","commands": "$X"},{"id": "probe-z","title": "Probe Z Axis","commands": "G38.2 Z-50 F10"}],"users": []}Create Environment Configuration File
Create an
.env.examplefile with environment variables:# CNCjs Server ConfigurationCNCJS_PORT=8000CNCJS_HOST=0.0.0.0# Network and AccessCNCJS_ALLOW_REMOTE_ACCESS=trueCNCJS_ACCESS_TOKEN_LIFETIME=30d# Serial Port ConfigurationCNCJS_BAUDRATE=115200CNCJS_DATABITS=8CNCJS_STOPBITS=1CNCJS_PARITY=none# Controller ConfigurationCNCJS_CONTROLLER_TYPE=Grbl# G-Code Watch DirectoryCNCJS_WATCH_DIRECTORY=/app/gcode# LoggingCNCJS_LOG_LEVEL=info# Mount Points (for custom widgets and pendants)CNCJS_MOUNT_WIDGET=/widget:https://cncjs.github.io/cncjs-widget-boilerplate/v1/CNCJS_MOUNT_PENDANT=/pendant:/app/pendant# SecurityCNCJS_ENABLE_AUTH=false# Database Configuration (if using persistent user database)CNCJS_DB_PATH=/home/cncjs/.cncrcCreate Entrypoint Script
Create an
entrypoint.shfile for initialization:#!/bin/shset -eecho "Starting CNCjs initialization..."# Create necessary directoriesmkdir -p /home/cncjs/.cncrc.dmkdir -p /app/gcode# Copy default configuration if not existsif [ ! -f /home/cncjs/.cncrc ]; thenif [ -f /app/.cncrc ]; thencp /app/.cncrc /home/cncjs/.cncrcecho "Default configuration file created"fifi# Ensure correct permissionschmod 755 /app/gcode || trueecho "Starting CNCjs server..."# Start CNCjs with parametersexec cncjs \--host "0.0.0.0" \--port "${CNCJS_PORT:-8000}" \--watch-directory "/app/gcode" \--allow-remote-access \--access-token-lifetime "${CNCJS_ACCESS_TOKEN_LIFETIME:-30d}" \"$@"Update the Dockerfile CMD to use this script if custom initialization is needed.
Create a .gitignore File
Create a
.gitignorefile to exclude sensitive files:# Environment variables.env.env.local.env.*.local# CNCjs configuration.cncrcconfig.json# G-Code files*.gcode*.nc*.ngcgcode/# Node modulesnode_modules/npm-debug.logyarn-error.log# IDE and editor files.vscode/.idea/*.swp*.swo*~# OS files.DS_StoreThumbs.db# Logs*.loglogs/# Build artifactsdist/build/Push to GitHub
Initialize and push your repository:
Terminal window git initgit add Dockerfile entrypoint.sh .cncrc .env.example .gitignoregit commit -m "Initial CNCjs deployment setup"git branch -M maingit remote add origin https://github.com/YOUR_USERNAME/YOUR_REPOSITORY.gitgit push -u origin mainReplace
YOUR_USERNAMEandYOUR_REPOSITORYwith your actual GitHub credentials.Deploy on Klutch.sh
- Log in to your Klutch.sh dashboard at klutch.sh/app
- Click Create App and select GitHub
- Connect your GitHub account and select your CNCjs repository
- Configure deployment settings:
- App Name:
cncjs-controller(or your preferred name) - Branch: Select
main
- App Name:
- Add environment variables:
CNCJS_PORT:8000CNCJS_ALLOW_REMOTE_ACCESS:trueCNCJS_WATCH_DIRECTORY:/app/gcodeCNCJS_ACCESS_TOKEN_LIFETIME:30d- Other variables from
.env.exampleas needed
- Click Deploy and wait for deployment to complete
Klutch.sh automatically detects the Dockerfile and uses it for building and deploying your CNCjs instance.
Attach Persistent Storage (Optional)
If you want to store G-code files persistently:
- Navigate to your deployed CNCjs app
- Go to Storage or Volumes section
- Click Add Persistent Volume
- Configure the volume:
- Mount Path:
/app/gcode - Size:
10GB(adjust based on your G-code library)
- Mount Path:
- Click Add Volume and restart the container
This allows you to store and manage your G-code file library persistently.
Configure Network Traffic
Set up HTTP traffic for your CNCjs web interface:
- In your app settings, navigate to Network section
- Set Traffic Type to
HTTP - Internal port should be set to
8000(CNCjs default) - Your CNCjs interface will be accessible at
https://example-app.klutch.sh
Initial Setup and Configuration
After your CNCjs deployment is running, follow these steps to configure it:
Access the Web Interface
- Open your browser and navigate to
https://example-app.klutch.sh - You should see the CNCjs dashboard with an empty workspace
- The interface is ready for configuration
Configure Serial Port Connection
- Look for the Ports section in the left sidebar
- If your CNC machine is connected via serial port, it should appear in the ports list
- Select your CNC controller port from the dropdown
- Verify the correct baud rate is selected (typically 115200 for Grbl)
- Click Connect to establish the connection
Set Controller Type
- Go to Settings in the workspace
- Select your CNC controller type:
- Grbl: For Grbl and Grbl-Mega controllers
- Marlin: For Marlin-based 3D printers and CNC machines
- Smoothieware: For Smoothieware controllers
- TinyG: For TinyG and g2core controllers
- Save the controller type selection
Create a User Account
- Go to My Account section
- Set up your user profile with username and password
- Configure any user-specific preferences
- Save account settings
Upload G-Code Files
- Click the GCode widget in the sidebar
- Use the file browser to select and upload G-code files
- Uploaded files appear in your file library
- Files are stored in the watch directory for persistence
Verify CNC Machine Connection
- After connecting to your CNC controller, you should see:
- Machine status (Idle, Running, Hold, Alarm)
- Current position (X, Y, Z coordinates)
- Real-time feed rate and spindle speed
- Test the connection by sending a simple command like
$H(Home) - Verify the machine responds correctly
Environment Variables
Basic Configuration
CNCJS_PORT=8000CNCJS_HOST=0.0.0.0CNCJS_ALLOW_REMOTE_ACCESS=trueCNCJS_WATCH_DIRECTORY=/app/gcodeCNCJS_BAUDRATE=115200These variables control the basic CNCjs server configuration and connection parameters.
Production Configuration
For production deployments, use these environment variables with Nixpacks customization:
# Advanced Production Configuration
# Server ConfigurationCNCJS_PORT=8000CNCJS_HOST=0.0.0.0CNCJS_BACKLOG=511
# Security and Access ControlCNCJS_ALLOW_REMOTE_ACCESS=trueCNCJS_ACCESS_TOKEN_LIFETIME=30dCNCJS_ENABLE_AUTH=true
# Serial Port ConfigurationCNCJS_BAUDRATE=115200CNCJS_DATABITS=8CNCJS_STOPBITS=1CNCJS_PARITY=none
# CNC Controller ConfigurationCNCJS_CONTROLLER_TYPE=GrblCNCJS_CONTROLLER_BAUDRATE=115200
# Watch Directory ConfigurationCNCJS_WATCH_DIRECTORY=/app/gcode
# Mount Points for Widgets and PendantsCNCJS_MOUNT_WIDGET=/widget:https://cncjs.github.io/cncjs-widget-boilerplate/v1/CNCJS_MOUNT_PENDANT=/pendant:/app/pendantCNCJS_MOUNT_TINYWEB=/tinyweb:/app/tinyweb
# Logging and DebuggingCNCJS_LOG_LEVEL=infoCNCJS_VERBOSE_MODE=false
# Configuration File PathCNCJS_CONFIG_FILE=/home/cncjs/.cncrc
# Security SettingsCNCJS_CHECK_FOR_UPDATES=trueCNCJS_EXCEPTION_IGNORE_ERRORS=false
# Database ConfigurationCNCJS_DB_PATH=/home/cncjs/.cncrc.d
# Performance SettingsCNCJS_SOCKET_TIMEOUT=10000CNCJS_SESSION_SECRET=your-secret-key-change-this
# Language SettingsCNCJS_LANGUAGE=en
# Optional: Hardware Pendant SupportCNCJS_PENDANT_KEYBOARD=trueCNCJS_PENDANT_PS3=falseCNCJS_PENDANT_NUMPAD=falseTo apply these variables:
- Go to your app settings in the Klutch.sh dashboard
- Navigate to Environment Variables
- Add or update each variable
- Click Save and redeploy if necessary
Code Examples
JavaScript: CNCjs API Client
This example shows how to interact with CNCjs via its API:
// CNCjs API Client Exampleclass CNCjsClient { constructor(baseUrl, accessToken = null) { this.baseUrl = baseUrl || 'https://example-app.klutch.sh'; this.accessToken = accessToken; }
async request(method, endpoint, data = null) { const url = `${this.baseUrl}/api${endpoint}`; const headers = { 'Content-Type': 'application/json', };
if (this.accessToken) { headers['Authorization'] = `Bearer ${this.accessToken}`; }
const options = { method, headers, };
if (data) { options.body = JSON.stringify(data); }
const response = await fetch(url, options); return response.json(); }
// Get machine status async getStatus() { return this.request('GET', '/status'); }
// Get available ports async getPorts() { return this.request('GET', '/ports'); }
// Connect to a specific port async connectPort(port, baudrate = 115200) { return this.request('POST', `/ports/${port}`, { baudrate }); }
// Send G-code command async sendGCode(command) { return this.request('POST', '/gcode', { command }); }
// Get current position async getPosition() { return this.request('GET', '/position'); }
// List available G-code files async listGcodeFiles() { return this.request('GET', '/gcode/files'); }
// Load G-code file async loadGcodeFile(filename) { return this.request('POST', `/gcode/load`, { filename }); }
// Start job execution async startJob() { return this.request('POST', '/job/start', {}); }
// Pause job async pauseJob() { return this.request('POST', '/job/pause', {}); }
// Stop job async stopJob() { return this.request('POST', '/job/stop', {}); }}
// Usage exampleasync function main() { const client = new CNCjsClient('https://example-app.klutch.sh');
// Get machine status const status = await client.getStatus(); console.log('Machine Status:', status);
// Get available ports const ports = await client.getPorts(); console.log('Available Ports:', ports);
// Send home command const response = await client.sendGCode('$H'); console.log('Home Response:', response);
// Get current position const position = await client.getPosition(); console.log('Current Position:', position);}
main().catch(console.error);Bash: G-Code Batch Processing
This script processes and uploads multiple G-code files:
#!/bin/bash
# CNCjs G-Code Batch Processing Script
set -e
# ConfigurationCNCJS_URL="https://example-app.klutch.sh"GCODE_DIRECTORY="/app/gcode"LOG_FILE="/var/log/cncjs-batch.log"
echo "$(date): Starting G-code batch processing..." >> "$LOG_FILE"
# Function to validate G-code filevalidate_gcode() { local file="$1"
# Check for common G-code errors if grep -q "^G[0-9]\+ [^0-9]" "$file"; then echo "Warning: Potentially invalid G-code syntax in $file" >> "$LOG_FILE" return 1 fi
echo "G-code file validated: $file" >> "$LOG_FILE" return 0}
# Function to process G-code filesprocess_gcode_files() { for gcode_file in "$GCODE_DIRECTORY"/*.gcode; do if [ -f "$gcode_file" ]; then echo "Processing: $gcode_file" >> "$LOG_FILE"
# Validate the file if validate_gcode "$gcode_file"; then echo "Ready for execution: $gcode_file" >> "$LOG_FILE" else echo "Validation failed: $gcode_file" >> "$LOG_FILE" fi fi done}
# Function to get machine statuscheck_machine_status() { local status=$(curl -s "$CNCJS_URL/api/status" | grep -o '"state":"[^"]*"' | cut -d'"' -f4) echo "Machine Status: $status" >> "$LOG_FILE" echo "$status"}
# Function to list loaded G-code fileslist_gcode_files() { echo "Available G-code files:" >> "$LOG_FILE" ls -lh "$GCODE_DIRECTORY"/*.gcode >> "$LOG_FILE" 2>&1 || true}
# Main executionecho "Checking machine status..." >> "$LOG_FILE"STATUS=$(check_machine_status)
if [ "$STATUS" = "Idle" ] || [ "$STATUS" = "idle" ]; then echo "Machine is ready for operation" >> "$LOG_FILE" process_gcode_files list_gcode_fileselse echo "Machine is not in Idle state. Current state: $STATUS" >> "$LOG_FILE"fi
echo "$(date): Batch processing complete" >> "$LOG_FILE"Shell: CNCjs Control Commands
Common commands for controlling CNCjs from the terminal:
# Connect to CNCjs instanceCNCJS_HOST="https://example-app.klutch.sh"
# Get server statuscurl -X GET "$CNCJS_HOST/api/status" \ -H "Content-Type: application/json"
# List available serial portscurl -X GET "$CNCJS_HOST/api/ports" \ -H "Content-Type: application/json"
# Connect to a serial portcurl -X POST "$CNCJS_HOST/api/ports/COM3/open" \ -H "Content-Type: application/json" \ -d '{"baudrate": 115200}'
# Send G-code command (home all axes)curl -X POST "$CNCJS_HOST/api/gcode" \ -H "Content-Type: application/json" \ -d '{"command": "$H"}'
# Send unlock commandcurl -X POST "$CNCJS_HOST/api/gcode" \ -H "Content-Type: application/json" \ -d '{"command": "$X"}'
# Send absolute positioning commandcurl -X POST "$CNCJS_HOST/api/gcode" \ -H "Content-Type: application/json" \ -d '{"command": "G90"}'
# Send movement command (move to position)curl -X POST "$CNCJS_HOST/api/gcode" \ -H "Content-Type: application/json" \ -d '{"command": "G00 X10 Y20 Z5 F1000"}'
# Get current machine statecurl -X GET "$CNCJS_HOST/api/state" \ -H "Content-Type: application/json"
# Disconnect from portcurl -X POST "$CNCJS_HOST/api/ports/COM3/close" \ -H "Content-Type: application/json"Best Practices
CNC Machine Operation
- Pre-Flight Checks: Always verify machine position, tool installation, and workpiece setup before execution
- G-Code Verification: Carefully review G-code files and preview tool paths before running
- Test Runs: Perform dry runs without the spindle running to verify movements
- Monitor Execution: Actively supervise CNC operation and be ready to stop if issues occur
- Emergency Stop: Know the location and operation of emergency stops
- Safety First: Always prioritize safety over efficiency
Configuration Management
- Backup Configuration: Regularly back up your .cncrc configuration file
- Version Control: Keep your G-code files organized in version control
- Documentation: Document your CNC setup, controller type, and calibration settings
- Update Management: Keep CNCjs updated for bug fixes and new features
- Test Updates: Test updates in a non-production environment first
Performance and Reliability
- Connection Stability: Use stable serial connections (USB recommended over Bluetooth for critical operations)
- Network Optimization: For remote access, ensure low-latency network connections
- Backup Storage: Maintain backups of important G-code files
- Monitoring: Monitor CNCjs logs for errors and warnings
- Resource Limits: Ensure adequate system resources for smooth operation
Security
- Access Control: Use authentication when enabling remote access
- Network Security: Use HTTPS and strong passwords for remote deployments
- Token Management: Rotate access tokens regularly
- User Permissions: Limit access to trusted users only
- Audit Logging: Monitor who connects and what commands are executed
Troubleshooting
Issue: Cannot Connect to Serial Port
Solution: Verify the serial port is correctly identified and not already in use. Check USB cable connection if using USB serial adapter. Ensure user running CNCjs has serial port permissions. Test connection with serial port testing tools separately.
Issue: G-Code Not Loading or Executing
Solution: Verify G-code file format is compatible. Check file path and permissions. Validate G-code syntax using an online G-code validator. Ensure machine is in Idle state before sending commands. Check error messages in console output.
Issue: Machine Not Responding to Commands
Solution: Verify serial connection is established and showing connected status. Check if machine needs homing first ($H command). Ensure controller firmware matches CNCjs configuration. Test with simple commands (like $$ for settings dump) to verify communication.
Issue: Intermittent Connection Drops
Solution: Check USB cable quality and connections. Reduce baud rate to improve stability. Monitor system resources for CPU/memory issues. Consider upgrading to a higher-quality USB serial adapter. Check for USB hub issues if using hubs.
Issue: Slow Performance or Latency
Solution: Check network latency if using remote access. Reduce update frequency in settings. Monitor system resource usage (CPU, memory). Close unnecessary browser tabs and applications. Consider upgrading instance size if server-side performance is limited.
Updating CNCjs
To update to a newer version:
- Go to your Klutch.sh app dashboard
- Navigate to Deployments
- Update the Dockerfile to use a newer Node.js version or CNCjs version
- Commit and push changes to GitHub:
Terminal window git add Dockerfilegit commit -m "Update CNCjs and Node.js versions"git push origin main - Klutch.sh automatically redeploys with the updated version
- Verify CNCjs is running correctly after update
- Test machine connectivity and basic operations
Always test updates in a safe environment before production deployment.
Use Cases
Home Hobby CNC
Deploy CNCjs to control a hobby CNC mill or router from your workshop, enabling precise control and monitoring.
Production Manufacturing
Use CNCjs as the control interface for production CNC equipment with multi-user access and job management.
Makerspcae Equipment
Set up CNCjs as a shared CNC control station in a makerspace for community members to operate equipment safely.
Remote CNC Operation
Enable remote CNC machine operation by deploying CNCjs on a cloud server and connecting a CNC machine via stable network connection.
Educational Training
Use CNCjs in educational settings to teach students CNC operation and G-code programming with hands-on experience.
Prototyping and Product Development
Leverage CNCjs for rapid prototyping with quick design iteration and CNC manufacturing capabilities.
Additional Resources
- Official CNCjs Website: https://cnc.js.org
- GitHub Repository: https://github.com/cncjs/cncjs
- CNCjs Documentation: https://cnc.js.org/docs/
- Installation Guide: https://cnc.js.org/docs/installation/
- User Guide: https://cnc.js.org/docs/user-guide/
- Widget Development: https://github.com/cncjs/cncjs-widget-boilerplate
- Pendant Boilerplate: https://github.com/cncjs/cncjs-pendant-boilerplate
- G-Code Tools: http://jscut.org/
- Grbl Project: https://github.com/grbl/grbl
- Smoothieware Project: https://github.com/Smoothieware/Smoothieware
Conclusion
CNCjs provides a comprehensive, open-source solution for controlling CNC machinery through a web-based interface accessible from any device. By deploying CNCjs on Klutch.sh, you gain a scalable, maintainable platform for CNC operation with professional-grade features including 3D visualization, multi-client support, customizable widgets, and extensive hardware compatibility.
The combination of CNCjs’s powerful CNC control capabilities with Klutch.sh’s simplified deployment model makes it straightforward to establish web-based CNC control. Whether you’re running a hobby CNC mill, production equipment, or makerspace shared machinery, CNCjs provides the tools needed for effective CNC machine operation and control.
Start with the deployment steps outlined in this guide, configure your serial port or network connection, and gradually expand your CNCjs setup with custom widgets, pendants, and macros. Always prioritize safety and proper testing before operational use, and leverage the active community for support and best practices.