Initializing
Back to Projects
Year2025
DomainDevOps
AccessOpen Source
Complexity8.7 / 10
Live Link
Node.jsExpressTypeScriptNext.jsSQLiteRcloneWebSocketshadcn/uiDockerCronMulti-Tenancy
DevOpsProduction

Aatmanova Cloud Manager — Enterprise Rclone GUI

Production-grade web interface for Rclone with multi-host management, file browser, mount management, job scheduling, real-time WebSocket monitoring, and enterprise security features.

Supported Cloud Providers0+
API Endpoints0+
User Roles0
Real-Time Metrics0

Table of Contents


The Challenge

Rclone is a powerful command-line tool for managing cloud storage across 50+ providers, but its CLI-only interface presents significant barriers for teams and enterprises. Non-technical users struggle with complex syntax, multiple servers require separate SSH connections, and monitoring ongoing transfers requires constant terminal attention.

The fundamental challenge was creating a user-friendly web interface that could wrap Rclone's functionality while adding enterprise-grade features like multi-host management, scheduled jobs, real-time monitoring, and proper access controls — all without compromising the security of the underlying Rclone RC API.

The requirement: Build a production-grade web interface that provides secure, authenticated access to Rclone across multiple hosts, enables visual file management with dry-run safety, supports cron-based job scheduling, offers real-time transfer monitoring via WebSockets, and implements proper audit logging for compliance.


Architecture & Solution

The system follows a proxy architecture where a secure Node.js layer sits between users and the Rclone RC API:

Parsing system architecture diagram...

Project Structure

code
rclone-manager/
├── backend/
│   ├── src/
│   │   ├── services/     # Core logic (Rclone, Auth, Audit, Scheduler)
│   │   ├── routes/       # API endpoints
│   │   ├── middleware/  # Security & validation
│   │   └── types/        # TypeScript definitions
│   └── tests/           # Jest unit tests
├── frontend-next/       # Next.js 14 web client
│   ├── app/             # Pages
│   ├── components/      # UI components
│   └── hooks/           # Custom hooks
├── docker-compose.yml
└── Dockerfile.prod

Tech Stack

LayerTechnologyVersion
FrontendNext.js14.x
UI Libraryshadcn/uilatest
StylingTailwind CSS4.x
BackendExpress4.x
RuntimeNode.js20.x
LanguageTypeScript5.x
DatabaseSQLite3.x
ORMbetter-sqlite312.x
Core EngineRclone1.65+
WebSocketws8.x
Securityhelmet, bcrypt7.x/6.x
Schedulingcron-parser5.x
ContainerDockerlatest

Key Engineering Decisions

1. Secure Rclone RC Proxy Layer

The backend acts as a secure proxy, ensuring no direct exposure of the Rclone RC port:

typescript
// backend/src/services/rclone.service.ts
export class RcloneService {
  private async forwardRequest(hostId: string, endpoint: string, body?: any) {
    const host = await this.getHostConfig(hostId);
    
    // Validate host is accessible
    const health = await this.checkHostHealth(host);
    if (!health.online) {
      throw new Error(`Host ${host.name} is offline`);
    }
    
    // Forward request to specific host's Rclone RC
    const response = await axios.post(
      `${host.rcUrl}/ ${endpoint}`,
      body,
      {
        auth: {
          username: host.rcUser,
          password: host.rcPass,
        },
        timeout: 30000,
      }
    );
    
    return response.data;
  }
  
  async listRemotes(hostId: string) {
    return this.forwardRequest(hostId, '/config/listremotes');
  }
  
  async copyFile(hostId: string, srcRemote: string, dstRemote: string, srcPath: string, dstPath: string) {
    return this.forwardRequest(hostId, '/operations/copyfile', {
      srcFs: `${srcRemote}:${srcPath}`,
      dstFs: `${dstRemote}:${dstPath}`,
    });
  }
}

2. Session-Based Authentication with Role-Based Access

typescript
// backend/src/middleware/auth.middleware.ts
export function authenticate(req: Request, res: Response, next: NextFunction) {
  if (!req.session.userId) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  
  const user = userService.getById(req.session.userId);
  if (!user || !user.isActive) {
    return res.status(401).json({ error: 'User not found or inactive' });
  }
  
  req.user = user;
  next();
}

