System Operations - iamhelitha/3xui-api-client GitHub Wiki

System Operations Guide

āœ… Status: Fully tested and working

This guide covers all system-level operations using the 3xui-api-client library. System operations include monitoring online clients and creating backups of your 3X-UI configuration.

Table of Contents

Overview

System operations provide essential monitoring and maintenance capabilities for your 3X-UI server:

  • Online Client Monitoring: Track currently connected clients in real-time
  • System Backups: Create backups of your entire 3X-UI configuration
  • Health Monitoring: Monitor system status and connectivity
  • Maintenance Operations: Perform routine system maintenance tasks

āš ļø Important: These operations affect the entire system and should be used with appropriate permissions and monitoring.

Get Online Clients

Monitor currently connected clients across all inbounds:

const ThreeXUI = require('3xui-api-client');

async function getOnlineClients() {
  try {
    console.log('šŸ‘„ Getting online clients...');
    
    const response = await client.getOnlineClients();
    
    if (response.success) {
      const onlineClients = response.obj;
      
      if (onlineClients && Array.isArray(onlineClients) && onlineClients.length > 0) {
        console.log(`šŸ“Š Found ${onlineClients.length} online clients:`);
        
        onlineClients.forEach((client, index) => {
          console.log(`\nšŸ”— Client ${index + 1}:`);
          console.log(`   Email: ${client.email}`);
          console.log(`   IP Address: ${client.ip}`);
          console.log(`   Connected Since: ${new Date(client.connectedAt)}`);
          console.log(`   Inbound ID: ${client.inboundId}`);
          console.log(`   Protocol: ${client.protocol}`);
          console.log(`   Location: ${client.location || 'Unknown'}`);
          console.log(`   Traffic: ↑${client.upload} ↓${client.download} bytes`);
        });
        
        // Group by inbound for summary
        const byInbound = onlineClients.reduce((acc, client) => {
          acc[client.inboundId] = (acc[client.inboundId] || 0) + 1;
          return acc;
        }, {});
        
        console.log('\nšŸ“‹ Summary by Inbound:');
        Object.entries(byInbound).forEach(([inboundId, count]) => {
          console.log(`   Inbound ${inboundId}: ${count} clients`);
        });
        
      } else {
        console.log('šŸ“Š No clients currently online');
      }
    } else {
      console.log('āŒ Failed to get online clients:', response.msg);
    }
    
    return response;
  } catch (error) {
    console.error('āŒ Error getting online clients:', error.message);
    throw error;
  }
}

// Usage example
const result = await getOnlineClients();

API Response Example (No Online Clients)

{
  "success": true,
  "msg": "",
  "obj": null
}

Note: The response shows "obj": null when no clients are currently online. When clients are connected, the response would contain an array of client connection details.

Expected Response Structure (When Clients Are Online)

{
  "success": true,
  "msg": "",
  "obj": [
    {
      "email": "user23c5n7",
      "ip": "192.168.1.100",
      "connectedAt": 1735265123000,
      "inboundId": 5,
      "protocol": "vless",
      "location": "US",
      "upload": 1024000,
      "download": 5120000
    }
  ]
}

Create System Backup

Create a complete backup of your 3X-UI configuration:

async function createBackup() {
  try {
    console.log('šŸ’¾ Creating system backup...');
    console.log('āš ļø This will create a backup of the current 3X-UI configuration');
    
    // Confirm before proceeding
    console.log('\nšŸ“‹ Backup will include:');
    console.log('   • All inbound configurations');
    console.log('   • Client settings and credentials');
    console.log('   • System settings');
    console.log('   • Database data');
    
    const response = await client.createBackup();
    
    if (response.success || response === "") {
      console.log('āœ… Backup created successfully');
      
      // The response might be empty string for successful backup
      if (typeof response === 'string' && response === "") {
        console.log('šŸ“ Backup file created on server');
        console.log('   Location: Check your 3X-UI backup directory');
        console.log('   Filename: Typically includes timestamp');
      }
      
      // Log backup creation
      const backupInfo = {
        created_at: new Date(),
        type: 'full_system_backup',
        status: 'completed',
        file_size: response.fileSize || 'unknown',
        backup_path: response.path || 'server_default'
      };
      
      console.log('šŸ“Š Backup Details:', backupInfo);
      
    } else {
      console.log('āŒ Backup creation failed:', response.msg || 'Unknown error');
    }
    
    return response;
  } catch (error) {
    console.error('āŒ Error creating backup:', error.message);
    throw error;
  }
}

