Cloud Commander

Cloud file manager with console and editor

View Project on GitHub

Find typo? Help fix it.
Contact

Cloud Commander v17.1.3

Main Blog Support Demo

Cloud Commander is a file manager for the web. It includes a command-line console and a text editor. Cloud Commander helps you manage your server and work with files, directories and programs in a web browser from any computer, mobile or tablet.

Cloud Commander

Benefits

Installation

Installation is very simple:

npm i cloudcmd -g

When in trouble, use:

npm i cloudcmd -g --force

Usage

To start the server, just run the global npm binary from your terminal:

cloudcmd

Cloud Commander supports the following command-line parameters:

Parameter Operation
-h, --help display help and exit
-v, --version display version and exit
-s, --save save configuration
-o, --online load scripts from remote servers
-a, --auth enable authorization
-u, --username set username
-p, --password set password
-c, --config configuration file path
--show-config show config values
--show-file-name show file name in view and edit
--editor set editor: “dword”, “edward” or “deepword”
--packer set packer: “tar” or “zip”
--root set root directory
--prefix set url prefix
--prefix-socket set prefix for url connection
--port set port number
--confirm-copy confirm copy
--confirm-move confirm move
--open open web browser when server starts
--name set tab name in web browser
--one-file-panel show one file panel
--keys-panel show keys panel
--contact enable contact
--config-dialog enable config dialog
--config-auth enable auth change in config dialog
--console enable console
--sync-console-path sync console path
--terminal enable terminal
--terminal-path set terminal path
--terminal-command set command to run in terminal (shell by default)
--terminal-auto-restart restart command on exit
--vim enable vim hot keys
--columns set visible columns
--export enable export of config through a server
--export-token authorization token used by export server
--import enable import of config
--import-token authorization token used to connect to export server
--import-url url of an import server
--import-listen enable listen on config updates from import server
--dropbox enable dropbox integration
--dropbox-token set dropbox token
--log enable logging
--no-show-config do not show config values
--no-server do not start server
--no-auth disable authorization
--no-online load scripts from local server
--no-open do not open web browser when server started
--no-name set default tab name in web browser
--no-keys-panel hide keys panel
--no-one-file-panel show two file panels
--no-confirm-copy do not confirm copy
--no-confirm-move do not confirm move
--no-config-dialog disable config dialog
--no-config-auth disable auth change in config dialog
--no-console disable console
--no-sync-console-path do not sync console path
--no-contact disable contact
--no-terminal disable terminal
--no-terminal-command set default shell to run in terminal
--no-terminal-auto-restart do not restart command on exit
--no-vim disable vim hot keys
--no-columns set default visible columns
--no-export disable export config through a server
--no-import disable import of config
--no-import-listen disable listen on config updates from import server
--no-show-file-name do not show file name in view and edit
--no-dropbox disable dropbox integration
--no-dropbox-token unset dropbox token
--no-log disable logging

For options not specified by command-line parameters, Cloud Commander then reads configuration data from ~/.cloudcmd.json. It uses port 8000 by default.

To begin using the web client, go to this URL in your browser:

http://localhost:8000

Updating the app

If you installed Cloud Commander with npm, stop the server. Then, reinstall it with:

npm install cloudcmd -g

Then, start the server again with cloudcmd and reload the page.

Hot keys

Key Operation
F1 help
F2 show user menu
F3 view, change directory
Shift + F3 view raw file, change directory
F4 edit
F5 copy
Alt + F5 pack
F6 rename/move
Shift + F6 rename current file
F7 new directory
Shift + F7 new file
F8, Delete remove
Shift + Delete remove without prompt
F9 menu
Alt + F9 extract
F10 config
* select/unselect all
+ expand selection
- shrink selection
: open Command Line
Ctrl + X cut to buffer
Ctrl + C copy to buffer
Ctrl + V paste from buffer
Ctrl + Z clear buffer
Ctrl + P copy path
Ctrl + R refresh
Ctrl + D clear local storage
Ctrl + A select all files in a panel
Ctrl + M rename selected files in editor
Ctrl + U swap panels
Ctrl + F3 sort by name
Ctrl + F5 sort by date
Ctrl + F6 sort by size
Up, Down file system navigation
Enter change directory/view file
Alt + Left/Right show content of directory under cursor in target panel
Alt + G go to directory
Ctrl + \ go to the root directory
Tab move via panels
Page Up up on one page
Page Down down on one page
Home to begin of list
End to end of list
Space select current file (and get size of directory)
Insert select current file (and move to next)
F9 context menu
~ console
Esc toggle vim hotkeys (file manager, editor)

Vim