export function authorize(...roles: string[]) {
  return (req: Request, res: Response, next: NextFunction) => {
    if (!roles.includes(req.user.role)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

// Usage
router.get('/hosts', authenticate, authorize('ADMIN'), listHosts);
router.get('/files', authenticate, listFiles); // Any authenticated user

3. Real-Time Transfer Monitoring with WebSockets

typescript
// backend/src/services/stats.service.ts
export class StatsService {
  private wsClients: Set<WebSocket> = new Set();
  
  constructor() {
    // Poll Rclone stats every second
    setInterval(async () => {
      const stats = await this.gatherStats();
      this.broadcast(stats);
    }, 1000);
  }
  
  private async gatherStats() {
    const activeJobs = await rcloneService.getJobs();
    const transfers = await rcloneService.getTransferStats();
    const system = await this.getSystemResources();
    
    return {
      jobs: activeJobs,
      transfers: transfers,
      cpu: system.cpu,
      memory: system.memory,
      bandwidth: system.bandwidth,
    };
  }
  
  private broadcast(data: any) {
    this.wsClients.forEach(client => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify(data));
      }
    });
  }
}

4. Cron-Based Job Scheduling

typescript
// backend/src/services/scheduler.service.ts
export class SchedulerService {
  async createSchedule(scheduleData: CreateScheduleDto) {
    // Validate cron expression
    const cron = cronParser.parseExpression(scheduleData.cronExpression);
    const nextRun = cron.next().toDate();
    
    const schedule = await db.schedules.create({
      data: {
        name: scheduleData.name,
        hostId: scheduleData.hostId,
        command: scheduleData.command,
        sourceRemote: scheduleData.sourceRemote,
        destinationRemote: scheduleData.destinationRemote,
        cronExpression: scheduleData.cronExpression,
        nextRunAt: nextRun,
        isActive: true,
      },
    });
    
    // Schedule the job
    this.scheduleJob(schedule);
    
    return schedule;
  }
  
  private scheduleJob(schedule: Schedule) {
    const job = cron.schedule(schedule.cronExpression, async () => {
      await this.executeJob(schedule);
      
      // Update next run time
      const next = cronParser.parseExpression(schedule.cronExpression).next();
      await db.schedules.update({
        where: { id: schedule.id },
        data: { lastRunAt: new Date(), nextRunAt: next.toDate() },
      });
    });
    
    this.jobs.set(schedule.id, job);
  }
}

5. Configuration Versioning and Backup

typescript
// backend/src/services/config.service.ts
export class ConfigService {
  async backupConfig(hostId: string) {
    const host = await db.hosts.findUnique({ where: { id: hostId }});
    const config = await rcloneService.getConfigDump(host);
    
    // Store backup with timestamp
    const backup = await db.configBackups.create({
      data: {
        hostId,
        configData: config,
        backupType: 'MANUAL',
      },
    });
    
    // Keep only last 10 backups
    await this.pruneOldBackups(hostId, 10);
    
    return backup;
  }
  
  async restoreConfig(backupId: string) {
    const backup = await db.configBackups.findUnique({ 
      where: { id: backupId }} 
    });
    
    // Verify backup integrity before restore
    if (!this.verifyConfigIntegrity(backup.configData)) {
      throw new Error('Backup integrity check failed');
    }
    
    // Restore
    await rcloneService.setConfigDump(backup.hostId, backup.configData);
    
    return { success: true };
  }
}

Core Features

Multi-Host Management

FeatureDescription
Host RegistryAdd multiple Rclone VPS/instances
Remote CloningCopy remote configs between hosts
Health MonitoringReal-time status checks
Connection ProfilesPersistent connection settings

File Browser

FeatureDescription
Directory NavigationBrowse remote files like local
Dry Run ModeSimulate copy/move before execution
File OperationsCopy, move, delete, create directory
File PreviewView file metadata

Mount Management

FeatureDescription
Mount CreationCreate FUSE mounts
Auto-MountMount on system startup
Health MonitoringReal-time mount status
Process ManagementAuto-spawn and restart

Job Control

FeatureDescription
Job TypesCopy, move, sync, sync backup
ControlPause, resume, stop
Progress TrackingReal-time speed and percentage
HistoryComplete job execution history

Scheduling

FeatureDescription
Cron ExpressionFull cron syntax support
Visual EditorGUI without cron knowledge
RecurrenceDaily, weekly, monthly patterns
Execution HistoryTrack past scheduled runs

Security Implementation

Authentication & Authorization

FeatureImplementation
Password Hashingbcrypt with salt
Session Managementexpress-session with secure cookies
Role-Based AccessADMIN and VIEWER roles
Host-Level PermissionsUsers see only authorized hosts

Audit Logging

typescript
// All critical actions are logged
const actions = [
  'LOGIN', 'LOGOUT', 'FAILED_LOGIN',
  'FILE_DELETE', 'FILE_COPY', 'FILE_MOVE',
  'JOB_START', 'JOB_STOP', 'JOB_COMPLETE',
  'CONFIG_CREATE', 'CONFIG_UPDATE', 'CONFIG_DELETE',
  'HOST_CREATE', 'HOST_DELETE',
  'SCHEDULE_CREATE', 'SCHEDULE_UPDATE', 'SCHEDULE_DELETE',
  'MOUNT_CREATE', 'MOUNT_DELETE',
];

