Skip to main content
This guide covers deploying the multi-device server (server.py), which provides a complete REST API for managing multiple ZKTeco biometric devices dynamically through API endpoints.

Overview

The multi-device server is designed for:
  • Organizations with multiple biometric devices across different locations
  • Dynamic device management via REST API
  • Centralized attendance tracking from all devices
  • Automatic persistence of device configurations
Devices are registered, updated, and removed via API calls, with all configurations automatically saved to devices.json.

Key Features

  • Dynamic Device Management: Add/edit/remove devices via API without restarting
  • Persistent Storage: Device configurations saved automatically to disk
  • Parallel Data Retrieval: Query all devices simultaneously for faster responses
  • Thread-Safe Operations: Concurrent request handling with device-level locking
  • Default Device Support: Optional pre-configured devices on first startup

Prerequisites

1

Install Dependencies

Install the required Python packages:
pip install flask pyopenssl pyzk
2

Network Configuration

Ensure:
  • Server can reach all ZKTeco devices on the network
  • Devices are accessible via their IP addresses
  • No firewall blocking port 4370 (default ZKTeco port)

Environment Variables

Configure the server before starting:
export API_HOST="0.0.0.0"
export API_PORT="5000"
export CERT_FILE="cert.pem"
export KEY_FILE="key.pem"
export DEVICES_FILE="devices.json"
VariableDefaultDescription
API_HOST0.0.0.0Server listening interface
API_PORT5000Server port
CERT_FILEcert.pemSSL certificate file path
KEY_FILEkey.pemSSL private key file path
DEVICES_FILEdevices.jsonDevice registry persistence file

Starting the Server

On first run, the server creates a default device configuration:
python server.py
Default device created:
{
  "principal": {
    "ip": "192.168.1.205",
    "port": 4370,
    "password": 0,
    "timeout": 5,
    "name": "Entrada Principal",
    "created_at": "2026-03-06 10:30:00"
  }
}
This device serves as an example and can be deleted or modified via the API.

Device Management

Registering Devices

Add devices dynamically via the API:
1

Register First Device

curl -X POST http://localhost:5000/devices \
  -H "Content-Type: application/json" \
  -d '{
    "id": "entrance",
    "name": "Main Entrance",
    "ip": "192.168.1.205",
    "port": 4370,
    "password": 0,
    "timeout": 5
  }'
Response:
{
  "success": true,
  "message": "Dispositivo 'entrance' registrado.",
  "data": {
    "ip": "192.168.1.205",
    "port": 4370,
    "password": 0,
    "timeout": 5,
    "name": "Main Entrance",
    "created_at": "2026-03-06 10:35:00"
  }
}
2

Add More Devices

# Warehouse device
curl -X POST http://localhost:5000/devices \
  -H "Content-Type: application/json" \
  -d '{
    "id": "warehouse",
    "name": "Warehouse Door",
    "ip": "192.168.1.206"
  }'

# Office device
curl -X POST http://localhost:5000/devices \
  -H "Content-Type: application/json" \
  -d '{
    "id": "office",
    "name": "Office Floor 2",
    "ip": "192.168.1.207"
  }'
Port, password, and timeout use defaults (4370, 0, 5) if not specified.
3

Verify Registration

List all devices:
curl http://localhost:5000/devices
Response:
{
  "success": true,
  "total": 3,
  "data": [
    {
      "id": "entrance",
      "name": "Main Entrance",
      "ip": "192.168.1.205",
      "port": 4370,
      "created_at": "2026-03-06 10:35:00"
    },
    {
      "id": "warehouse",
      "name": "Warehouse Door",
      "ip": "192.168.1.206",
      "port": 4370,
      "created_at": "2026-03-06 10:36:00"
    },
    {
      "id": "office",
      "name": "Office Floor 2",
      "ip": "192.168.1.207",
      "port": 4370,
      "created_at": "2026-03-06 10:37:00"
    }
  ]
}

Testing Device Connectivity

Verify each device is reachable:
curl http://localhost:5000/devices/entrance/ping
Success Response:
{
  "success": true,
  "message": "Conexion exitosa con 'entrance'.",
  "device_time": "2026-03-06 10:40:15",
  "ip": "192.168.1.205"
}
Failure Response:
{
  "success": false,
  "error": "Connection timeout",
  "ip": "192.168.1.205"
}