When the --vim option is provided, or the configuration parameter vim is set, the following hotkeys become available:

Key Operation
j navigate to next file
k navigate to previous file
dd remove current file
G or $ navigate to bottom file
gg or ^ navigate to top file
v visual mode
y copy (selected in visual mode files)
p paste files
Esc unselect all
/ find file in current directory
n navigate to next found file
N navigate to previous found file
md make directory
mf make file
tt show terminal
e edit file

Commands can be joined, for example:

Drag and drop

These file operations are accessible with “drag and drop”.

Drag Mouse Button Key Origin Destination Operation
Left   Panel Panel copy files
Left Shift Panel Panel rename/move files
Left   Panel Desktop download files
Left   Desktop Panel upload files

View

View

Features

Hotkeys

Key Operation
F3 open
Esc close

Edit

Edit

Hot keys

Key Operation
F4 open
Shift + F4 open in “vim” mode
Esc close

For more details see Edward hotkeys.

Console

Console

Hot keys

Key Operation
~ open
Ctrl + P paste path of current directory
Esc close

For more details see console hot keys.

Terminal

Terminal

Install

The terminal is disabled and not installed by default. To use it, you should install gritty with:

npm i gritty -g

and then set the path for the terminal with:

cloudcmd --terminal --terminal-path `gritty --path` --save

Windows

If you can’t install gritty on Windows, try to install windows-build-tools first:

npm install windows-build-tools -g

Then get the path of gritty with:

gritty --path

It will returns something like:

C:\Users\coderaiser\AppData\Roaming\npm\node_modules\gritty

Set this path as --terminal-path with:

cloudcmd --save --terminal --terminal-path "C:\Users\coderaiser\AppData\Roaming\npm\node_modules\gritty"

After that, you can use Cloud Commander’s terminal in the same way as a normal shell console.

Hotkeys

Key Operation
Shift + ~ open
Shift + Esc close

Environment Variables

Every program executed in Cloud Commander’s terminal has these environment variables:

On Unix, you can use it this way:

~> echo $CURRENT_PATH
/home/coderaiser/cloudcmd/bin/cloudcmd.js

Configuration

Config

Hot keys

Key Operation
F10 open
Esc close

When you change any options, the ~/.cloudcmd.json file is automatically updated. It can also be edited manually with any text editor. Here’s a description of all options:

{
    "name": "", // set tab name in web browser
    "auth": false, // enable http authentication
    "username": "root", // username for authentication
    "password": "toor", // password hash for authentication
    "algo": "sha512WithRSAEncryption", // cryptographic algorithm
    "editor": "edward", // default, could be "dword" or "edward"
    "packer": "tar", // default, could be "tar" or "zip"
    "diff": true, // when save - send patch, not whole file
    "zip": true, // zip text before send / unzip before save
    "buffer": true, // buffer for copying files
    "dirStorage": true, // store directory listing
    "online": false, // do not load js files from cdn
    "open": true, // open web browser when server started
    "oneFilePanel": false, // show one file panel
    "keysPanel": true, // show classic panel with buttons of keys
    "port": 8000, // http port
    "ip": null, // ip or null(default)
    "root": "/", // root directory
    "prefix": "", // url prefix
    "prefixSocket": "", // prefix for socket connection
    "confirmCopy": true, // confirm copy
    "confirmMove": true, // confirm move
    "showConfig": false, // show config at startup
    "showFileName": false, // do not show file name in view and edit
    "contact": true, // enable contact
    "configDialog": true, // enable config dialog
    "configAuth": true, // enable auth change in config dialog
    "console": true, // enable console
    "syncConsolePath": false, // do not sync console path
    "terminal": false, // disable terminal
    "terminalPath": "", // path of a terminal
    "terminalCommand": "", // set command to run in terminal
    "terminalAutoRestart": true, // restart command on exit
    "vim": false, // disable vim hot keys
    "columns": "name-size-date-owner-mode", // set visible columns
    "export": false, // enable export of config through a server
    "exportToken": "root", // token used by export server
    "import": false, // enable import of config
    "import-url": "http://localhost:8000", // url of an export server
    "importToken": "root", // token used to connect to export server
    "importListen": false, // listen on config updates
    "dropbox": false, // disable dropbox integration
    "dropboxToken": "", // unset dropbox token
    "log": true // logging
}

Environment Variables

Some config options can be overridden with environment variables, such as:

User Menu

When you press F2 Cloud Commander will read a file .cloudcmd.menu.js by walking up parent directories, if can’t read it will try to read ~/.cloudcmd.menu.js.

Let’s consider example user menu works file:

const RENAME_FILE = 'Rename file';

