Proxy server for thermal printers using ESC/POS commands. Designed to work with POS systems like IIKO, RKEEPER, and JOWI.
Supports both Linux and Windows!
- USB Printer Support: Auto-discovery of USB thermal printers
- Linux: Direct access via
/dev/usb/lp*,/dev/ttyUSB* - Windows: Direct USB via LibUSB (no drivers needed!) or Windows Spooler
- Linux: Direct access via
- Network Printer Support: TCP/IP connection to network printers (port 9100)
- Serial Port Support: COM port printers (Windows)
- ESC/POS Commands: Native ESC/POS command generation
- Cyrillic Support: CP866 encoding for Russian text
- Web Interface: Test printing from browser
- REST API: Simple JSON API for integration
- Windows Service: Easy deployment on Windows servers
- systemd Service: Easy deployment on Linux servers
- Ubuntu 22.04 LTS or newer
- .NET 8 Runtime/SDK
- Windows 10/11 or Windows Server 2016+
- .NET 8 Runtime/SDK (or use self-contained .exe)
- USB or Network thermal printer (XPRINTER, EPSON, etc.)
# Download from releases
# Extract to C:\OpenPrint
# Run OpenPrint.exe# Clone repository
cd OpenPrint
# Build self-contained .exe
dotnet publish -c Release -r win-x64 --self-contained true -o ./publish/win-x64
# Run
.\publish\win-x64\OpenPrint.exe# Run as Administrator
.\install.ps1
# Or manually:
sc.exe create OpenPrint binPath="C:\OpenPrint\OpenPrint.exe" start=auto
sc.exe start OpenPrint# Clone or download the project
cd OpenPrint
# Run installation script (as root)
sudo ./install.shOpenPrint can communicate directly with USB printers without installing manufacturer drivers!
OpenPrint uses LibUSB to send raw ESC/POS data directly to the USB device, bypassing the Windows Print Spooler.
# List all USB devices
.\drivers\install-winusb.ps1 -ListDevicesOr check Device Manager:
- Open Device Manager
- Find your printer
- Properties → Details → Hardware IDs
- Note the VID and PID (e.g.,
USB\VID_0483&PID_5720)
# Automatic (recommended)
.\drivers\install-winusb.ps1 -Auto
# Or for specific device
.\drivers\install-winusb.ps1 -VendorId "0483" -ProductId "5720"This will:
- Download Zadig (driver installer)
- Create an INF file for your printer
- Open Zadig for driver installation
In Zadig:
- Options → List All Devices
- Select your printer (e.g., "USB Printing Support")
- Select WinUSB as target driver
- Click "Replace Driver"
If auto-discovery doesn't find your printer, add it manually to appsettings.json:
{
"OpenPrint": {
"LibUsbPrinters": [
{
"Name": "My Thermal Printer",
"VendorId": 1155,
"ProductId": 22304,
"Enabled": true
}
]
}
}Note: VendorId/ProductId should be in decimal. Convert hex to decimal:
- 0x0483 = 1155
- 0x5720 = 22304
If you need to restore the original printer driver:
- Open Device Manager
- Find the printer (may be under "Universal Serial Bus devices")
- Right-click → Update Driver
- Browse → Let me pick from available drivers
- Select the original manufacturer driver
Edit appsettings.json:
{
"OpenPrint": {
"Port": 5050,
"Host": "127.0.0.1",
"AutoDiscoverUSB": true,
// Windows: Enable/disable discovery methods
"UseLibUsb": true,
"UseWindowsSpooler": true,
// Linux: USB device paths
"UsbDevicePaths": [
"/dev/usb/lp*",
"/dev/ttyUSB*"
],
// Windows: LibUSB printers (direct USB, no drivers)
"LibUsbPrinters": [
{
"Name": "Kitchen Printer",
"VendorId": 1155,
"ProductId": 22304,
"Enabled": false
}
],
// Windows: Printers with installed drivers
"WindowsPrinters": [
{
"Name": "Bar Printer",
"WindowsPrinterName": "XPRINTER XP-80C",
"Enabled": false
}
],
// Windows: Serial/COM port printers
"SerialPorts": [
{
"Name": "COM Printer",
"PortName": "COM3",
"BaudRate": 9600,
"Enabled": false
}
],
// Network printers (works on both platforms)
"NetworkPrinters": [
{
"Name": "Network Printer",
"IpAddress": "192.168.1.100",
"Port": 9100,
"Enabled": true
}
],
"PrintDefaults": {
"PaperCut": true,
"Encoding": "CP866"
}
}
}http://127.0.0.1:5050
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
Service health check |
GET |
/api/printers |
List all printers |
POST |
/api/printers/refresh |
Force refresh printer list |
POST |
/api/print |
Print content |
POST |
/api/print/test |
Print test page |
POST |
/api/printers/{id}/test |
Print test page to specific printer |
POST /api/print
Content-Type: application/json
{
"printerIdentifier": "usb_0483_5720",
"content": "Hello World!\nПривет Мир!",
"options": {
"fontSize": "normal",
"alignment": "center",
"cutPaper": true,
"encoding": "CP866"
}
}{
"success": true,
"message": "Print successful",
"printerUsed": "Kitchen Printer",
"timestamp": "2025-12-15T10:30:00Z"
}# Health check
curl http://localhost:5050/api/health
# List printers
curl http://localhost:5050/api/printers
# Print
curl -X POST http://localhost:5050/api/print \
-H "Content-Type: application/json" \
-d '{"content": "Test print\nТестовая печать", "options": {"cutPaper": true}}'import requests
client = requests.Session()
base_url = "http://localhost:5050"
# Print receipt
response = client.post(f"{base_url}/api/print", json={
"content": "Order #123\n\nCoffee x2\nTotal: 200.00",
"options": {"alignment": "center", "cutPaper": True}
})
print(response.json())const response = await fetch('http://localhost:5050/api/print', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: 'Hello World!',
options: { cutPaper: true }
})
});
const result = await response.json();
console.log(result);# Install service
.\install.ps1
# Uninstall service
.\install.ps1 -Uninstall
# Manual commands
Start-Service OpenPrint
Stop-Service OpenPrint
Restart-Service OpenPrint
Get-Service OpenPrint
# View logs
Get-EventLog -LogName Application -Source OpenPrint -Newest 50sudo systemctl start openprint
sudo systemctl stop openprint
sudo systemctl restart openprint
sudo systemctl status openprint
sudo journalctl -u openprint -f-
Check WinUSB driver is installed
.\drivers\install-winusb.ps1 -ListDevices
-
Verify device in Device Manager
- Should appear under "Universal Serial Bus devices"
- NOT under "Printers" (that means Windows driver is active)
-
Check configuration
- Ensure
UseLibUsb: truein appsettings.json - Add printer manually to
LibUsbPrintersif auto-discovery fails
- Ensure
Some printers may not work with WinUSB. Use Windows Spooler mode:
{
"UseLibUsb": false,
"UseWindowsSpooler": true,
"WindowsPrinters": [
{
"Name": "My Printer",
"WindowsPrinterName": "EXACT NAME FROM CONTROL PANEL",
"Enabled": true
}
]
}sudo usermod -aG lp $USER
sudo usermod -aG dialout $USER
# Logout and login again# Test connectivity
nc -zv 192.168.1.100 9100
# Check firewall
sudo ufw allow from 192.168.1.0/24 to any port 9100- Ensure CP866 encoding in config
- Some printers need firmware update for Cyrillic
- Try Windows-1251 encoding as alternative
Tested with:
- XPRINTER XP-80C
- XPRINTER XP-58
- XPRINTER XP-365B
- EPSON TM-T88V
- POS-58 series
- Star TSP100
- Citizen CT-S310
Most ESC/POS compatible thermal printers should work.
OpenPrint/
├── Models/
│ ├── AppSettings.cs # Configuration classes
│ ├── Printer.cs # Printer model
│ ├── PrintRequest.cs # API request model
│ └── PrintResponse.cs # API response model
├── Services/
│ ├── IPrinterService.cs # Service interfaces
│ ├── PrinterService.cs # Main orchestration
│ ├── UsbPrinterDiscovery.cs # Linux USB discovery
│ ├── WindowsUsbPrinterDiscovery.cs # Windows USB discovery
│ ├── WindowsPrinterManager.cs # Windows Spooler P/Invoke
│ ├── LibUsbPrinterManager.cs # Direct USB via LibUSB
│ ├── NetworkPrinterManager.cs # Network printers
│ ├── EscPosCommandBuilder.cs # ESC/POS commands
│ └── PrintQueue.cs # Thread-safe queue
├── wwwroot/
│ └── index.html # Web interface
├── drivers/
│ └── install-winusb.ps1 # WinUSB driver installer
├── Program.cs # Entry point
├── appsettings.json # Configuration
├── install.ps1 # Windows service installer
├── install.sh # Linux service installer
└── OpenPrint.csproj # Project file
dotnet publish -c Release -r win-x64 --self-contained true -o ./publish/win-x64Result: ./publish/win-x64/OpenPrint.exe (~46 MB)
dotnet publish -c Release -r linux-x64 --self-contained true -o ./publish/linux-x64dotnet publish -c Release -o ./publish/portableMIT License