Updating Device Configuration

Modify device settings without removing and re-adding:
curl -X PUT http://localhost:5000/devices/entrance \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Main Entrance - Updated",
    "ip": "192.168.1.210",
    "timeout": 10
  }'
All fields are optional. Only provided fields will be updated. The changes are immediately persisted to devices.json.

Removing Devices

curl -X DELETE http://localhost:5000/devices/entrance
The device is removed from memory and devices.json is updated automatically.

Devices.json Persistence

The server automatically manages the devices.json file:

File Structure

{
  "entrance": {
    "ip": "192.168.1.205",
    "port": 4370,
    "password": 0,
    "timeout": 5,
    "name": "Main Entrance",
    "created_at": "2026-03-06 10:35:00",
    "updated_at": "2026-03-06 14:20:00"
  },
  "warehouse": {
    "ip": "192.168.1.206",
    "port": 4370,
    "password": 0,
    "timeout": 5,
    "name": "Warehouse Door",
    "created_at": "2026-03-06 10:36:00"
  }
}

Persistence Behavior

The file is updated automatically on:
  • Device registration (POST /devices)
  • Device update (PUT /devices/{id})
  • Device deletion (DELETE /devices/{id})
On server start:
  1. If devices.json exists → Load all devices from file
  2. If file doesn’t exist → Create with default device example
This ensures devices persist across server restarts.
You can manually edit devices.json while the server is stopped. On next startup, the server will load your changes.After editing:
sudo systemctl restart zkteco-multi
Backup your device configuration:
cp devices.json devices.backup.json
Migrate to a new server:
scp devices.json user@new-server:/opt/zkteco/devices.json

Centralized Attendance Retrieval

Query attendance from all devices simultaneously:

All Devices at Once

curl http://localhost:5000/attendance/all
Response:
{
  "success": true,
  "total": 1247,
  "errors": {},
  "data": [
    {
      "user_id": "123",
      "timestamp": "2026-03-06 08:30:15",
      "status": 1,
      "punch": 0,
      "device_id": "entrance",
      "device_name": "Main Entrance"
    },
    {
      "user_id": "456",
      "timestamp": "2026-03-06 08:31:20",
      "status": 1,
      "punch": 0,
      "device_id": "warehouse",
      "device_name": "Warehouse Door"
    }
  ]
}
Data is retrieved in parallel from all devices using threading. If a device fails, its error is reported in the errors object, but successful devices still return data.

Filtering Across All Devices

curl "http://localhost:5000/attendance/all?user_id=123"

Single Device Attendance

curl http://localhost:5000/devices/entrance/attendance

# With filters
curl "http://localhost:5000/devices/entrance/attendance?user_id=123"

Per-Device Operations

All device operations use the pattern /devices/{device_id}/{operation}:

Device Information

curl http://localhost:5000/devices/entrance/info
Response:
{
  "success": true,
  "data": {
    "id": "entrance",
    "name": "Main Entrance",
    "ip": "192.168.1.205",
    "serialnumber": "BNVR123456789",
    "device_name": "ZKTeco Device",
    "platform": "ZEM560",
    "firmware_version": "Ver 6.60",
    "users_count": 42,
    "device_time": "2026-03-06 10:45:30"
  }
}

User Management

curl http://localhost:5000/devices/entrance/users
curl -X POST http://localhost:5000/devices/entrance/users \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "123",
    "name": "John Doe",
    "privilege": 0
  }'
curl -X PUT http://localhost:5000/devices/entrance/users/123 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe Updated"
  }'
curl -X DELETE http://localhost:5000/devices/entrance/users/123

Fingerprint Management

curl -X POST http://localhost:5000/devices/entrance/users/123/enroll-finger \
  -H "Content-Type: application/json" \
  -d '{"finger_index": 0}'

Time Synchronization

curl http://localhost:5000/devices/entrance/time

Multi-Device Deployment Patterns

Distributed Locations

# Head office devices
curl -X POST http://localhost:5000/devices -d '{
  "id": "hq_entrance", "name": "HQ Main Entrance", "ip": "192.168.1.10"
}'

