Web API
PMDaemon provides a comprehensive REST API and real-time WebSocket interface for remote process management and monitoring. Built on the high-performance Axum web framework, it offers PM2-compatible endpoints with additional advanced features.
Overview
The Web API provides:
- 🌐 REST API - Full process management via HTTP
- ⚡ WebSocket support - Real-time updates and monitoring
- 🔒 Security features - CORS support and security headers
- 📊 System metrics - CPU, memory, load average monitoring
- 📝 Log access - Retrieve and stream process logs
- 🔄 PM2 compatibility - Compatible JSON response format
Starting the Web Server
Basic Usage
# Start on default port (9615) without authentication
pmdaemon web
# With API key authentication (recommended for production)
pmdaemon web --api-key "your-secret-api-key"
# Custom port and host with authentication
pmdaemon web --port 8080 --host 0.0.0.0 --api-key "$API_KEY"
Configuration Options
Option | Default | Description |
---|---|---|
--port | 9615 | Port to bind the web server |
--host | 127.0.0.1 | Host address to bind |
--api-key | None | API key for authentication (optional) |
Security Considerations
# Local development (no authentication needed)
pmdaemon web --host 127.0.0.1
# Production with authentication (recommended)
pmdaemon web --host 127.0.0.1 --api-key "$API_KEY"
# Behind reverse proxy with SSL
pmdaemon web --host 127.0.0.1 --api-key "$API_KEY"
# Use nginx/Apache as reverse proxy with HTTPS
# Environment variable for API key
export PMDAEMON_API_KEY="your-secret-key"
pmdaemon web --host 0.0.0.0
REST API Endpoints
Process Management
List All Processes
GET /api/processes
Response:
{
"processes": [
{
"id": 0,
"name": "web-api",
"status": "online",
"pid": 1234,
"port": 3000,
"cpu": 2.5,
"memory": 47185920,
"uptime": 7890000,
"restarts": 0,
"health": "healthy"
}
],
"total": 1
}
Get Process Details
GET /api/processes/{name_or_id}
Example:
curl http://localhost:9615/api/processes/web-api
Response:
{
"id": 0,
"name": "web-api",
"status": "online",
"pid": 1234,
"port": 3000,
"cpu": 2.5,
"memory": 47185920,
"uptime": 7890000,
"restarts": 0,
"health": "healthy",
"config": {
"script": "node",
"args": ["server.js"],
"cwd": "/app",
"env": {
"NODE_ENV": "production",
"PORT": "3000"
}
}
}
Start a Process
POST /api/processes
Request Body:
{
"name": "new-api",
"script": "node",
"args": ["app.js"],
"port": "3001",
"instances": 1,
"env": {
"NODE_ENV": "production"
}
}
Response:
{
"success": true,
"message": "Process 'new-api' started successfully",
"process": {
"id": 1,
"name": "new-api",
"status": "starting",
"pid": null,
"port": 3001
}
}
Stop a Process
DELETE /api/processes/{name_or_id}
Example:
curl -X DELETE http://localhost:9615/api/processes/web-api
Response:
{
"success": true,
"message": "Process 'web-api' stopped successfully"
}
Restart a Process
POST /api/processes/{name_or_id}/restart
Optional Request Body:
{
"port": "3002",
"instances": 2
}
Response:
{
"success": true,
"message": "Process 'web-api' restarted successfully"
}
System Information
Get System Metrics
GET /api/system
Response:
{
"cpu": {
"usage": 15.2,
"cores": 8
},
"memory": {
"total": 8589934592,
"used": 2147483648,
"available": 6442450944,
"usage_percent": 25.0
},
"load": {
"one": 0.85,
"five": 1.2,
"fifteen": 0.9
},
"uptime": 432000,
"timestamp": "2024-01-15T14:30:25Z"
}
Log Management
Get Process Logs
GET /api/logs/{name_or_id}
Query Parameters:
lines
- Number of lines to retrieve (default: 20)type
- Log type:stdout
,stderr
, orall
(default: all)
Example:
curl "http://localhost:9615/api/logs/web-api?lines=50&type=stdout"
Response:
{
"logs": [
{
"timestamp": "2024-01-15T14:30:25Z",
"type": "stdout",
"message": "Server started on port 3000"
},
{
"timestamp": "2024-01-15T14:30:26Z",
"type": "stdout",
"message": "Database connected successfully"
}
],
"total_lines": 50,
"process": "web-api"
}
Health Checks
Get Process Health Status
GET /api/processes/{name_or_id}/health
Response:
{
"process": "web-api",
"health": {
"status": "healthy",
"last_check": "2024-01-15T14:30:25Z",
"check_type": "http",
"url": "http://localhost:3000/health",
"success_rate": 98.5,
"total_checks": 200,
"successful_checks": 197
}
}
WebSocket API
Connection
Connect to the WebSocket endpoint for real-time updates:
const ws = new WebSocket('ws://localhost:9615/ws');
ws.onopen = function() {
console.log('Connected to PMDaemon WebSocket');
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('Received update:', data);
};
Message Types
Process Status Updates
{
"type": "process_update",
"data": {
"id": 0,
"name": "web-api",
"status": "online",
"pid": 1234,
"cpu": 2.5,
"memory": 47185920,
"timestamp": "2024-01-15T14:30:25Z"
}
}
System Metrics Updates
{
"type": "system_update",
"data": {
"cpu": 15.2,
"memory": {
"usage_percent": 25.0,
"used": 2147483648
},
"load": {
"one": 0.85
},
"timestamp": "2024-01-15T14:30:25Z"
}
}
Health Check Updates
{
"type": "health_update",
"data": {
"process": "web-api",
"status": "healthy",
"timestamp": "2024-01-15T14:30:25Z"
}
}
Process Events
{
"type": "process_event",
"data": {
"event": "started",
"process": "new-api",
"timestamp": "2024-01-15T14:30:25Z"
}
}
Client Examples
JavaScript/Node.js
// REST API client
const axios = require('axios');
class PMDaemonClient {
constructor(baseURL = 'http://localhost:9615') {
this.api = axios.create({ baseURL });
}
async listProcesses() {
const response = await this.api.get('/api/processes');
return response.data;
}
async startProcess(config) {
const response = await this.api.post('/api/processes', config);
return response.data;
}
async stopProcess(nameOrId) {
const response = await this.api.delete(`/api/processes/${nameOrId}`);
return response.data;
}
async getSystemMetrics() {
const response = await this.api.get('/api/system');
return response.data;
}
}
// Usage
const client = new PMDaemonClient();
const processes = await client.listProcesses();
console.log(processes);
Python
import requests
import websocket
import json
class PMDaemonClient:
def __init__(self, base_url='http://localhost:9615'):
self.base_url = base_url
def list_processes(self):
response = requests.get(f'{self.base_url}/api/processes')
return response.json()
def start_process(self, config):
response = requests.post(f'{self.base_url}/api/processes', json=config)
return response.json()
def stop_process(self, name_or_id):
response = requests.delete(f'{self.base_url}/api/processes/{name_or_id}')
return response.json()
def get_system_metrics(self):
response = requests.get(f'{self.base_url}/api/system')
return response.json()
# WebSocket client
def on_message(ws, message):
data = json.loads(message)
print(f"Received: {data}")
def on_error(ws, error):
print(f"Error: {error}")
def on_close(ws, close_status_code, close_msg):
print("Connection closed")
# Connect to WebSocket
ws = websocket.WebSocketApp("ws://localhost:9615/ws",
on_message=on_message,
on_error=on_error,
on_close=on_close)
ws.run_forever()
cURL Examples
# List all processes
curl http://localhost:9615/api/processes
# Start a new process
curl -X POST http://localhost:9615/api/processes \
-H "Content-Type: application/json" \
-d '{
"name": "test-api",
"script": "node",
"args": ["server.js"],
"port": "3000"
}'
# Get system metrics
curl http://localhost:9615/api/system
# Get process logs
curl "http://localhost:9615/api/logs/test-api?lines=100"
# Stop a process
curl -X DELETE http://localhost:9615/api/processes/test-api
Error Handling
HTTP Status Codes
Code | Meaning | Description |
---|---|---|
200 | OK | Request successful |
201 | Created | Process created successfully |
400 | Bad Request | Invalid request parameters |
404 | Not Found | Process not found |
409 | Conflict | Process name already exists |
500 | Internal Server Error | Server error |
Error Response Format
{
"success": false,
"error": {
"code": "PROCESS_NOT_FOUND",
"message": "Process 'nonexistent' not found",
"details": {
"requested_process": "nonexistent",
"available_processes": ["web-api", "worker"]
}
}
}
Security Features
CORS Support
PMDaemon includes built-in CORS support for web applications:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Security Headers
Standard security headers are included:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Authentication (Future)
Authentication features planned for future releases:
- API key authentication
- JWT token support
- Role-based access control
Performance
Benchmarks
The Axum-based web server provides excellent performance:
- Concurrent connections: 10,000+
- Request throughput: 50,000+ req/s
- Memory usage: Low overhead
- WebSocket connections: 1,000+ concurrent
Optimization Tips
-
Use WebSocket for real-time data:
// Efficient for live updates
const ws = new WebSocket('ws://localhost:9615/ws'); -
Batch API requests:
// Get all data in one request
const [processes, system] = await Promise.all([
client.listProcesses(),
client.getSystemMetrics()
]); -
Limit log retrieval:
# Don't retrieve too many log lines
curl "http://localhost:9615/api/logs/app?lines=100"
Next Steps
- WebSocket API - Detailed WebSocket documentation
- API Examples - More client examples
- Security - Security best practices
- Integration Examples - Framework integration