Skip to content

Deploying CUPS

Introduction

CUPS (Common Unix Printing System) is the industry-standard, open-source printing system for Linux and Unix-like operating systems. It provides a standards-based, modern approach to printing that supports both local and network printers through a web-based administration interface and command-line tools. CUPS enables centralized print server management with support for AirPrint, IPP Everywhere, and legacy PostScript printers, making it ideal for organizations needing enterprise-grade network printing capabilities.

Key Features

  • Web-Based Administration: Intuitive web interface for managing printers, print jobs, and queues at localhost:631/admin/
  • IPP Everywhere Support: Native support for Internet Printing Protocol Everywhere standards for modern printer compatibility
  • AirPrint Support: Full AirPrint capability for seamless printing from Apple devices
  • Legacy Printer Support: PPD (PostScript Printer Description) driver support for older printer models
  • Berkeley and System V Commands: Both lpr/lpq and lp/lpstat command interfaces for maximum compatibility
  • Print Filters: Built-in filters for handling PDF, PostScript, text, and image files
  • Network Printing: Support for both local USB printers and network-attached printers
  • Print Queue Management: Full job queuing, prioritization, and queue administration
  • Multi-User Support: Role-based access control with admin, operator, and user roles
  • Print Job History: Complete logging and history of all print jobs
  • Printer Classes: Ability to create printer classes for load distribution
  • Class-Based Printing: Support for printer classes and printer pools
  • Custom Filters: Extensible filter system for custom print processing
  • LDAP Integration: Support for LDAP-based user authentication and authorization
  • Kerberos Support: Enterprise Kerberos authentication capabilities
  • Share Remote Printers: Share printers across the network with other CUPS servers
  • Subscription Model: Event-based notification system for print job status
  • Accounting: Basic print job accounting and tracking
  • Media Selection: Support for multiple paper sizes and media types
  • Color Management: Advanced color profile support and management
  • Duplex Printing: Full duplex (double-sided) printing support
  • Print Resolution Options: Configurable print resolution settings

Prerequisites

Before deploying CUPS on Klutch.sh, ensure you have:

  • A Klutch.sh account with access to the dashboard
  • A GitHub repository for your CUPS deployment (public or private)
  • Basic understanding of printer configuration and networking
  • Access to printer device URIs or IP addresses for network printers

Important Considerations