// Usage with confirmation
async function confirmedBackup() {
  console.log('šŸ”„ Initiating system backup...');
  console.log('āš ļø This operation may take several minutes depending on your data size');
  
  try {
    const result = await createBackup();
    return result;
  } catch (error) {
    console.error('šŸ’„ Backup operation failed:', error.message);
    return { success: false, error: error.message };
  }
}

// Execute backup
const backupResult = await confirmedBackup();

API Response Example (Create Backup)

""

Note: The 3X-UI backup API returns an empty string ("") when the backup is created successfully. This is the expected behavior based on the actual test results.

Response Interpretation

  • Empty string (""): Backup created successfully
  • Object with success: false: Backup failed with error message
  • Error thrown: Network or authentication issue

Server-Side Implementation

Complete system operations management with database integration:

const ThreeXUI = require('3xui-api-client');

class SystemOperationsManager {
  constructor(serverUrl, username, password, database) {
    this.client = new ThreeXUI(serverUrl, username, password);
    this.db = database;
  }

  async ensureAuthenticated() {
    const session = await this.db.sessions.findOne({
      where: { 
        server_url: this.client.baseURL,
        expires_at: { $gt: new Date() }
      }
    });

    if (!session) {
      await this.client.login();
      await this.db.sessions.create({
        server_url: this.client.baseURL,
        session_cookie: this.client.cookie,
        created_at: new Date(),
        expires_at: new Date(Date.now() + 3600000)
      });
    } else {
      this.client.cookie = session.session_cookie;
      this.client.api.defaults.headers.Cookie = session.session_cookie;
    }
  }

  async monitorOnlineClients() {
    await this.ensureAuthenticated();
    
    try {
      const response = await this.client.getOnlineClients();
      
      if (response.success) {
        const onlineClients = response.obj || [];
        
        // Store current online status in database
        await this.db.online_snapshots.create({
          timestamp: new Date(),
          total_online: onlineClients.length,
          clients: onlineClients,
          server_url: this.client.baseURL
        });
        
        // Update client last_seen timestamps
        for (const client of onlineClients) {
          await this.db.clients.update(
            { email: client.email },
            {
              last_seen: new Date(),
              last_ip: client.ip,
              status: 'online'
            }
          );
        }
        
        // Mark offline clients
        const onlineEmails = onlineClients.map(c => c.email);
        await this.db.clients.updateMany(
          { 
            email: { $nin: onlineEmails },
            status: 'online'
          },
          { status: 'offline' }
        );
        
        return {
          success: true,
          online_count: onlineClients.length,
          clients: onlineClients
        };
      }
      
      return response;
    } catch (error) {
      console.error('āŒ Error monitoring online clients:', error.message);
      throw error;
    }
  }

  async createScheduledBackup(schedule = 'daily') {
    await this.ensureAuthenticated();
    
    try {
      console.log(`šŸ’¾ Creating ${schedule} backup...`);
      
      const backupStart = new Date();
      const response = await this.client.createBackup();
      const backupEnd = new Date();
      
      const isSuccess = response === "" || response.success !== false;
      
      // Log backup in database
      await this.db.backups.create({
        server_url: this.client.baseURL,
        backup_type: 'system_full',
        schedule_type: schedule,
        started_at: backupStart,
        completed_at: backupEnd,
        duration_ms: backupEnd - backupStart,
        status: isSuccess ? 'completed' : 'failed',
        response: response,
        automated: true
      });
      
      if (isSuccess) {
        console.log('āœ… Scheduled backup completed successfully');
        
        // Cleanup old backups if configured
        await this.cleanupOldBackups();
        
        return { success: true, created_at: backupStart };
      } else {
        console.log('āŒ Scheduled backup failed');
        return { success: false, error: response.msg || 'Unknown error' };
      }
      
    } catch (error) {
      // Log failed backup
      await this.db.backups.create({
        server_url: this.client.baseURL,
        backup_type: 'system_full',
        schedule_type: schedule,
        started_at: new Date(),
        status: 'failed',
        error: error.message,
        automated: true
      });
      
      throw error;
    }
  }

