CLI as Docker container

The remote agent (zplcloud proxy) as a prebuilt multi-arch image for Raspberry Pi, Synology NAS and any Docker host. One outbound connection, no inbound ports.

Overview

  • Image docker.zplcloud.com/zplcloud-agent:latest - linux/amd64 + linux/arm64, public, no login.
  • Runs zplcloud proxy: outbound HTTPS/WebSocket to api.zplcloud.com; works behind NAT and firewalls.
  • Printers in the "Remote Printers" tab receive jobs, profiles and probes through the agent: LAN (TCP 9100) or USB (CDC-ACM serial or libusb printer class).
  • restart: unless-stopped provides autostart; optional daily log file.

Prerequisites

  • Docker (Desktop, Engine or Synology Container Manager).
  • API key (platform → API).
  • Printers in the same LAN (TCP 9100) or connected via USB.

docker-compose.agent.yml

Set ZPLCLOUD_API_KEY and ZPLCLOUD_AGENT:

# docker-compose.agent.yml
services:
  zplcloud-agent:
    image: docker.zplcloud.com/zplcloud-agent:latest
    container_name: zplcloud-agent
    restart: unless-stopped
    environment:
      ZPLCLOUD_API_KEY: "sk_zplcloud_CHANGE_ME"     # API tab
      ZPLCLOUD_AGENT: "PI"                           # name in the Remote Printers tab
      ZPLCLOUD_API_BASE: "https://api.zplcloud.com"  # backend (outbound)
      ZPLCLOUD_VERBOSE: "false"                      # true = SignalR trace
      ZPLCLOUD_LOG: "true"                           # write zplcloud-<yyyy-MM-dd>.log
      ZPLCLOUD_LOG_DIR: "logs/zplcloud-logs"
      ZPLCLOUD_TIMEOUT: "5000"
    volumes:
      - ./logs/zplcloud-logs:/logs/zplcloud-logs
      # raw USB bus (libusb needs it to detect the Zebra printer)
      - /dev/bus/usb:/dev/bus/usb
    # simplest USB path (printer class AND CDC-ACM serial)
    privileged: true
    # safer alternative: remove privileged, pass devices + udev rule
    # devices:
    #   - "/dev/bus/usb:/dev/bus/usb:rwm"
    #   - "/dev/ttyACM0:/dev/ttyACM0:rwm"
    #   - "/dev/ttyUSB0:/dev/ttyUSB0:rwm"

The platform generates this file with your values under ZPL CLI (Docker Compose or command line, private or company scope).

Environment variables

VariableRequiredMeaning
ZPLCLOUD_API_KEYyesAPI key; authenticates the agent.
ZPLCLOUD_AGENTyesDisplay name in the Remote Printers tab.
ZPLCLOUD_API_BASEnoBase URL (default https://api.zplcloud.com).
ZPLCLOUD_VERBOSEnotrue = SignalR negotiation/transport trace.
ZPLCLOUD_LOGnotrue = write zplcloud-<yyyy-MM-dd>.log into ZPLCLOUD_LOG_DIR.
ZPLCLOUD_LOG_DIRnoLog directory in the container (bind mount ./logs/zplcloud-logs).
ZPLCLOUD_TIMEOUTnoConnect/read timeout in ms (default 5000).

Start, logs, update

docker compose -f docker-compose.agent.yml up -d          # start
docker compose -f docker-compose.agent.yml logs -f zplcloud-agent
docker compose -f docker-compose.agent.yml restart          # e.g. after an API key change
docker compose -f docker-compose.agent.yml pull && docker compose -f docker-compose.agent.yml up -d   # update
docker compose -f docker-compose.agent.yml down             # stop / remove

Platforms

  • linux/amd64 - x64 Linux, x64 Synology, Intel Docker hosts, Docker Desktop on Windows (WSL2).
  • linux/arm64 - 64-bit Raspberry Pi OS, ARM Synology, Apple Silicon.
  • 32-bit Raspberry Pi: no image; use the native installer (linux-arm).

USB printers

  • privileged: true covers printer class (libusb) and CDC-ACM serial.
  • Without privileged: pass the devices explicitly (devices: above) and add a udev rule, e.g. GROUP="dialout", MODE="0660" for the Zebra vendor ID.

Troubleshooting

SymptomCheck
Agent not onlineZPLCLOUD_API_KEY; docker compose logs -f; ZPLCLOUD_VERBOSE=true for the SignalR trace.
USB printer not foundprivileged: true or devices + udev rule; /dev/bus/usb must be mounted.
TCP 9100 unreachablePrinter IP/host in the Remote Printers tab; printer and container in the same LAN.