Deployment Steps

  1. Create a Dockerfile

    Create a Dockerfile in the root of your repository with a CUPS image. This Dockerfile sets up CUPS with necessary dependencies for printer support:

    FROM ubuntu:22.04
    # Install CUPS and dependencies
    RUN apt-get update && apt-get install -y \
    cups \
    cups-client \
    cups-common \
    cups-filters \
    cups-filters-core-drivers \
    printer-driver-cups-pdf \
    poppler-utils \
    ghostscript \
    sudo \
    net-tools \
    curl \
    && rm -rf /var/lib/apt/lists/*
    # Create spool directory
    RUN mkdir -p /var/spool/cups && \
    mkdir -p /var/cache/cups && \
    mkdir -p /var/log/cups
    # Copy custom configuration if needed
    COPY cupsd.conf /etc/cups/cupsd.conf 2>/dev/null || true
    # Expose CUPS port
    EXPOSE 631
    # Start CUPS daemon
    CMD ["cupsd", "-f"]
  2. Create cupsd.conf Configuration

    Create a cupsd.conf file in your repository root with the following configuration for network access and basic security:

    # Log everything
    LogLevel warn
    MaxLogSize 0
    # Listen on all interfaces
    Listen 0.0.0.0:631
    Listen /run/cups/cups.sock
    # Restrict access to the server
    <Location />
    Order allow,deny
    </Location>
    # Restrict access to the admin pages
    <Location /admin>
    Order allow,deny
    </Location>
    # Restrict access to configuration files
    <Location /admin/conf>
    Order allow,deny
    </Location>
    # Set the default printer/job policies
    <Policy default>
    <Limit All>
    Order deny,allow
    </Limit>
    </Policy>
  3. Create Environment Variables File

    Create a .env.example file in your repository root for local development and configuration documentation:

    # CUPS Configuration
    CUPS_PORT=631
    CUPS_LISTEN_ADDRESS=0.0.0.0
    # Printer Configuration
    CUPS_PRINTER_NAME=DefaultPrinter
    CUPS_PRINTER_URI=
    CUPS_PRINTER_MODEL=everywhere
    # Logging
    CUPS_LOG_LEVEL=warn
    # Advanced Options
    CUPS_MAX_LOG_SIZE=0
    CUPS_SHARE_PRINTERS=yes
    CUPS_USER_CANCEL_ANY=no
  4. Create .gitignore File

    Create a .gitignore file to exclude sensitive files from version control:

    # CUPS configurations with sensitive data
    cupsd.conf.local
    printers.conf
    classes.conf
    subscriptions.conf
    # Temporary files
    *.tmp
    *.log
    # Development files
    .DS_Store
    Thumbs.db
    # Environment specific files
    .env
    .env.local
  5. Push to GitHub

    Push your repository to GitHub. Ensure your Dockerfile, cupsd.conf, .env.example, and .gitignore are committed:

    Terminal window
    git add Dockerfile cupsd.conf .env.example .gitignore
    git commit -m "Initial CUPS deployment configuration"
    git push origin main
  6. Deploy on Klutch.sh

    1. Navigate to klutch.sh/app and log in to your dashboard
    2. Click Create New App
    3. Select Docker as the deployment method (detected automatically from your Dockerfile)
    4. Connect your GitHub repository containing the CUPS deployment files
    5. Confirm the Dockerfile is detected from your root directory
    6. Click Deploy to start the deployment process
    7. Wait for the deployment to complete and your app to become active
  7. Configure Traffic Rules

    1. In your app dashboard, navigate to Traffic settings
    2. Select HTTP as the traffic type
    3. Set the internal port to 631 (CUPS default port)
    4. Save your traffic configuration
    5. Your CUPS server will be accessible at example-app.klutch.sh
  8. Attach Persistent Volume

    1. In your app dashboard, go to Volumes settings
    2. Click Add Volume
    3. Enter mount path: /var/spool/cups
    4. Set volume size to 50GB (adjust based on your print job volume)
    5. Click Attach to create and mount the persistent volume
    6. The volume will automatically persist print jobs, queue data, and configurations across deployments

Initial Setup and Configuration

After deploying CUPS on Klutch.sh, access the web interface at example-app.klutch.sh (or your deployed domain). Follow these steps to complete your setup:

Access the Web Interface

  1. Navigate to http://example-app.klutch.sh in your browser
  2. You should see the CUPS home page with various options
  3. Click Administration or go to /admin/ for printer management
  4. For first-time setup, you may need to authenticate with admin credentials

Add a Printer

  1. In the Administration page, click Add Printer
  2. You’ll be prompted for credentials (use root or an admin account)
  3. Select your printer type:
    • Network Printer: For IP-based network printers
    • USB Printer: For directly connected USB printers
    • Shared Printers: From other CUPS servers
  4. Enter the printer connection details (IP address or URI)
  5. Select the appropriate driver:
    • Use IPP Everywhere for modern network printers
    • Use AirPrint for Apple devices and AirPrint-capable printers
    • Select specific driver for legacy printers
  6. Configure basic printer options (media sizes, default settings)
  7. Click Share This Printer if you want to share it across your network

Create Print Queues

  1. After adding printers, create logical print queues for different departments or use cases
  2. Use the Printers and Classes section to manage queues
  3. Assign printers to classes for load balancing

Configure User Access

  1. Go to Administration > Server Settings
  2. Configure who can manage printers and jobs
  3. Add users to the lpadmin group for administrative privileges
  4. Set policies for job cancellation, sharing, and browsing

Environment Variables

Basic Configuration

Configure these environment variables through your deployment environment:

  • CUPS_PORT=631 - Port on which CUPS listens (default: 631)
  • CUPS_LISTEN_ADDRESS=0.0.0.0 - Address to listen on (0.0.0.0 for all interfaces)
  • CUPS_LOG_LEVEL=warn - Logging level (error, warn, info, debug)
  • CUPS_MAX_LOG_SIZE=0 - Maximum log file size in bytes (0 for unlimited)

Production Environment Variables

For production deployments, use Nixpacks environment variables to customize CUPS behavior:

# Production printer sharing settings
CUPS_SHARE_PRINTERS=yes
CUPS_BROWSE_LOCAL_PRINTERS=yes
# Job management
CUPS_USER_CANCEL_ANY=no
CUPS_ALLOW_USER_CANCEL_CURRENT_JOB=yes
# Security and access control
CUPS_CREATE_SPOOL_DIR=yes
CUPS_LOG_FILE_PERM=0600
# Performance tuning
CUPS_MAX_CLIENTS=100
CUPS_MAX_CLIENTS_PER_HOST=10
CUPS_MAX_JOBS=500
# Network settings
CUPS_LISTEN_BACKLOG=128
CUPS_TIMEOUT=300
CUPS_KEEP_ALIVE=yes
CUPS_KEEP_ALIVE_TIMEOUT=60

These variables can be set in your Klutch.sh app settings to override default behavior during deployment.

Code Examples

JavaScript - CUPS HTTP API Client

// CUPS HTTP API Client for job management
const axios = require('axios');
class CUPSClient {
constructor(host = 'example-app.klutch.sh', port = 631) {
this.baseURL = `http://${host}:${port}`;
this.client = axios.create({
baseURL: this.baseURL,
timeout: 30000,
});
}
// Get all printers
async getPrinters() {
try {
const response = await this.client.get('/admin/');
return response.data;
} catch (error) {
console.error('Error fetching printers:', error.message);
throw error;
}
}
// Get printer status
async getPrinterStatus(printerName) {
try {
const response = await this.client.get(`/printers/${printerName}`);
return response.data;
} catch (error) {
console.error(`Error getting status for ${printerName}:`, error.message);
throw error;
}
}
// Get print jobs
async getJobs(printerName, limit = 100) {
try {
const response = await this.client.get(`/jobs/?printer-name=${printerName}&limit=${limit}`);
return response.data;
} catch (error) {
console.error('Error fetching jobs:', error.message);
throw error;
}
}
// Pause printer
async pausePrinter(printerName) {
try {
const response = await this.client.post(`/admin/?OP=hold-new-jobs&PRINTER_NAME=${printerName}`);
return response.data;
} catch (error) {
console.error(`Error pausing printer ${printerName}:`, error.message);
throw error;
}
}
// Resume printer
async resumePrinter(printerName) {
try {
const response = await this.client.post(`/admin/?OP=release-held-new-jobs&PRINTER_NAME=${printerName}`);
return response.data;
} catch (error) {
console.error(`Error resuming printer ${printerName}:`, error.message);
throw error;
}
}
// Cancel print job
async cancelJob(jobId, printerName) {
try {
const response = await this.client.post(
`/admin/?OP=cancel-job&PRINTER_NAME=${printerName}&JOB_ID=${jobId}`
);
return response.data;
} catch (error) {
console.error(`Error canceling job ${jobId}:`, error.message);
throw error;
}
}
}
// Usage example
async function main() {
const cups = new CUPSClient('example-app.klutch.sh', 631);
const printers = await cups.getPrinters();
console.log('Available Printers:', printers);
const status = await cups.getPrinterStatus('DefaultPrinter');
console.log('Printer Status:', status);
const jobs = await cups.getJobs('DefaultPrinter', 50);
console.log('Recent Jobs:', jobs);
}
main().catch(console.error);

Bash - Print Job Management Script

#!/bin/bash
# CUPS Print Job Management Script
# Requires: curl, lpstat, lp commands
CUPS_HOST="example-app.klutch.sh"
CUPS_PORT="631"
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to list all printers
list_printers() {
echo -e "${GREEN}Available Printers:${NC}"
lpstat -p -d 2>/dev/null || curl -s "http://${CUPS_HOST}:${CUPS_PORT}/printers" | grep -o '<tr><td><a[^>]*>[^<]*</a>' | sed 's/<[^>]*>//g'
}
# Function to check printer status
check_printer_status() {
local printer=$1
echo -e "${GREEN}Status for ${printer}:${NC}"
lpstat -p "${printer}" 2>/dev/null || echo "Printer not found or offline"
}
# Function to view print queue
view_queue() {
local printer=${1:-""}
echo -e "${GREEN}Print Queue:${NC}"
if [ -z "$printer" ]; then
lpstat -o 2>/dev/null || curl -s "http://${CUPS_HOST}:${CUPS_PORT}/jobs" | grep -o 'job-[0-9]*'
else
lpstat -o -P "${printer}" 2>/dev/null || echo "No jobs for $printer"
fi
}
# Function to print a file
print_file() {
local file=$1
local printer=${2:-""}
if [ ! -f "$file" ]; then
echo -e "${RED}Error: File '$file' not found${NC}"
return 1
fi
if [ -z "$printer" ]; then
lp "$file" 2>/dev/null && echo -e "${GREEN}File sent to default printer${NC}"
else
lp -d "${printer}" "$file" 2>/dev/null && echo -e "${GREEN}File sent to ${printer}${NC}"
fi
}
# Function to cancel print job
cancel_job() {
local job_id=$1
if [ -z "$job_id" ]; then
echo -e "${RED}Error: Job ID required${NC}"
return 1
fi
cancel "$job_id" 2>/dev/null && echo -e "${GREEN}Job $job_id cancelled${NC}" || echo -e "${RED}Failed to cancel job $job_id${NC}"
}
# Function to get job details
get_job_details() {
local job_id=$1
if [ -z "$job_id" ]; then
echo -e "${RED}Error: Job ID required${NC}"
return 1
fi
lpstat -t | grep "$job_id" || echo "Job $job_id not found"
}
# Main menu
case "${1:-help}" in
list)
list_printers
;;
status)
check_printer_status "${2:-DefaultPrinter}"
;;
queue)
view_queue "$2"
;;
print)
print_file "$2" "$3"
;;
cancel)
cancel_job "$2"
;;
details)
get_job_details "$2"
;;
*)
echo -e "${YELLOW}CUPS Print Job Management${NC}"
echo "Usage: $0 {list|status|queue|print|cancel|details} [args]"
echo ""
echo "Commands:"
echo " list - List all available printers"
echo " status [printer] - Check printer status"
echo " queue [printer] - View print queue"
echo " print <file> [printer] - Print a file"
echo " cancel <job-id> - Cancel a print job"
echo " details <job-id> - Get job details"
;;
esac

Shell - CUPS REST API Operations

#!/bin/sh
# CUPS REST API Operations
# Requires: curl
CUPS_URL="http://example-app.klutch.sh:631"
# Get CUPS server status
get_server_status() {
echo "Getting CUPS server status..."
curl -s -X GET "$CUPS_URL/" | head -20
}
# Get all printers (CUPS-Get-Printers operation)
get_all_printers() {
echo "Fetching all printers..."
curl -s -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "OP=CUPS-Get-Printers" \
"$CUPS_URL/ipp"
}
# Get printer attributes
get_printer_attributes() {
local printer=$1
echo "Getting attributes for printer: $printer"
curl -s -X GET "$CUPS_URL/printers/$printer" | head -30
}
# Get current jobs on a printer
get_printer_jobs() {
local printer=${1:-DefaultPrinter}
echo "Getting jobs for printer: $printer"
curl -s -X GET "$CUPS_URL/jobs/?printer-name=$printer"
}
# Pause a printer
pause_printer() {
local printer=$1
echo "Pausing printer: $printer"
curl -s -X POST \
"$CUPS_URL/admin/?OP=hold-new-jobs&PRINTER_NAME=$printer" \
-w "\nStatus: %{http_code}\n"
}
# Resume a printer
resume_printer() {
local printer=$1
echo "Resuming printer: $printer"
curl -s -X POST \
"$CUPS_URL/admin/?OP=release-held-new-jobs&PRINTER_NAME=$printer" \
-w "\nStatus: %{http_code}\n"
}
# Get CUPS version
get_cups_version() {
echo "CUPS Version Information:"
curl -s -X GET "$CUPS_URL/" | grep -i "version\|cups" | head -5
}
# Monitor printer queue in real-time
monitor_queue() {
local printer=${1:-DefaultPrinter}
echo "Monitoring print queue for: $printer (refresh every 5 seconds)"
while true; do
clear
echo "=== Print Queue Monitor ==="
echo "Printer: $printer"
echo "Last updated: $(date)"
echo ""
curl -s -X GET "$CUPS_URL/jobs/?printer-name=$printer&limit=10" | grep -E "job-[0-9]+|id=|<td"
sleep 5
done
}
# Main script
case "${1:-status}" in
status)
get_server_status
;;
printers)
get_all_printers
;;
attributes)
get_printer_attributes "${2:-DefaultPrinter}"
;;
jobs)
get_printer_jobs "${2:-DefaultPrinter}"
;;
pause)
pause_printer "$2"
;;
resume)
resume_printer "$2"
;;
version)
get_cups_version
;;
monitor)
monitor_queue "$2"
;;
*)
echo "CUPS REST API Operations"
echo "Usage: $0 {status|printers|attributes|jobs|pause|resume|version|monitor} [args]"
echo ""
echo "Commands:"
echo " status - Get CUPS server status"
echo " printers - Get all printers"
echo " attributes [printer] - Get printer attributes"
echo " jobs [printer] - Get printer jobs"
echo " pause <printer> - Pause a printer"
echo " resume <printer> - Resume a printer"
echo " version - Get CUPS version"
echo " monitor [printer] - Monitor queue in real-time"
;;
esac

Best Practices

  • Backup Configurations: Regularly backup your CUPS configuration files from the persistent volume to recover settings after updates
  • Monitor Disk Space: Set up monitoring for the print spool volume to prevent queue saturation and job failures
  • Use Strong Authentication: Configure admin authentication with strong passwords and consider LDAP integration for enterprise deployments
  • Network Printer Verification: Test network printer connectivity before adding to CUPS to ensure proper device URIs and driver support
  • Log Review: Regularly review CUPS logs in /var/log/cups/ for errors, warnings, and performance issues
  • Security Configuration: Restrict web interface access through firewall rules and VPN if not in a trusted network
  • Update Print Drivers: Keep printer drivers and PPD files updated for compatibility with newer printer models
  • Queue Maintenance: Regularly remove completed or failed print jobs to maintain queue efficiency
  • Performance Tuning: Adjust MaxClients and job limit settings based on your deployment’s workload
  • Rate Limiting: For shared servers, implement print job rate limiting to prevent resource exhaustion

Troubleshooting

Issue: Web interface not accessible

  • Ensure CUPS service is running: verify the deployment status in your Klutch.sh dashboard
  • Check traffic rules configuration: confirm HTTP traffic is routed to port 631
  • Verify firewall: ensure port 631 is not blocked by network policies
  • Check Docker logs: access app logs in the dashboard to see CUPS startup errors

Issue: Cannot add network printer

  • Verify network connectivity: ensure CUPS container can reach the printer’s IP address
  • Check printer discovery: use network scanning tools to confirm printer is online and responding
  • Validate device URI: ensure the URI format is correct (e.g., ipp://192.168.1.100:631/ipp/print)
  • Test with generic driver: try using the IPP Everywhere driver first before specific drivers

Issue: Print jobs stuck in queue

  • Clear stuck jobs: use the web interface to view and cancel problematic jobs
  • Restart CUPS service: redeploy or restart the container to clear in-memory queues
  • Check disk space: monitor persistent volume usage to ensure sufficient space for print spool
  • Review permissions: verify the print queue directory has correct ownership and permissions

Issue: Slow print performance

  • Monitor resource usage: check CPU and memory usage in the Klutch.sh dashboard
  • Review active jobs: check for resource-intensive print jobs or filters
  • Optimize filters: disable unnecessary filters if print quality permits
  • Increase timeout: adjust CUPS timeout settings for slow network printers

Issue: Authentication failures for admin functions

  • Verify user groups: ensure admin users are members of the lpadmin group
  • Check credentials: confirm username and password are correct
  • Review configuration: inspect cupsd.conf for authentication policy settings
  • Check logs: review CUPS error logs for specific authentication errors

Update Instructions

To update CUPS to the latest version:

  1. Update the Base Image: Modify your Dockerfile to use the latest Ubuntu LTS image
  2. Redeploy: Push the updated Dockerfile to your GitHub repository
  3. Trigger Deployment: In the Klutch.sh dashboard, manually trigger a redeploy or wait for automatic updates
  4. Preserve Data: Your persistent volumes will retain print queues and configurations during the update
  5. Verify: After deployment, test printer functionality and queue operations

Example Dockerfile update:

FROM ubuntu:24.04 # Updated from 22.04
# Rest of Dockerfile remains the same

Use Cases

  • Office Print Server: Centralized network printing for office environments with multiple printers and users
  • Managed Print Services: Enterprise-grade print management with accounting and job tracking
  • Mobile Printing: Enable AirPrint support for seamless printing from iOS and macOS devices
  • Label Printing: PDF-to-label printing for shipping, inventory, and organizational workflows
  • Print-to-File: Create PDF files from any printable document using the PDF printer
  • Distributed Printing: Share a single expensive printer across multiple locations via network
  • Legacy Device Integration: Bridge between modern systems and older printers with PPD drivers
  • Automated Document Processing: Integrate with workflow systems for automatic document printing
  • Print Job Quotas: Monitor and limit printing by user or department for cost control
  • Cross-Platform Compatibility: Support Windows, macOS, and Linux clients from a single server

Additional Resources

Conclusion

Deploying CUPS on Klutch.sh provides a powerful, centralized printing solution with enterprise-grade management capabilities. By following this guide, you’ve set up a production-ready print server with persistent storage, network printer support, and a comprehensive web interface for administration.

Your CUPS deployment is now ready to handle network printing operations. Access the administration interface at example-app.klutch.sh, add your network printers, and begin managing print jobs across your organization. With persistent volumes configured, your print queue and settings will survive deployments and updates.

For advanced configurations, additional printer integrations, or troubleshooting assistance, refer to the official CUPS documentation and community resources linked above. Regular monitoring and maintenance of your deployment will ensure optimal printing performance and reliability.