  async generateSystemReport() {
    await this.ensureAuthenticated();
    
    try {
      // Get online clients
      const onlineResponse = await this.client.getOnlineClients();
      const onlineClients = onlineResponse.success ? (onlineResponse.obj || []) : [];
      
      // Get all inbounds
      const inboundsResponse = await this.client.getInbounds();
      const inbounds = inboundsResponse.success ? inboundsResponse.obj : [];
      
      // Calculate statistics
      const report = {
        generated_at: new Date(),
        server_url: this.client.baseURL,
        system_status: {
          online_clients: onlineClients.length,
          total_inbounds: inbounds.length,
          active_inbounds: inbounds.filter(i => i.enable).length,
          total_clients: inbounds.reduce((sum, i) => sum + (i.clientStats?.length || 0), 0)
        },
        traffic_summary: {
          total_upload: inbounds.reduce((sum, i) => sum + i.up, 0),
          total_download: inbounds.reduce((sum, i) => sum + i.down, 0),
          total_traffic: inbounds.reduce((sum, i) => sum + i.total, 0)
        },
        inbound_details: inbounds.map(inbound => ({
          id: inbound.id,
          port: inbound.port,
          protocol: inbound.protocol,
          enabled: inbound.enable,
          client_count: inbound.clientStats?.length || 0,
          traffic: { up: inbound.up, down: inbound.down, total: inbound.total }
        })),
        online_clients: onlineClients
      };
      
      // Store report in database
      await this.db.system_reports.create(report);
      
      return report;
    } catch (error) {
      console.error('āŒ Error generating system report:', error.message);
      throw error;
    }
  }

  async healthCheck() {
    try {
      await this.ensureAuthenticated();
      
      const health = {
        timestamp: new Date(),
        server_url: this.client.baseURL,
        authentication: 'success',
        api_responsive: true,
        checks: {}
      };
      
      // Test online clients endpoint
      try {
        const onlineResponse = await this.client.getOnlineClients();
        health.checks.online_clients = onlineResponse.success ? 'pass' : 'fail';
      } catch (error) {
        health.checks.online_clients = 'error';
        health.api_responsive = false;
      }
      
      // Test inbounds endpoint
      try {
        const inboundsResponse = await this.client.getInbounds();
        health.checks.inbounds = inboundsResponse.success ? 'pass' : 'fail';
      } catch (error) {
        health.checks.inbounds = 'error';
        health.api_responsive = false;
      }
      
      // Test backup capability
      try {
        // We don't actually create a backup during health check
        health.checks.backup_ready = 'pass';
      } catch (error) {
        health.checks.backup_ready = 'error';
      }
      
      // Store health check result
      await this.db.health_checks.create(health);
      
      return health;
    } catch (error) {
      return {
        timestamp: new Date(),
        server_url: this.client.baseURL,
        authentication: 'failed',
        api_responsive: false,
        error: error.message
      };
    }
  }
}

module.exports = SystemOperationsManager;

Error Handling

Common errors and solutions:

Authentication Errors

try {
  const response = await client.getOnlineClients();
} catch (error) {
  if (error.message.includes('401')) {
    console.log('Session expired, re-authenticating...');
    await client.login();
    const response = await client.getOnlineClients();
  }
}

Network Connectivity Issues

async function robustSystemOperation(operation) {
  let retries = 3;
  
  while (retries > 0) {
    try {
      return await operation();
    } catch (error) {
      retries--;
      
      if (error.code === 'ECONNREFUSED' && retries > 0) {
        console.log(`šŸ”„ Connection failed, retrying... (${retries} attempts left)`);
        await new Promise(resolve => setTimeout(resolve, 5000));
      } else {
        throw error;
      }
    }
  }
}

// Usage
const result = await robustSystemOperation(() => client.getOnlineClients());

Backup Failures

async function safeBackup() {
  try {
    const response = await client.createBackup();
    
    // Handle empty string response (success)
    if (response === "") {
      return { success: true, message: 'Backup created successfully' };
    }
    
    // Handle object response
    if (typeof response === 'object' && response.success === false) {
      throw new Error(response.msg || 'Backup failed');
    }
    
    return { success: true, response: response };
  } catch (error) {
    console.error('āŒ Backup failed:', error.message);
    
    // Attempt to diagnose the issue
    if (error.message.includes('space')) {
      console.log('šŸ’” Suggestion: Check available disk space on server');
    } else if (error.message.includes('permission')) {
      console.log('šŸ’” Suggestion: Check backup directory permissions');
    }
    
    return { success: false, error: error.message };
  }
}