// Audit entry structure
{
  action: string,
  userId: string,
  hostId: string,
  details: string,
  ipAddress: string,
  userAgent: string,
  timestamp: Date,
}

Configuration Protection

  • Automatic config versioning before any modification
  • Encrypted backup to remote cloud storage
  • Config integrity verification before restore

API Endpoints

Authentication

MethodEndpointDescription
POST/auth/loginUser login
POST/auth/logoutUser logout
GET/auth/meCurrent user info
POST/auth/passwordChange password

Hosts

MethodEndpointDescription
GET/hostsList all hosts
POST/hostsAdd new host
GET/hosts/:idGet host details
PATCH/hosts/:idUpdate host
DELETE/hosts/:idRemove host
POST/hosts/:id/testTest connection

Remotes

MethodEndpointDescription
GET/remotes/:hostIdList remotes
POST/remotes/:hostIdCreate remote
PATCH/remotes/:hostId/:nameUpdate remote
DELETE/remotes/:hostId/:nameDelete remote

Files

MethodEndpointDescription
GET/files/:hostId/:remoteList files
POST/files/:hostId/copyCopy file
POST/files/:hostId/moveMove file
DELETE/files/:hostIdDelete file
POST/files/:hostId/mkdirCreate directory

Mounts

MethodEndpointDescription
GET/mounts/:hostIdList mounts
POST/mounts/:hostIdCreate mount
DELETE/mounts/:hostId/:mountUnmount

Jobs

MethodEndpointDescription
GET/jobsList all jobs
GET/jobs/:idJob details
POST/jobs/:id/pausePause job
POST/jobs/:id/resumeResume job
POST/jobs/:id/stopStop job

Schedules

MethodEndpointDescription
GET/schedulesList schedules
POST/schedulesCreate schedule
PATCH/schedules/:idUpdate schedule
DELETE/schedules/:idDelete schedule

Stats

MethodEndpointDescription
GET/stats/transferTransfer stats
GET/stats/systemSystem resources
GET/stats/jobsJob statistics
WS/ws/statsReal-time stats stream

Frontend Components

The Next.js frontend provides a Windows Explorer-like interface:

ComponentDescription
DashboardOverview with host status, recent jobs, stats
File BrowserNavigate and manage cloud files
MountsManage FUSE mounts
JobsMonitor and control transfer jobs
SchedulesCreate and manage cron jobs
SettingsUser and system configuration

Real-Time Features

  • WebSocket connection for live transfer updates
  • Speed, bandwidth, and progress monitoring
  • Job state changes (pause/resume/complete)
  • System resource monitoring

Deployment

Docker Production

bash
# Configure environment
cp .env.prod.example .env

# Build and start
docker-compose -f docker-compose.prod.yml up -d --build

Services

ServicePortDescription
Frontend3000Next.js web UI
Backend3001Express API
Rclone5572Rclone RC

Configuration Variables

VariableDefaultDescription
ADMIN_PASSWORDadminWeb UI password
SESSION_SECRETrandomSession encryption
RCLONE_API_URLhttp://rclone:5572Rclone RC URL
RCLONE_API_USERadminRclone RC user
RCLONE_API_PASS(empty)Rclone RC password

Roadmap

  • Phase 1 — Core Platform (Complete) - Auth, hosts, remotes
  • Phase 2 — File Browser (Complete) - Navigation, copy, move, delete
  • Phase 3 — Mount Management (Complete) - FUSE mounting, health checks
  • Phase 4 — Job Control (Complete) - Background transfers, WebSocket
  • Phase 5 — Scheduling (Complete) - Cron-based automation
  • Phase 6 — Security (Complete) - Audit logging, config versioning
  • Phase 7 — Advanced Features (In Progress) - Bandwidth limits, sync verification
  • Phase 8 — Clustering (Planned) - Distributed job processing
  • Phase 9 — Mobile App (Planned) - iOS/Android monitoring

Conclusion

The Aatmanova Cloud Manager transforms the powerful but CLI-only Rclone into an accessible enterprise web application. The secure proxy architecture ensures the Rclone RC API is never directly exposed while providing comprehensive multi-host management from a centralized dashboard.

Real-time WebSocket monitoring enables teams to track transfers as they happen, while cron-based scheduling automates recurring backup tasks without manual intervention. The SQLite-backed audit logging provides compliance-ready tracking of all critical actions, and the configuration versioning system protects against accidental misconfiguration.

The production-ready Docker deployment with optimized non-root containers ensures security in production environments, while the modular architecture supports future enhancements like distributed job processing and mobile applications.

Architecture Feedback

Spotted a potential optimization or antipattern? Let me know.

Submit a Technical Suggestion