export default {
    '__settings': {
        select: [RENAME_FILE],
        run: false,
    },
    [`F2 - ${RENAME_FILE}`]: async ({DOM}) => {
        await DOM.renameCurrent();
    },
    'D - Build Dev': async ({CloudCmd}) => {
        await CloudCmd.TerminalRun.show({
            command: 'npm run build:client:dev',
            autoClose: false, // optional
            closeMessage: 'Press any button to close Terminal', // optional
        });
        
        await CloudCmd.refresh();
    },
    'P - Build Prod': async ({CloudCmd}) => {
        await CloudCmd.TerminalRun.show({
            command: 'npm run build:client',
            autoClose: true, // optional
        });
        
        await CloudCmd.refresh();
    },
    'C - Create User Menu File': async ({DOM, CloudCmd}) => {
        const {CurrentInfo} = DOM;
        
        const {dirPath} = CurrentInfo;
        const path = `${dirPath}.cloudcmd.menu.js`;
        const {prefix} = CloudCmd;
        
        const data = await readDefaultMenu({
            prefix,
        });
        
        await createDefaultMenu({
            path,
            data,
            DOM,
            CloudCmd,
        });
    },
};

async function createDefaultMenu({path, data, DOM, CloudCmd}) {
    const {IO} = DOM;
    
    await IO.write(path, data);
    await CloudCmd.refresh();
    
    DOM.setCurrentByName('.cloudcmd.menu.js');
    
    await CloudCmd.EditFile.show();
}

async function readDefaultMenu({prefix}) {
    const res = await fetch(`${prefix}/api/v1/user-menu/default`);
    const data = await res.text();
    
    return data;
}

You will have ability to run one of this 3 commands with help of double click, enter, or binded key (F2, D or P in this example). Also you can run commands in terminal, or execute any built-in function of Cloud Commander extended it’s interface. You can find more examples in User Menu Cookbook.

User Menu API

Here you can find API that can be used in User Menu. DOM and CloudCmd two main objects you receive in arguments list using destructuring.

DOM contains all base functions of Cloud Commander (rename, remove, download etc);

CloudCmd contains all modules (Terminal, View, Edit, Config, Console etc);

IO Files API

Distribute

Being able to configure Cloud Commander remotely opens the doors to using it as microservice, and that’s what the “distribute” options set out to do.

There is an export server and an import client, which are enabled with --export and --import respectively. There is a “token”, which should be the same in --import-token and --export-token. To use the import client, you should provide --import-url to the client so it can connect to an export server.

There are two ways that the import client can receive configuration from an export server:

An example - using the “distribute” options to get configuration from a remote instance:

Here’s an export server:

coderaiser@cloudcmd:~$ cloudcmd --port 1234 --export --export-token=cloudcmd

…and an import client:

coderaiser@cloudcmd:~$ cloudcmd --name importer --port 4321 --import-url http://127.0.0.1:1234 --import-token=cloudcmd --no-server --save

Here’s the log output from the export server:

url: http://localhost:1234/
2018.08.23 13:41:45 -> export: try to auth from importer [127.0.0.1:4321]
2018.08.23 13:41:45 -> export: connected to importer [127.0.0.1:4321]
2018.08.23 13:41:45 -> export: config send to importer [127.0.0.1:4321]
2018.08.23 13:41:45 -> export: disconnected importer [127.0.0.1:4321]

…and the log output from the import client:

2018.08.23 13:47:36 -> import: try to auth to http://127.0.0.1:1234
2018.08.23 13:47:36 -> import: connected to http://127.0.0.1:1234
2018.08.23 13:47:36 -> import: config received from http://127.0.0.1:1234
2018.08.23 13:47:36 -> import: disconnected from http://127.0.0.1:1234

When the import client uses --import-listen, a persistent connection is used, and the client receives live updates from the import server.

The export server omits the following configuration fields:

Menu

Right-mouse click to show a context menu with these items:

Hot keys

Key Operation
F9 open
Esc close

One file panel

Cloud Commander can work in one panel mode when your screen size can’t accommodate a second panel (such as on mobile or tablet), or via the --one-file-panel options flag.

One file panel

Using as middleware

Cloud Commander can be used as middleware for node.js applications based on socket.io and express:

Init package.json:

npm init -y

Install dependencies:

npm i cloudcmd express socket.io -S

And create index.js:

import http from 'node:http';
import cloudcmd from 'cloudcmd';
import {Server} from 'socket.io';
import express from 'express';

const app = express();
const port = 1337;
const prefix = '/';

const server = http.createServer(app);
const socket = new Server(server, {
    path: `${prefix}socket.io`,
});