Best Practices

1. Regular Monitoring

const cron = require('node-cron');

// Monitor online clients every 5 minutes
cron.schedule('*/5 * * * *', async () => {
  try {
    const onlineClients = await systemManager.monitorOnlineClients();
    
    // Check for unusual patterns
    if (onlineClients.online_count === 0) {
      console.log('āš ļø No clients online - check server status');
    } else if (onlineClients.online_count > 100) {
      console.log('šŸ“Š High client count detected:', onlineClients.online_count);
    }
  } catch (error) {
    console.error('āŒ Monitoring failed:', error.message);
  }
});

2. Automated Backups

// Daily backup at 2 AM
cron.schedule('0 2 * * *', async () => {
  console.log('šŸ’¾ Starting daily backup...');
  
  try {
    const result = await systemManager.createScheduledBackup('daily');
    
    if (result.success) {
      console.log('āœ… Daily backup completed');
      
      // Send success notification
      await sendAdminNotification('Daily backup completed successfully');
    } else {
      throw new Error(result.error);
    }
  } catch (error) {
    console.error('āŒ Daily backup failed:', error.message);
    await sendAdminAlert('Daily backup failed', error.message);
  }
});

// Weekly backup with retention
cron.schedule('0 1 * * 0', async () => {
  await systemManager.createScheduledBackup('weekly');
  await systemManager.cleanupOldBackups();
});

3. Health Monitoring

// Health check every hour
cron.schedule('0 * * * *', async () => {
  const health = await systemManager.healthCheck();
  
  if (!health.api_responsive) {
    await sendCriticalAlert('3X-UI API not responding', health);
  }
  
  // Check specific service health
  Object.entries(health.checks).forEach(([service, status]) => {
    if (status === 'error' || status === 'fail') {
      console.log(`āš ļø Service ${service} is ${status}`);
    }
  });
});

4. Performance Monitoring

async function performanceMonitoring() {
  const startTime = Date.now();
  
  try {
    // Test response times
    const onlineStart = Date.now();
    await client.getOnlineClients();
    const onlineTime = Date.now() - onlineStart;
    
    const inboundsStart = Date.now();
    await client.getInbounds();
    const inboundsTime = Date.now() - inboundsStart;
    
    const metrics = {
      timestamp: new Date(),
      response_times: {
        online_clients: onlineTime,
        get_inbounds: inboundsTime
      },
      total_time: Date.now() - startTime
    };
    
    // Alert if response times are slow
    if (onlineTime > 5000 || inboundsTime > 5000) {
      console.log('āš ļø Slow API response detected:', metrics);
    }
    
    await database.performance_metrics.create(metrics);
    
  } catch (error) {
    console.error('āŒ Performance monitoring failed:', error.message);
  }
}

// Run performance monitoring every 15 minutes
setInterval(performanceMonitoring, 900000);

Use Cases

Real-Time Dashboard

class RealTimeDashboard {
  constructor(systemManager) {
    this.systemManager = systemManager;
    this.subscribers = [];
  }

  async startMonitoring(interval = 30000) {
    setInterval(async () => {
      try {
        const data = await this.gatherDashboardData();
        this.broadcastUpdate(data);
      } catch (error) {
        console.error('āŒ Dashboard update failed:', error.message);
      }
    }, interval);
  }

  async gatherDashboardData() {
    const [onlineClients, systemReport] = await Promise.all([
      this.systemManager.monitorOnlineClients(),
      this.systemManager.generateSystemReport()
    ]);

    return {
      timestamp: new Date(),
      online_clients: onlineClients.online_count,
      total_traffic: systemReport.traffic_summary.total_traffic,
      active_inbounds: systemReport.system_status.active_inbounds,
      system_health: await this.systemManager.healthCheck()
    };
  }

  broadcastUpdate(data) {
    this.subscribers.forEach(callback => {
      try {
        callback(data);
      } catch (error) {
        console.error('āŒ Dashboard subscriber error:', error.message);
      }
    });
  }