curl -X POST http://localhost:5000/devices -d '{
  "id": "hq_cafeteria", "name": "HQ Cafeteria", "ip": "192.168.1.11"
}'

# Branch office devices (different subnet via VPN)
curl -X POST http://localhost:5000/devices -d '{
  "id": "branch_entrance", "name": "Branch Office Entrance", "ip": "10.10.1.20"
}'

curl -X POST http://localhost:5000/devices -d '{
  "id": "branch_warehouse", "name": "Branch Warehouse", "ip": "10.10.1.21"
}'

High Availability Setup

1

Backup devices.json Regularly

# Cron job to backup daily
0 2 * * * cp /var/lib/zkteco/devices.json /backup/devices_$(date +\%Y\%m\%d).json
2

Use Load Balancer

Deploy multiple server instances behind a load balancer, sharing the same devices.json via NFS or syncing mechanism.
3

Monitor Device Health

Create a monitoring script:
#!/bin/bash
for device in entrance warehouse office; do
  response=$(curl -s http://localhost:5000/devices/$device/ping)
  if echo "$response" | grep -q '"success":true'; then
    echo "$device: OK"
  else
    echo "$device: FAILED" | mail -s "Device Alert" [email protected]
  fi
done

Thread Safety and Concurrency

The server implements device-level locking:
# Each device has its own lock
with get_lock(device_id):
    # Only one request can access this device at a time
    conn = conectar(device_id)
    # ... perform operations
Benefits:
  • Multiple devices can be queried simultaneously
  • Prevents device conflicts and corruption
  • Single device requests are serialized automatically
Example: If 3 requests arrive:
  1. Request A to device “entrance” - starts immediately
  2. Request B to device “warehouse” - starts immediately (different device)
  3. Request C to device “entrance” - waits for Request A to finish

Troubleshooting

Error: Dispositivo 'xxx' no encontradoSolutions:
  • List devices: curl http://localhost:5000/devices
  • Verify device ID matches exactly (case-sensitive)
  • Check if device was deleted
Error: El id 'xxx' ya existeSolutions:
  • Use a different unique identifier
  • Update the existing device instead (PUT /devices/{id})
  • Delete the old device first if replacing it
Error: Permission denied when writing devices.jsonSolutions:
# Fix ownership
sudo chown www-data:www-data /var/lib/zkteco/devices.json

# Fix permissions
sudo chmod 644 /var/lib/zkteco/devices.json
Some devices succeed, others fail in the errors object.Solutions:
  • Check device connectivity individually with /devices/{id}/ping
  • Review device-specific error messages in response
  • Verify network routes to failed devices
  • Check if failed devices are powered on
Error: JSON parsing error on startupSolutions:
# Validate JSON syntax
python3 -m json.tool devices.json

# Restore from backup
cp devices.backup.json devices.json

# Or delete and restart with defaults
rm devices.json
sudo systemctl restart zkteco-multi

Performance Optimization

Large Deployments (10+ Devices)

Increase Timeout

For slow networks or distant devices:
{
  "timeout": 15
}

Use Filtering

Reduce data transfer with date/user filters:
?date=2026-03-06&user_id=123

Monitor Resource Usage

Each device query spawns a thread. Monitor with:
htop -p $(pgrep -f server.py)

Implement Caching

For frequently accessed data, implement Redis or memcached caching layer

Migration from Single to Multi-Device

Upgrading from servidor.py to server.py:
1

Stop Single-Device Server

sudo systemctl stop zkteco-single
2

Register Your Device

# Start multi-device server
python server.py

# Register your existing device
curl -X POST http://localhost:5000/devices \
  -H "Content-Type: application/json" \
  -d '{
    "id": "main_device",
    "name": "Main Device",
    "ip": "192.168.1.205",
    "port": 4370
  }'
3

Update Client Applications

Change endpoint URLs:
  • Old: http://server:5000/attendance
  • New: http://server:5000/devices/main_device/attendance
Or use: http://server:5000/attendance/all to query all devices

Next Steps

SSL Configuration

Secure your multi-device deployment with HTTPS

Environment Variables

Complete configuration reference

API Reference

Full endpoint documentation

Device Management API

Detailed device CRUD operations

Build docs developers (and LLMs) love