const config = {
    name: 'cloudcmd :)',
};

const filePicker = {
    data: {
        FilePicker: {
            key: 'key',
        },
    },
};

// override option from json/modules.json
const modules = {
    filePicker,
};

const {
    createConfigManager,
    configPath,
} = cloudcmd;

const configManager = createConfigManager({
    configPath,
});

app.use(prefix, cloudcmd({
    socket, // used by Config, Edit (optional) and Console (required)
    config, // config data (optional)
    modules, // optional
    configManager, // optional
}));

server.listen(port);

Here is example with two Config Managers:

import http from 'node:http';
import cloudcmd from 'cloudcmd';
import {Server} from 'socket.io';
import express from 'express';

const app = express();
const port = 8000;
const prefix1 = '/1';
const prefix2 = '/2';

const {createConfigManager} = cloudcmd;

const server = http.createServer(app);
const socket1 = new Server(server, {
    path: `${prefix1}/socket.io`,
});

const socket2 = new Server(server, {
    path: `${prefix2}/socket.io`,
});

const configManager1 = createConfigManager();

configManager1('name', '1');

const configManager2 = createConfigManager();
configManager2('name', '2');

app.use(prefix1, cloudcmd({
    socket: socket1,
    configManager: configManager1,
}));

app.use(prefix2, cloudcmd({
    socket: socket2,
    configManager: configManager2,
}));

server.listen(port);

If you want to enable authorization, you can pass credentials to Cloud Commander with a config. To generate a password, you can install criton with npm i criton --save, and use it (or any other way) to generate a hash of a password.

import criton from 'criton';

const algo = 'sha512WithRSAEncryption';

// default
// you can generate a hash dynamically
const password = criton('root', algo);

// or use a pregenerated hash as well
'2b64f2e..ca5d9a9';

const auth = true;
const username = 'root';

const config = {
    algo, // optional
    auth,
    username,
    password,
};

Now you’re ready to go!

Authorization

~/.cloudcmd.json contains password hash because of security reason, if someone steal your config, he wouldn’t know your password, because hash is very strong and can be customized.

You should never write your password as plain text to ~/.cloudcmd.json, you can generate password using cloudcmd itself:

cloudcmd --username name --password password --auth --save --no-server

This command will create hash of your password and write it to ~/.cloudcmd.json.

Server

Standard practices dictate that no non-root process get to talk to the internet on a port less than 1024. Despite this, I suggest you start Cloud Commander as a non-root process. How can we get around this limitation? There’s a couple of fast & easy ways. One of them is port forwarding:

Iptables

Just run shell/addtables.sh for default options.

iptables -t nat -L # look rules before
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8000
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 4430
iptables -t nat -L # look rules after

You should see something like this (8000 and 4430 should be in config as port and sslPort)

target     prot opt source               destination
REDIRECT   tcp  --  anywhere             anywhere             tcp dpt:http redir ports 8000
REDIRECT   tcp  --  anywhere             anywhere             tcp dpt:https redir ports 4430

If you would want to get things back just clear rules (rule numbers 1 and 2; in your list they could differ).

iptables -t nat -D PREROUTING 2
iptables -t nat -D PREROUTING 1

nginx

Get nginx. On Linux, you can run:

sudo apt-get install nginx #for ubuntu and debian

Then, make a host file /etc/nginx/sites-available/io.cloudcmd.io (where, for example, io.cloudcmd.io is your domain name) with these contents:

server {
    listen 80;
    client_max_body_size 100m;
    server_name io.cloudcmd.io;
    access_log /var/log/nginx/io.cloudcmd.io.access.log;
    location / {
        proxy_pass          http://127.0.0.1:8000/;
    }
}

If you want add SSL, add a couple lines to the server block:

server {
    listen 443;
    client_max_body_size 100m;
    ssl                  on;
    ssl_certificate      /home/coderaiser/cloudcmd/ssl/ssl.crt;
    ssl_certificate_key  /home/coderaiser/cloudcmd/ssl/ssl.key;
    server_name io.cloudcmd.io;
    access_log /var/log/nginx/io.cloudcmd.io.access.log;
    location / {
        proxy_pass    http://127.0.0.1:8000/;
    }
}

For WebSocket support, (nginx >= v1.3.13) modify the server block like so:

    location / {
        proxy_http_version  1.1;
        proxy_set_header    Upgrade $http_upgrade;
        proxy_set_header    Connection "upgrade";

        proxy_pass          http://127.0.0.1:8000/;
    }

If you need redirection from http to https, simply use:

server {
    listen 80;
    server_name admin.cloudcmd.io;
    rewrite ^ https://io.cloudcmd.io$request_uri? permanent; #301 redirect
    access_log /var/log/nginx/io.cloudcmd.io.access.log;
}
# create a symlink of this file
ln -s ./sites-available/io.cloudcmd.io ./sites-enabled
# restart nginx
/etc/init.d/nginx restart

Deploy

Cloud Commander can be easily deployed to Heroku.

Deploy to Heroku

Docker

Cloud Commander can be used as docker container like so:

docker run -t --rm -v ~:/root -v /:/mnt/fs -w=/root -p 8000:8000 coderaiser/cloudcmd

Configuration will be read from the home directory, the host’s root file system will be mounted to /mnt/fs, and port 8000 port will exposed to the host’s port.

Also, you can use docker compose with docker-compose.yml:

version: '2'
services:
  web:
    ports:
      - 8000:8000
    volumes:
      - ~:/root
      - /:/mnt/fs
    image: coderaiser/cloudcmd

When you create this file, run:

docker-compose up

Dropbox

Dropbox support is integrated into Cloud Commander, and you can switch from your local file system to a Dropbox account. All you need to do is set --dropbox option and generate a dropbox token for your account.

This could look like this:

cloudcmd --dropbox --dropbox-token your-dropbox-token

While using Dropbox remember that there is no remote support for the console/terminal. Seeing the progress of file operations is also not supported. There’s only basic support, but you can do the following things with files and directories:

Automatically start cloudcmd on boot for systemd

First, locate the command to run cloudcmd

which cloudcmd

take note of the result and create a systemd entry by executing

sudo nano /etc/systemd/system/cloudcmd.service

and use this template

[Unit]
Description = Cloud Commander

[Service]
TimeoutStartSec = 0
Restart = always
ExecStart = THE RESULT OF which cloudcmd WE'VE EXECUTED EARLIER
User = YOUR_USER

[Install]
WantedBy = multi-user.target

Don’t forget to change the line for ExecStart and User

Save the changes and exit editor.

You may now enable cloudcmd and set it to autostart on boot by running:

sudo systemctl enable --now cloudcmd

Automatically start cloudcmd on boot for FreeBSD

First, locate the command to run cloudcmd

which cloudcmd

take note of the result and create a rc script

vi /usr/local/etc/rc.d/cloudcmd

and use this template

!/bin/sh
#
# PROVIDE: cloudcmd
# REQUIRE: LOGIN
# KEYWORD: shutdown

# Author: IhatemyISP (ihatemyisp.net)
# Version: 1.0.0

# Description:
#    This script runs Cloud Commander as a service under the supplied user on boot

#    1) Place file in /usr/local/etc/rc.d/
#    2) Add cloudcmd_enable="YES" to /etc/rc.conf
#    3) (Optional) To run as non-root, add cloudcmd_runAs="user" to /etc/rc.conf
#    4) (Optional) To pass Cloud Commander args, add cloudcmd_args="" to /etc/rc.conf

# Freebsd rc library
. /etc/rc.subr

# General Info
name="cloudcmd"            # Safe name of program
program_name="cloudcmd"   # Name of exec
title="CloudCommander"          # Title to display in top/htop

# RC.config vars
load_rc_config $name      # Loading rc config vars
: ${cloudcmd_enable="NO"}  # Default: Do not enable Cloud Commander
: ${cloudcmd_runAs="root"} # Default: Run Cloud Commander as root

# Freebsd Setup
rcvar=cloudcmd_enable                   # Enables the rc.conf YES/NO flag
pidfile="/var/run/${program_name}.pid" # PID file location

# Env Setup
export HOME=$( getent passwd "$cloudcmd_runAs" | cut -d: -f6 ) # Gets the home directory of the runAs user

# Command Setup
exec_path="/usr/local/bin/${program_name}" # Path to the cloudcmd exec, /usr/local/bin/ when installed globally
output_file="/var/log/${program_name}.log" # Path to Cloud Commander output file

# Command
command="/usr/sbin/daemon"
command_args="-r -t ${title} -u ${cloudcmd_runAs} -o ${output_file} -P ${pidfile} ${exec_path} ${cloudcmd_args}"

# Loading Config
load_rc_config ${name}
run_rc_command "$1"

Enable autostart

echo cloudcmd_enable="YES" >> /etc/rc.conf

(Optional) Set user to run Cloud Commander as (default is root)

echo cloudcmd_runAs="user" >> /etc/rc.conf

Start the service (or just reboot)

service cloudcmd start

Get involved

There are a lot of ways to be involved in Cloud Commander development:

Version history

Special Thanks