  subscribe(callback) {
    this.subscribers.push(callback);
  }
}

// Usage
const dashboard = new RealTimeDashboard(systemManager);
dashboard.subscribe((data) => {
  console.log('šŸ“Š Dashboard Update:', data);
  // Update web interface, send to monitoring service, etc.
});
dashboard.startMonitoring();

Automated Maintenance System

class MaintenanceSystem {
  constructor(systemManager) {
    this.systemManager = systemManager;
  }

  scheduleMaintenanceTasks() {
    // Hourly online client monitoring
    cron.schedule('0 * * * *', () => {
      this.performTask('online_monitoring');
    });

    // Daily backup
    cron.schedule('0 2 * * *', () => {
      this.performTask('daily_backup');
    });

    // Weekly system report
    cron.schedule('0 0 * * 0', () => {
      this.performTask('weekly_report');
    });

    // Monthly cleanup
    cron.schedule('0 1 1 * *', () => {
      this.performTask('monthly_cleanup');
    });
  }

  async performTask(taskType) {
    console.log(`šŸ”§ Starting ${taskType}...`);
    
    try {
      switch (taskType) {
        case 'online_monitoring':
          await this.monitorAndAlert();
          break;
        case 'daily_backup':
          await this.createDailyBackup();
          break;
        case 'weekly_report':
          await this.generateWeeklyReport();
          break;
        case 'monthly_cleanup':
          await this.performMonthlyCleanup();
          break;
      }
      
      console.log(`āœ… ${taskType} completed`);
    } catch (error) {
      console.error(`āŒ ${taskType} failed:`, error.message);
      await this.sendMaintenanceAlert(taskType, error);
    }
  }

  async monitorAndAlert() {
    const onlineClients = await this.systemManager.monitorOnlineClients();
    const health = await this.systemManager.healthCheck();

    // Check for issues
    if (!health.api_responsive) {
      await this.sendCriticalAlert('API not responsive', health);
    }

    if (onlineClients.online_count === 0) {
      await this.sendWarningAlert('No clients online', onlineClients);
    }
  }

  async createDailyBackup() {
    const result = await this.systemManager.createScheduledBackup('daily');
    
    if (!result.success) {
      throw new Error(result.error);
    }
    
    await this.sendNotification('Daily backup completed successfully');
  }

  async generateWeeklyReport() {
    const report = await this.systemManager.generateSystemReport();
    
    // Send weekly summary to administrators
    await this.sendWeeklyReport(report);
  }

  async performMonthlyCleanup() {
    await this.systemManager.cleanupOldBackups();
    
    // Additional cleanup tasks
    await this.cleanupOldLogs();
    await this.optimizeDatabase();
  }
}

High-Availability Monitoring

class HAMonitoring {
  constructor(primarySystem, backupSystems = []) {
    this.primary = primarySystem;
    this.backups = backupSystems;
    this.currentActive = this.primary;
  }

  async startHAMonitoring() {
    setInterval(async () => {
      await this.checkSystemHealth();
    }, 60000); // Check every minute
  }

  async checkSystemHealth() {
    try {
      const health = await this.currentActive.healthCheck();
      
      if (!health.api_responsive) {
        console.log('āš ļø Primary system unresponsive, attempting failover...');
        await this.attemptFailover();
      } else {
        console.log('āœ… Primary system healthy');
      }
    } catch (error) {
      console.error('āŒ Health check failed:', error.message);
      await this.attemptFailover();
    }
  }

  async attemptFailover() {
    for (const backup of this.backups) {
      try {
        const health = await backup.healthCheck();
        
        if (health.api_responsive) {
          console.log('āœ… Failing over to backup system');
          this.currentActive = backup;
          await this.sendFailoverAlert();
          return;
        }
      } catch (error) {
        console.log('āŒ Backup system also unavailable');
      }
    }
    
    await this.sendCriticalAlert('All systems unavailable');
  }

  async sendFailoverAlert() {
    const alert = {
      type: 'failover',
      timestamp: new Date(),
      message: 'System failover completed',
      active_system: this.currentActive.client.baseURL
    };
    
    // Send to monitoring service, email, SMS, etc.
    console.log('🚨 FAILOVER ALERT:', alert);
  }
}

Navigation

Previous Next
← Traffic Management Home →

Related Documentation

Last updated: January 2025