Getting Started

What is NebulaSSH?

NebulaSSH is a web-based SSH terminal and remote management platform. It allows you to:

  • Connect to remote servers via SSH directly from your browser
  • Manage files using the built-in SFTP file manager
  • Access remote desktops via VNC
  • Remotely manage Windows PCs using the Connector Agent (like AnyDesk)

Quick Start

  1. Login — Use your credentials to sign in
  2. Add a Session — Click "New Session" in the SSH Terminal page and enter your server details
  3. Connect — Double-click a saved session to open an SSH terminal

SSH Terminal

Creating a Session

  1. Go to SSH Terminal from the sidebar
  2. Click New Session
  3. Fill in: Host, Port (default 22), Username, and Authentication method
  4. Choose Password or Private Key authentication
  5. Click Save

Using the Terminal

  • Double-click a session to connect
  • The terminal supports full ANSI colors and keyboard shortcuts
  • Use Ctrl+Shift+V to paste into the terminal
  • Right-click for copy/paste context menu

SFTP File Manager

Accessing Files

  • When connected to an SSH session, click the SFTP tab in the sidebar
  • Browse the remote file system with the file tree

File Operations

  • Upload — Drag and drop files into the file manager
  • Download — Click a file to download it
  • Rename / Delete / Chmod — Right-click a file for context menu options
  • Create Folder — Right-click in empty area and select "New Folder"

VNC Desktop

VNC Desktop lets you view and interact with a remote graphical desktop directly from your browser. It auto-detects running browsers and X11 displays on the remote server.

Opening VNC Desktop

  1. Connect to an SSH session in the Terminal
  2. Click the VNC Desktop button in the terminal toolbar
  3. A new browser tab opens with the remote desktop viewer
  4. The system automatically detects active displays and running browsers

Toolbar Controls

ButtonDescription
Find BrowserAuto-detects browser windows (Chrome, Firefox, etc.) running on the remote desktop and connects to that display
DisplaysScan and switch between available X11 displays (:0, :1, etc.)
Ctrl+Alt+DelSend the keyboard combination to the remote desktop
Toggle Scale/FitSwitch between fit-to-window and 1:1 pixel rendering
FullscreenToggle fullscreen view of the remote desktop
RefreshReconnect to VNC if the connection drops

How It Works

Your Browser                    Remote Linux Server
     |                                  |
     |--- Click "VNC Desktop" --------->|
     |                                  |
     |    1. Detect X11 displays        |
     |    2. Find running browsers      |
     |    3. Start x11vnc server        |
     |    4. SSH port forwarding        |
     |                                  |
     |<-- WebSocket (noVNC) ------------|
     |    Live desktop stream           |
     |                                  |

Display Auto-Detection

When you open VNC Desktop, the system automatically:

  • Scans /tmp/.X*-lock files for running X11 displays
  • Detects browser processes (Chrome, Firefox, Chromium, Electron, Playwright)
  • Reads the DISPLAY environment variable of each browser process
  • Connects to the display where a browser is actively running
  • If no display exists, creates a new virtual display (Xvfb) at 1920x1080

AI Browser Viewing via VNC

When Claude Code (AI) is connected to a terminal via SSH, it can view and interact with remote browser windows through the VNC Desktop feature. This allows the AI to see what is displayed on the screen, take screenshots, and assist with browser-based tasks.

How AI Views the Browser

When you click VNC Desktop on a terminal session, the remote server starts an x11vnc server on the display where a browser is running. The AI can then use the VNC API to view the desktop and take screenshots of what is visible.

Step-by-Step Flow

  1. Connect to SSH — Open an SSH terminal session to your remote server
  2. Click VNC Desktop — Click the VNC Desktop button in the terminal toolbar
  3. Browser is detected — The system auto-detects running browsers on the remote display
  4. AI gets visual access — Claude Code can now see the remote desktop through the VNC stream and take screenshots
  5. AI assists — Ask the AI to describe what it sees, click elements, navigate pages, or debug visual issues

Using the VNC API for AI

The AI can interact with VNC sessions through these API endpoints:

# Step 1: Start a VNC session (auto-detects browser display)
curl -s -X POST https://app.nebulassh.com/api/Vnc/start \
  -H "Content-Type: application/json" \
  -d '{"host":"your-server","port":22,"username":"user","password":"pass"}'

# Response:
# { "sessionId": "abc123", "display": ":1", "port": 5901 }

# Step 2: Auto-detect displays with running browsers
curl -s -X POST https://app.nebulassh.com/api/Vnc/auto-detect \
  -H "Content-Type: application/json" \
  -d '{"host":"your-server","port":22,"username":"user","password":"pass"}'

# Response:
# { "displays": [{ "display": ":1", "browsers": ["chrome"], "hasVnc": true }] }

# Step 3: Scan all available X11 displays
curl -s -X POST https://app.nebulassh.com/api/Vnc/scan \
  -H "Content-Type: application/json" \
  -d '{"host":"your-server","port":22,"username":"user","password":"pass"}'

# Step 4: Connect to a specific display
curl -s -X POST https://app.nebulassh.com/api/Vnc/connect \
  -H "Content-Type: application/json" \
  -d '{"host":"your-server","port":22,"username":"user","password":"pass","display":":1"}'

# Step 5: Check session status
curl -s https://app.nebulassh.com/api/Vnc/status/{sessionId}

# Step 6: Execute commands on the remote desktop session
curl -s -X POST https://app.nebulassh.com/api/Vnc/execute/{sessionId} \
  -H "Content-Type: application/json" \
  -d '{"command":"xdotool getactivewindow getwindowname"}'

# Step 7: Stop the session when done
curl -s -X POST https://app.nebulassh.com/api/Vnc/stop/{sessionId}

What the AI Can Do

CapabilityDescription
View the desktopSee the remote graphical environment through the VNC stream via the browser tab
Detect browsersIdentify which browsers (Chrome, Firefox, etc.) are running and on which display
Take screenshotsCapture what is currently shown on the remote desktop for visual analysis
Execute commandsRun shell commands in the remote session (e.g., xdotool for mouse/keyboard automation)
Switch displaysMove between different X11 displays to find the right browser window

Example: Ask AI to View a Browser

With Claude Code connected to your terminal, you can use natural language:

> Open VNC desktop and show me what's on the screen

> Take a screenshot of the remote browser

> What website is currently open in the browser on display :1?

> Click the login button on the remote browser

> Navigate the remote browser to https://example.com

Prerequisites

  • An active SSH session to a Linux server with a graphical environment (X11)
  • A browser running on the remote server (Chrome, Firefox, Chromium, etc.)
  • x11vnc must be installed on the remote server — run sudo apt install -y x11vnc on the remote machine if VNC Desktop disconnects
  • Optional: xdotool for mouse/keyboard automation via AI commands

Troubleshooting

VNC Desktop disconnects immediately? The most common cause is that x11vnc is not installed on the remote server. SSH into the remote machine and run:
sudo apt install -y x11vnc
For CentOS/RHEL: sudo yum install -y x11vnc  |  For Arch: sudo pacman -S x11vnc
ProblemSolution
VNC Desktop disconnects immediately on clickx11vnc is not installed on the remote server. Connect via SSH terminal and run: sudo apt install -y x11vnc. This is required on every remote machine you want to use VNC Desktop with.
No displays foundEnsure a graphical session (X11/Xvfb) is running. Start one with Xvfb :99 -screen 0 1920x1080x24 &
No browser detectedLaunch a browser on the remote server: DISPLAY=:99 google-chrome &
VNC connection dropsClick Refresh in the VNC toolbar, or restart the session via the API
x11vnc not foundInstall it on the remote machine: sudo apt install -y x11vnc
Black/empty screenCheck the display number is correct. Use Displays dropdown to scan for active displays
AI cannot see the desktopEnsure the VNC Desktop tab is open in your browser. The AI views the desktop through the browser-rendered VNC stream

CDP Viewer

The CDP Viewer gives you a live, interactive view of a headless Chrome/Chromium running on a remote server — no graphical desktop, X11 or VNC needed. It streams the browser's screen over the Chrome DevTools Protocol (CDP) and lets you click, type and scroll right inside it. It opens in a new browser tab.

When to Use CDP Viewer vs VNC Desktop

FeatureCDP ViewerVNC Desktop
Requires GUI/X11No — works with headless ChromeYes — needs Xvfb or X11
Requires x11vncNoYes
View typeLive screencast (JPEG frames) + mouse/keyboard controlLive video stream of the whole desktop
ScopeThe browser onlyThe entire remote desktop
Best forHeadless servers, web apps, AI/automation, CI/CDFull desktop & native GUI apps
DependenciesJust Google Chrome/Chromium (no extra packages)x11vnc + Xvfb + browser

How It Works

  1. Headless Chrome runs on the remote server with --remote-debugging-port (CDP bound to 127.0.0.1 — it never needs to be exposed to the network).
  2. When you click CDP Viewer, NebulaSSH uses your existing SSH connection to open a secure local tunnel to that debug port — so the credentials stay on the server side and the debug port is never public.
  3. The server connects to Chrome's CDP and issues Page.startScreencast; Chrome streams live JPEG frames, which are relayed to your browser tab over a WebSocket and drawn on a canvas.
  4. Your mouse and keyboard events are sent back as CDP Input.dispatch* commands, so the view is fully interactive. A short-lived session token (not your password) is what the viewer tab uses.

Setup Guide: New Machine

Follow these steps to set up a fresh Linux server for the CDP Viewer:

Step 1: Install Google Chrome
# Ubuntu/Debian
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list
sudo apt update && sudo apt install -y google-chrome-stable

# CentOS/RHEL
sudo dnf install -y https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm

# Or install Chromium instead
sudo apt install -y chromium-browser   # Ubuntu
sudo dnf install -y chromium           # CentOS
Step 2: Start Headless Chrome with Remote Debugging
# Start Chrome headless with debugging port
google-chrome --headless=new --no-sandbox \
  --remote-debugging-port=9222 \
  --disable-gpu --disable-dev-shm-usage \
  https://www.google.com &

# Verify it's running
curl -s http://127.0.0.1:9222/json/version
# Should return: { "Browser": "Chrome/...", ... }

# Check active pages
curl -s http://127.0.0.1:9222/json/list
# Should return a list of open tabs/pages
Step 3: Use the CDP Viewer
  1. Connect to the server via SSH in NebulaSSH
  2. Click the CDP Viewer button in the terminal action bar
  3. A new browser tab opens with the live view — it auto-detects the running Chrome and starts streaming
  4. Interact directly: click, type and scroll on the canvas. Use the toolbar to navigate to a URL, reload, change the viewport size, toggle auto-reload, or turn control off for view-only

AI/Automation Setup

For AI agents (like Claude Code) that need to view and interact with web pages on a remote server:

# One-liner: Start headless Chrome for AI viewing
google-chrome --headless=new --no-sandbox --remote-debugging-port=9222 \
  --disable-gpu --disable-dev-shm-usage https://your-target-site.com &

# For Playwright/Node.js automation with viewing support
npx playwright install chromium
node -e "
const { chromium } = require('playwright');
(async () => {
  const browser = await chromium.launch({
    headless: true,
    args: ['--remote-debugging-port=9222', '--no-sandbox']
  });
  const page = await browser.newPage();
  await page.goto('https://your-target-site.com');
  // Browser stays open for the CDP Viewer to stream
  console.log('Browser ready for viewing on port 9222');
})();
"

Keep Browser Running on Disconnect

To keep the headless browser running after you close the SSH session, use nohup or tmux:

# Method 1: nohup (simple)
nohup google-chrome --headless=new --no-sandbox --remote-debugging-port=9222 \
  --disable-gpu --disable-dev-shm-usage https://your-site.com > /dev/null 2>&1 &

# Method 2: tmux (recommended for long-running)
tmux new-session -d -s chrome "google-chrome --headless=new --no-sandbox \
  --remote-debugging-port=9222 --disable-gpu --disable-dev-shm-usage https://your-site.com"

# Method 3: systemd service (production)
sudo tee /etc/systemd/system/headless-chrome.service > /dev/null << 'EOF'
[Unit]
Description=Headless Chrome for CDP Viewer
After=network.target

[Service]
Type=simple
User=your-username
ExecStart=/usr/bin/google-chrome --headless=new --no-sandbox --remote-debugging-port=9222 --disable-gpu --disable-dev-shm-usage https://your-site.com
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now headless-chrome

Quick Checklist

@#RequirementCheck Command
1Google Chrome or Chromium installedgoogle-chrome --version or chromium --version
2Chrome running with debug portpgrep -fa 'remote-debugging-port'
3CDP responding (on the server)curl -s http://127.0.0.1:9222/json/version
4Pages availablecurl -s http://127.0.0.1:9222/json/list

Troubleshooting

ProblemSolution
CDP Viewer says "No Chrome page/CDP target found"Start Chrome with --remote-debugging-port=9222. Run: google-chrome --headless=new --no-sandbox --remote-debugging-port=9222 --disable-gpu --disable-dev-shm-usage https://google.com &
Chrome crashes immediatelyInstall missing dependencies: sudo apt install -y libnss3 libatk-bridge2.0-0 libx11-xcb1 libxcomposite1 libxdamage1 libxrandr2 libgbm1 libasound2 libpangocairo-1.0-0 libgtk-3-0. Also try adding --disable-dev-shm-usage flag.
"Address already in use" on port 9222Kill existing Chrome processes: pkill -9 -f chrome, then restart
Viewer tab shows "closed" / no framesVerify CDP is accessible on the server: curl -s http://127.0.0.1:9222/json/list. If empty, no pages are open in the browser. Also confirm your SSH session to that host is still connected.
Snap Chromium doesn't work headlessUse Google Chrome instead: sudo apt install -y google-chrome-stable. Snap packages have sandbox restrictions that break headless mode.
View is blank/whiteThe page might still be loading. Use the toolbar to Navigate to a URL or hit Reload.

NebulaSSH Connector Agent

The Connector Agent lets you remotely access Windows and Linux machines using a unique ID — no real IP address, port forwarding, or VPN needed. Works like AnyDesk but with command-line access.
Authentication required. Agents and the API are no longer open:
  • A new machine must enroll with a one-time enrollment token (Dashboard → Agents & Connector). Without it the agent is rejected.
  • Listing or driving agents requires your API key (X-Api-Key header), and you only ever see the agents you own.

Supported Platforms

PlatformAgentShell SupportRequirements
WindowsNebulaSSHAgent.exePowerShell, CMDNo dependencies (self-contained .exe)
Linuxnebulassh-agentBash, Sh, Zshcurl, python3

How It Works

The agent runs on the target machine and connects outbound to the relay server. No inbound ports need to be opened. The relay server acts as a bridge between you and the remote machine.

   You (Browser / CLI)              Relay Server               Remote Machine
         |                      (app.nebulassh.com)             (Windows or Linux)
         |                              |                          |
         |--- Execute command --------->|                          |
         |                              |--- Poll (every 2s) ---->|
         |                              |<-- Here's a command ----|
         |                              |                          |
         |                              |    [ Runs command ]      |
         |                              |                          |
         |                              |<-- Result (stdout) -----|
         |<-- Output -------------------|                          |

Key Features

  • No IP required — connect using a unique Agent ID (e.g., 031-975-703-405)
  • NAT/Firewall friendly — agent connects outbound via HTTPS, works behind any firewall
  • Auto-reconnect — agent reconnects automatically if connection drops
  • File transfer — upload and download files to/from the remote machine
  • AI-friendly — all operations use simple REST APIs, perfect for Claude Code or any AI tool

Windows Agent Setup

The Windows Agent is a lightweight graphical (GUI) app with a dark dashboard and a system-tray icon. It shows your NebulaSSH ID, connection status, and a live log, with Connect, Disconnect, and Settings buttons. It can minimize to the tray and auto-connect on startup. By default it connects to https://app.nebulassh.com.

Step 1: Download the Agent

Download the right version for your Windows PC:

VersionForSizeDownload
NebulaSSHAgent.exe (x64)Windows 10/11, Server 2016/2019/2022 (64-bit)68 MBDownload
NebulaSSHAgent.exe (x86)Windows 7/8/10/11, Server 2012 R2+ (32-bit)63 MBDownload
NebulaSSHAgent.exe (ARM64)Windows 11 ARM, Surface Pro X64 MBDownload

No installation required. No .NET runtime needed. Single file, self-contained (bundles the .NET 8 runtime).

Prefer a tiny, no-window-chrome version? The Console (.NET Framework) agent is only ~20 KB and runs on virtually any Windows (7/8/10/11, Server 2008 R2+) using the built-in .NET Framework — no 60 MB download, no runtime to install. It opens a simple console window and connects to https://app.nebulassh.com.
VersionForSizeDownload
NebulaSSHAgent-Console.exeAny Windows with .NET Framework 4.x (built into Win 8+, on Win 7 via update)~20 KBDownload
Run it (first time): NebulaSSHAgent-Console.exe --enroll-token NS-XXXXX-XXXXX-XXXXX-XXXXX — get the token from the dashboard (Agents & Connector). After enrollment just run NebulaSSHAgent-Console.exe. Point it elsewhere with --relay https://your-relay (defaults to app.nebulassh.com). Press Ctrl+C to stop.

Step 2: Get an Enrollment Token

A new machine must be authorized once before it can connect. Get a credential from the dashboard — open Agents & Connector or click the button (top-right of the Terminal). Use a one-time enrollment token (NS-…, valid 1 hour) or your permanent enrollment key (nse_…, reusable for every machine, never expires). You'll paste it into the agent in the next step. You provide it one of three ways:

  • GUI agent: open Settings (⚙) and paste it into the Enrollment Token field before clicking Connect.
  • Console agent: set NEBULASSH_ENROLL_TOKEN=NS-... then run the exe, or NebulaSSHAgent-Console.exe --enroll-token NS-...
  • Any agent: drop the token into an enroll.token file next to the executable.

The token is single-use and only needed the first time. After the machine is enrolled it reconnects on its own — no token required.

Step 3: Run the Agent on Windows

Double-click NebulaSSHAgent.exe. The agent window opens and shows your unique NebulaSSH ID, the connection status, and a live activity log. Click Connect (or it connects automatically if Auto-Start is enabled in Settings).

┌─ NebulaSSH Agent ──────────────────────┐
│  Status:  ● Connected                  │
│  Your NebulaSSH ID:  123-456-789-012   │
│  Relay:   https://app.nebulassh.com    │
│                                        │
│  [ Connect ]  [ Disconnect ]  [ ⚙ ]    │
│  ─ Log ──────────────────────────────  │
│  Registered as 123-456-789-012         │
│  Waiting for commands...               │
└────────────────────────────────────────┘

Save this ID — you will use it to connect from the web UI or CLI. Closing the window minimizes the agent to the system tray so it keeps running in the background.

Settings

Open Settings (⚙) in the agent window to change:

SettingDescriptionDefault
Relay URLThe relay server the agent connects tohttps://app.nebulassh.com
Enrollment TokenOne-time token to authorize this machine on first connect (cleared automatically once enrolled)empty
Auto-StartLaunch minimized to the tray and connect on Windows loginOff

Start Automatically on Login (Optional)

Enable Auto-Start in Settings — the agent registers itself to launch minimized to the tray and connect every time you sign in to Windows. To run it before login (as a service), use Task Scheduler:

  1. Open Task Scheduler > Create Basic Task
  2. Name: NebulaSSH Agent
  3. Trigger: When the computer starts
  4. Action: Start a program > Browse to NebulaSSHAgent.exe, add the argument --minimized
  5. Check: Run whether user is logged on or not

Linux Agent Setup

Install the Linux Agent on any Linux machine you want to manage remotely. Once running, the machine appears in your NebulaSSH dashboard and can be controlled from anywhere — no IP address, port forwarding, or VPN needed.

Requirements

  • curl — for HTTP communication with the relay server
  • python3 — for JSON parsing
  • bash — shell (pre-installed on all Linux systems)
# Install dependencies (Ubuntu/Debian)
sudo apt update && sudo apt install -y curl python3

# For CentOS/RHEL/Fedora
sudo yum install -y curl python3

# For Arch Linux
sudo pacman -S curl python

Step 1: Download the Agent

Download the agent script and optional installer, or pull them straight to your machine with curl:

FileForDownload
nebulassh-agentThe Linux agent (bash). Run it directly.Download
install.shGuided installer (copies the agent + sets up a systemd service)Download

The agent defaults to the https://app.nebulassh.com relay — no extra flags needed.

Or download via curl (one-liner)
# Download the agent script straight to /usr/local/bin and make it executable
sudo curl -fsSL https://app.nebulassh.com/api/connector/download-linux-agent -o /usr/local/bin/nebulassh-agent
sudo chmod +x /usr/local/bin/nebulassh-agent

# (Optional) grab the guided installer instead
curl -fsSL https://app.nebulassh.com/api/connector/download-linux-installer -o install.sh
chmod +x install.sh && sudo ./install.sh

Step 2: Run the Agent

A brand-new machine must present an enrollment token on its first run so it binds to your account — otherwise you’ll see “Enrollment required”. Get one from the dashboard: click the button (top-right of the Terminal) or open Agents & Connector. Use a one-time token (NS-…) or your permanent enrollment key (nse_…, reusable for every machine).

# First run — supply your token / key (one-time NS-… or permanent nse_…)
nebulassh-agent --relay https://app.nebulassh.com --enroll-token NS-XXXXX-XXXXX-XXXXX-XXXXX

# …or pass it via environment variable
NEBULASSH_ENROLL_TOKEN=NS-XXXXX-XXXXX-XXXXX-XXXXX nebulassh-agent --relay https://app.nebulassh.com

# After enrollment the token is no longer needed — just run:
nebulassh-agent --relay https://app.nebulassh.com

# Run as a background daemon
nebulassh-agent --relay https://app.nebulassh.com --daemon

On startup, the agent displays your unique Agent ID:

╔══════════════════════════════════════╗
║    NebulaSSH Linux Agent v1.0.0     ║
╚══════════════════════════════════════╝
Agent ID:    031-975-703-405
Relay:       https://app.nebulassh.com
Shell:       bash
Interval:    2s

[2026-05-31 17:43:05] [INFO] Registering agent 031-975-703-405...
[2026-05-31 17:43:05] [INFO] Registration successful!
[2026-05-31 17:43:05] [INFO] Machine:   my-server
[2026-05-31 17:43:05] [INFO] OS:        Linux 6.8.0-117-generic x86_64
[2026-05-31 17:43:05] [INFO] User:      admin

Save the Agent ID — you’ll use it to connect from the web UI or CLI.

Agent Command-Line Options

FlagDescriptionDefault
--relay URLRelay server URL (required on first run)—
--enroll-token TOKENOne-time token (NS-…) or permanent key (nse_…); required on first enrollment only. Also via NEBULASSH_ENROLL_TOKEN.—
--shell SHELLDefault shell: bash, sh, zshbash
--interval NPoll interval in seconds2
--daemonRun as background process—
--statusShow agent status (running/stopped)—
--stopStop the running agent—
--idPrint the Agent ID and exit—

Step 3: Auto-Start with Systemd (Recommended)

Set up the agent as a systemd service so it starts on boot. If the machine isn’t enrolled yet, include your enrollment token below — a permanent key (nse_…) is best here since it never expires. Already enrolled it in Step 2? Then just drop the NEBULASSH_ENROLL_TOKEN line.

# Create the service file
sudo tee /etc/systemd/system/nebulassh-agent.service <<EOF
[Unit]
Description=NebulaSSH Linux Agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=$USER
Environment=HOME=$HOME
# First-time enrollment only — use your permanent key (nse_…) or a one-time NS-… token.
# Safe to remove once the machine is enrolled.
Environment=NEBULASSH_ENROLL_TOKEN=nse_XXXXXXXXXXXXXXXXXXXXXXXX
ExecStart=/usr/local/bin/nebulassh-agent --relay https://app.nebulassh.com
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

# Enable and start the service
sudo systemctl daemon-reload
sudo systemctl enable nebulassh-agent
sudo systemctl start nebulassh-agent

Managing the Service

# Check status
sudo systemctl status nebulassh-agent

# View logs
sudo journalctl -u nebulassh-agent -f

# Restart agent
sudo systemctl restart nebulassh-agent

# Stop agent
sudo systemctl stop nebulassh-agent

Or Use the Installer Script

For a guided setup, use the included installer:

# Run the installer with your one-time enrollment token
# (generate it in Dashboard -> Agents & Connector)
sudo NEBULASSH_ENROLL_TOKEN=NS-XXXXX-XXXXX-XXXXX-XXXXX ./install.sh

# It will:
# 1. Copy the agent to /usr/local/bin/
# 2. Ask for your relay server URL
# 3. Enroll the machine under your account (consumes the token)
# 4. Optionally create a systemd service

Connecting to the Linux Agent

Once the agent is running, you can connect from anywhere:

From the Web UI:

  • The agent appears in the Connector Agents list on the dashboard
  • Click on the agent to send commands

From the CLI:

# List all online agents
nebulassh agents

# Execute a command on the Linux agent
nebulassh exec 031-975-703-405 "hostname && uptime && free -h"

# Interactive shell mode
nebulassh shell 031-975-703-405

From AI tools (Claude Code, etc.):

# Step 1: Send a command
curl -X POST https://app.nebulassh.com/api/connector/execute \
  -H "Content-Type: application/json" \
  -d '{"AgentId":"031-975-703-405","Command":"df -h && free -h","Shell":"bash"}'
# Response: {"commandId":"abc123def456"}

# Step 2: Get the result
curl https://app.nebulassh.com/api/connector/result/abc123def456
# Response: {"isCompleted":true,"output":"...","error":"","exitCode":0}

File Transfer

# Upload a file to the Linux agent
curl -X POST https://app.nebulassh.com/api/connector/upload \
  -F "agentId=031-975-703-405" \
  -F "remotePath=/home/user/deploy/app.tar.gz" \
  -F "file=@./app.tar.gz"

# Download a file from the Linux agent
curl -X POST https://app.nebulassh.com/api/connector/download \
  -H "Content-Type: application/json" \
  -d '{"AgentId":"031-975-703-405","RemotePath":"/var/log/syslog"}'

How the Agent ID is Generated

The Agent ID is hardware-bound and stays the same across reboots:

  • Generated from: /etc/machine-id + hostname + username
  • Format: XXX-XXX-XXX-XXX (12 digits)
  • Unique per machine + user combination
  • No registration or account needed

Tunnel Connector Agent

The Tunnel Connector gives you a real interactive shell on a machine that has no public IP — behind NAT/CGNAT or with only a LAN address. The agent dials outbound to the relay over WSS (443), so nothing needs to be opened on the remote box. You then open a Connector session in the terminal and get a normal shell (prompt, colors, TUI apps) — no SSH username or password required. Once enrolled, the agent auto-starts at every boot.
Not the same as the command Connector Agent above: that one runs one-shot commands; the Tunnel agent gives a live PTY shell. It reuses the same enrollment token / key.

Step 1: Download the Tunnel Agent

PlatformForShellSizeDownload
Linux x64Any 64-bit Linux (glibc). Self-contained, no runtime.real PTY (bash)35 MBDownload
Linux ARM64Raspberry Pi 64-bit, ARM servers.real PTY (bash)33 MBDownload
Windows x64Windows 10/11, Server 2019/2022 (64-bit). GUI app — double-click, paste token, Connect.ConPTY (full ANSI)69 MBDownload
Windows ARM64Windows 11 ARM, Surface Pro X. GUI app.ConPTY (full ANSI)65 MBDownload
Windows 7/8Windows 7 SP1 / 8 (32- or 64-bit). Uses built-in .NET Framework 4.5+. GUI app.command shell36 KBDownload
AndroidAndroid 7.0+ (API 24). Universal APK — arm64, arm32 and x86_64 in one file. App — install, paste token, Connect.real PTY (mksh)4.7 MBDownload

The .NET 8 builds are single-file and self-contained (no runtime to install). The tiny Windows 7/8 build uses the .NET Framework that ships with Windows.

Step 2: Get an Enrollment Token

A new machine must be authorized once. Open Agents & Connector (or the button, top-right of the Terminal) and copy a one-time token (NS-…) or your permanent key (nse_…).

Step 3: Install on Linux

One-liner — download, enroll, and enable start-at-boot in one go (pick linux-x64 or linux-arm64):

# 64-bit x86 Linux
sudo curl -fsSL https://app.nebulassh.com/api/connector/download-tunnel-agent/linux-x64 \
  -o /usr/local/bin/nebulassh-tunnel-agent
sudo chmod +x /usr/local/bin/nebulassh-tunnel-agent

# First run: enrolls the machine + installs a systemd service (auto-start on boot) + connects
sudo /usr/local/bin/nebulassh-tunnel-agent --enroll-token NS-XXXXX-XXXXX-XXXXX-XXXXX

# ARM64? swap the URL for .../download-tunnel-agent/linux-arm64

Or use the guided installer (downloads the right arch, enrolls, enables the service):

curl -fsSL https://app.nebulassh.com/api/connector/download-tunnel-agent/install-linux -o install-linux.sh
chmod +x install-linux.sh
sudo NEBULASSH_ENROLL_TOKEN=NS-XXXXX-XXXXX-XXXXX-XXXXX ./install-linux.sh

Run as root → a system-wide systemd service (nebulassh-tunnel-agent.service, starts at boot). Run as a normal user → a per-user service (with linger enabled so it survives logout). The agent writes the unit itself when you pass --install (the first run does this automatically).

Manual control
nebulassh-tunnel-agent --id            # print this machine's Agent ID
nebulassh-tunnel-agent --run           # run in the foreground
nebulassh-tunnel-agent --install       # just enable start-at-boot and exit
nebulassh-tunnel-agent --uninstall     # remove start-at-boot
nebulassh-tunnel-agent --no-autostart  # run once without enabling boot start

# systemd (system service)
sudo systemctl status  nebulassh-tunnel-agent
sudo journalctl -u nebulassh-tunnel-agent -f
sudo systemctl restart nebulassh-tunnel-agent

# systemd (per-user service)
systemctl --user status nebulassh-tunnel-agent

Step 3 (Windows): Install

Download the matching build above, then from PowerShell:

# Windows 10/11 (x64) — enrolls, enables start-at-logon (HKCU Run), and connects
.\nebulassh-tunnel-agent-win-x64.exe --enroll-token NS-XXXXX-XXXXX-XXXXX-XXXXX

# Windows 7/8 — same flags, uses the built-in .NET Framework
.\nebulassh-tunnel-agent-win7.exe --enroll-token NS-XXXXX-XXXXX-XXXXX-XXXXX

Prefer a script? Download install-windows.ps1 and run .\install-windows.ps1 -EnrollToken NS-… (add -Framework on Windows 7/8). On Windows 10+/Linux you get a real PTY (full-screen apps work); on Windows 7/8 it's a plain command shell.

Step 4: Connect from the Web UI

  1. After enrolling, the machine appears under Agents & Connector and comes online.
  2. In the terminal, click New Session → the Connector tab.
  3. Type the Agent ID (e.g. 510-393-156-936) — or pick it from your agents list — and click Connect (or Save it as a reusable session).
  4. You get an interactive shell — no host, no IP, no SSH credentials.
The shell runs as whoever the agent runs as. Enrollment binds the agent to your account, and the web app additionally checks that you own the agent before opening the shell.
Built-in file browser (SFTP). A Connector session also gives you a file browser in the sidebar — browse, upload, download, edit, rename and delete files on the remote machine, just like an SSH session. It's served over the same tunnel (the agent's local filesystem), so no SSH server or credentials are needed on the box. Re-download the agent if you enrolled an older build.
Windows agents are a GUI app — no command line needed. Just double-click the downloaded .exe, paste your enrollment token into the window, and click Connect. It keeps running in the system tray and reconnects on every reboot. (The command-line flags below still work for scripted installs.)

Connect an AI agent to the Tunnel Connector

Just like you can point an AI at a command agent, an AI assistant (or any script) can drive a Tunnel Connector machine with nothing but its Agent ID and your API key (nsk_… from Agents & Connector). One call runs a command and returns its output — no interactive browser, no IP.

Tell your AI: “Connect to my NebulaSSH tunnel connector. My ID is 510-393-156-936 and my API key is nsk_….” — then it uses one of the methods below. Every call is ownership-checked, so a key only ever reaches the agents it owns.
1. HTTP — works for any AI/tool that can call an API
# Run a command on the tunnel machine and get its output back
curl -s -X POST https://app.nebulassh.com/api/connector/tunnel-exec \
  -H "X-Api-Key: nsk_XXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{"agentId":"510-393-156-936","command":"whoami && uname -a","shell":"auto"}'
# → {"output":"root\nLinux …\n","error":"","exitCode":0}
  • shell: auto (bash on Linux / PowerShell on Windows), or bash/cmd/powershell. Optional.
  • timeoutSeconds: 1–300 (default 60). Auth via X-Api-Key or Authorization: Bearer <key>.
  • 404 = that agent has no live tunnel (not a Tunnel Connector agent, or offline). List yours: GET /api/connector/agents.

tunnel-exec is the recommended one-shot call — it blocks until the command finishes and returns the output in the same response.

Using the classic queue flow? The generic POST /api/connector/execute → poll GET /api/connector/result/{commandId} pattern (the one most AI agents reach for by default) also works on Tunnel Connector agents: the server detects the live tunnel, runs the command over it, and fills in the result so your poll completes normally. Either style is fine — but for a one-shot command, tunnel-exec saves you the polling loop.
# Classic queue + poll (works for tunnel AND classic agents)
CID=$(curl -s -X POST https://app.nebulassh.com/api/connector/execute \
  -H "X-Api-Key: nsk_XXXX" -H "Content-Type: application/json" \
  -d '{"agentId":"510-393-156-936","command":"uname -a","shell":"bash"}' | jq -r .commandId)

curl -s https://app.nebulassh.com/api/connector/result/$CID -H "X-Api-Key: nsk_XXXX"
# → {"isCompleted":true,"output":"Linux …\n","error":"","exitCode":0}

If result stays {"isCompleted":false} forever, the agent on that box is an older tunnel build without command support — re-download the latest agent (above) and it will respond.

2. The nebulassh CLI
curl -fsSL https://app.nebulassh.com/api/connector/cli -o nebulassh && chmod +x nebulassh
export NEBULASSH_API_KEY=nsk_XXXXXXXXXXXXXXXXXXXX

./nebulassh agents                                    # list your agents
./nebulassh exec 510-393-156-936 "df -h && free -h"   # works for tunnel AND classic agents
./nebulassh tunnel-exec 510-393-156-936 "uptime"      # force the tunnel path

exec tries the tunnel first and falls back to the classic command connector, so the same command works for either agent kind.

3. MCP server (Claude and other MCP clients)

The bundled MCP server (connector/nebulassh-mcp) exposes tools an assistant can call directly: list_agents, run_command (works for both agent kinds), tunnel_exec, generate_enrollment_token, and more. Point your MCP client at the server's /mcp endpoint and send the key as Authorization: Bearer nsk_…; then just ask it to run a command on the agent ID.

The target must run the Tunnel Connector agent (a build with exec support — re-download if you installed a very early one). Also, the agent and the API you call must be the same NebulaSSH server (tunnels are held in memory per instance): if the agent’s --relay is app.nebulassh.com, call app.nebulassh.com.

Linux Setup (Fresh PC)

This guide covers everything needed to connect from a fresh Linux installation to a Windows PC running the NebulaSSH Agent. Only curl and python3 are required.

Step 1: Install Dependencies

Run these commands on a fresh Ubuntu/Debian Linux machine:

# Update package list
sudo apt update

# Install curl (HTTP client for API communication)
sudo apt install -y curl

# Install python3 (JSON parsing for CLI tool)
sudo apt install -y python3

# Optional: Install ca-certificates (for HTTPS/SSL)
sudo apt install -y ca-certificates

For CentOS/RHEL/Fedora:

sudo yum install -y curl python3 ca-certificates

For Arch Linux:

sudo pacman -S curl python ca-certificates

Step 2: Verify Installation

curl --version      # Must show version 7.x or 8.x
python3 --version   # Must show 3.6+

Step 3: Set Relay Server

# Set relay URL (add to ~/.bashrc for persistence)
export NEBULASSH_RELAY=https://app.nebulassh.com

# Make permanent
echo 'export NEBULASSH_RELAY=https://app.nebulassh.com' >> ~/.bashrc
source ~/.bashrc

Step 4: Test Connectivity

# Verify the relay is reachable (public endpoint — no key needed)
curl -sI https://app.nebulassh.com/api/connector/cli | head -1
# Should show: HTTP/2 200

# Listing agents now requires your API key (X-Api-Key); without it you get 401
curl -s -H "X-Api-Key: $NEBULASSH_API_KEY" https://app.nebulassh.com/api/connector/agents
# Returns your agents as JSON ([] if none). Get the key from Dashboard -> Agents & Connector.

One-Shot Setup (Copy-Paste)

Run this single block on a brand new Linux machine to install everything:

sudo apt update && sudo apt install -y curl python3 ca-certificates && \
echo 'export NEBULASSH_RELAY=https://app.nebulassh.com' >> ~/.bashrc && \
export NEBULASSH_RELAY=https://app.nebulassh.com && \
echo "Setup complete! Now install the CLI tool (see next section)"

CLI Tool (Copy & Install)

Copy the script below (it includes API-key auth), or use the one-liner download further down to always pull the current version. Either way, the connector requires your API key (X-Api-Key) for control-plane calls — set NEBULASSH_API_KEY before running nebulassh agents/exec.

Install Method: Copy Script

Create the file and paste the script:

#!/bin/bash
#
# NebulaSSH CLI Client
# Remote command execution on Windows PCs via relay server
#
# Usage:
#   nebulassh agents                                    - List connected agents
#   nebulassh exec 123-456-789 "hostname"              - Run via PowerShell (default)
#   nebulassh exec 123-456-789 "dir C:\" cmd           - Run via CMD
#   nebulassh shell 123-456-789                        - Interactive shell mode
#

RELAY_URL="${NEBULASSH_RELAY:-https://app.nebulassh.com}"
API_KEY="${NEBULASSH_API_KEY:-}"
POLL_INTERVAL=1
MAX_WAIT=120

require_key() {
    if [ -z "$API_KEY" ]; then
        echo -e "${RED}[ERROR]${NC} Set NEBULASSH_API_KEY first."
        echo "Get your key from the NebulaSSH dashboard -> Agents & Connector."
        exit 1
    fi
}

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

print_banner() {
    echo -e "${CYAN}"
    echo ' _   _      _           _        ____ ____  _   _ '
    echo '| \ | | ___| |__  _   _| | __ _ / ___/ ___|| | | |'
    echo '|  \| |/ _ \ '\''_ \| | | | |/ _` |\___ \___ \| |_| |'
    echo '| |\  |  __/ |_) | |_| | | (_| | ___) |__) |  _  |'
    echo '|_| \_|\___|_.__/ \__,_|_|\__,_||____/____/|_| |_|'
    echo -e "${NC}"
    echo -e "  ${BOLD}NebulaSSH CLI Client${NC} - Remote Windows Command Execution"
    echo ""
}

cmd_agents() {
    require_key
    echo -e "${BOLD}Your Agents:${NC}"
    echo ""
    response=$(curl -s -H "X-Api-Key: ${API_KEY}" "${RELAY_URL}/api/connector/agents")
    if [ -z "$response" ] || [ "$response" = "[]" ]; then
        echo -e "  ${YELLOW}No agents connected.${NC}"
        return
    fi
    echo -e "  ${BOLD}ID                  Machine          OS                          User        Status${NC}"
    echo "  ────────────────────────────────────────────────────────────────────────────────────────────"
    echo "$response" | python3 -c "
import sys, json
agents = json.load(sys.stdin)
for a in agents:
    aid = a.get('agentId', 'N/A')
    machine = a.get('machineName', 'N/A')[:16]
    os_ver = a.get('osVersion', 'N/A')[:28]
    user = a.get('username', 'N/A')[:10]
    online = 'Online' if a.get('isOnline') else 'Offline'
    print(f'  {aid:<20}{machine:<17}{os_ver:<30}{user:<12}{online}')
" 2>/dev/null
    echo ""
}

cmd_exec() {
    local agent_id="$1"
    local command="$2"
    local shell="${3:-powershell}"
    if [ -z "$agent_id" ] || [ -z "$command" ]; then
        echo -e "${RED}Usage: nebulassh exec <agent-id> <command> [powershell|cmd]${NC}"
        return 1
    fi
    require_key
    echo -e "${CYAN}[NebulaSSH]${NC} Sending to ${BOLD}${agent_id}${NC} (${shell}): ${command}"
    echo ""
    response=$(curl -s -X POST "${RELAY_URL}/api/connector/execute" \
        -H "Content-Type: application/json" \
        -H "X-Api-Key: ${API_KEY}" \
        -d "{\"agentId\":\"${agent_id}\",\"command\":\"${command}\",\"shell\":\"${shell}\"}")
    command_id=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin).get('commandId',''))" 2>/dev/null)
    if [ -z "$command_id" ]; then
        error=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin).get('error','Unknown error'))" 2>/dev/null)
        echo -e "${RED}[ERROR]${NC} ${error}"
        return 1
    fi
    waited=0
    while [ $waited -lt $MAX_WAIT ]; do
        result=$(curl -s -H "X-Api-Key: ${API_KEY}" "${RELAY_URL}/api/connector/result/${command_id}")
        is_completed=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('isCompleted', False))" 2>/dev/null)
        if [ "$is_completed" = "True" ] || [ "$is_completed" = "true" ]; then
            echo "$result" | python3 -c "
import sys, json
r = json.load(sys.stdin)
output = r.get('output', '')
error = r.get('error', '')
exit_code = r.get('exitCode', -1)
if output:
    print(output.rstrip())
if error:
    print('\033[0;31m' + error.rstrip() + '\033[0m')
print(f'\n\033[0;36m[NebulaSSH]\033[0m Exit code: {exit_code}')
" 2>/dev/null
            return 0
        fi
        sleep $POLL_INTERVAL
        waited=$((waited + POLL_INTERVAL))
        printf "\r  Waiting... %ds" "$waited"
    done
    echo ""
    echo -e "${RED}[TIMEOUT]${NC} Command did not complete within ${MAX_WAIT}s"
    return 1
}

cmd_shell() {
    local agent_id="$1"
    if [ -z "$agent_id" ]; then
        echo -e "${RED}Usage: nebulassh shell <agent-id>${NC}"
        return 1
    fi
    echo -e "${GREEN}[NebulaSSH Shell]${NC} Connected to ${BOLD}${agent_id}${NC}"
    echo -e "Prefix with ${BOLD}cmd:${NC} to use CMD. Type ${BOLD}exit${NC} to quit."
    echo ""
    while true; do
        echo -ne "${GREEN}nebulassh@${agent_id}${NC}> "
        read -r input
        [ -z "$input" ] && continue
        [ "$input" = "exit" ] || [ "$input" = "quit" ] && { echo -e "${CYAN}[NebulaSSH]${NC} Disconnected."; break; }
        shell="powershell"
        command="$input"
        if [[ "$input" == cmd:* ]]; then
            shell="cmd"
            command="${input#cmd:}"
            command="$(echo "$command" | sed 's/^ *//')"
        fi
        cmd_exec "$agent_id" "$command" "$shell"
        echo ""
    done
}

case "${1}" in
    agents|list|ls)
        print_banner
        cmd_agents
        ;;
    exec|run|e)
        cmd_exec "$2" "$3" "$4"
        ;;
    shell|sh|connect)
        print_banner
        cmd_shell "$2"
        ;;
    --relay|-r)
        RELAY_URL="$2"
        shift 2
        exec "$0" "$@"
        ;;
    --help|-h|help|"")
        print_banner
        echo "Usage: nebulassh <command> [options]"
        echo ""
        echo "Commands:"
        echo "  agents                                  List all connected Windows agents"
        echo "  exec  <agent-id> <command> [shell]      Execute a command (shell: powershell|cmd)"
        echo "  shell <agent-id>                        Interactive shell session"
        echo ""
        echo "Agent ID format: XXX-XXX-XXX (hardware-bound, persistent)"
        echo ""
        echo "Environment:"
        echo "  NEBULASSH_API_KEY  Your control-plane API key (required). Dashboard -> Agents & Connector."
        echo "  NEBULASSH_RELAY    Relay server URL (default: https://app.nebulassh.com)"
        echo ""
        echo "Examples:"
        echo "  nebulassh agents"
        echo "  nebulassh exec 123-456-789 \"Get-Process\" powershell"
        echo "  nebulassh exec 123-456-789 \"ipconfig /all\" cmd"
        echo "  nebulassh shell 123-456-789"
        echo ""
        ;;
    *)
        echo -e "${RED}Unknown command: $1${NC}"
        echo "Run 'nebulassh --help' for usage."
        exit 1
        ;;
esac

Quick Install Commands

After copying the script above, run:

# Save the script (paste copied content)
sudo nano /usr/local/bin/nebulassh
# (Paste the script, then Ctrl+X, Y, Enter)

# Make executable
sudo chmod +x /usr/local/bin/nebulassh

# Verify installation
nebulassh --help

One-Liner Install (Download from Server)

# Download and install CLI tool directly
curl -s https://app.nebulassh.com/api/connector/cli -o /usr/local/bin/nebulassh && \
chmod +x /usr/local/bin/nebulassh && \
nebulassh --help

For AI / Claude Code

If Claude Code (CLI AI) is installed on the Linux machine, it can use the tool directly or call the API with curl. It needs curl, the relay URL, and your API key (NEBULASSH_API_KEY / X-Api-Key).

# AI can use the CLI tool (export NEBULASSH_API_KEY first)
nebulassh exec 123-456-789-012 "Get-Process"

# Or call API directly with curl (the API key is required)
curl -s -X POST https://app.nebulassh.com/api/connector/execute \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $NEBULASSH_API_KEY" \
  -d '{"agentId":"123-456-789-012","command":"hostname","shell":"powershell"}'

Connect from Linux

Option A: CLI Client

# Set relay server
export NEBULASSH_RELAY=https://app.nebulassh.com

# Set your API key (required) - get it from Dashboard -> Agents & Connector
export NEBULASSH_API_KEY=nsk_your_key_here

# List the agents you own
./nebulassh agents

# Execute a command (PowerShell - default)
./nebulassh exec 123-456-789-012 "Get-Process | Select -First 5"

# Execute a command (CMD)
./nebulassh exec 123-456-789-012 "ipconfig /all" cmd

# Interactive shell session
./nebulassh shell 123-456-789-012

Option B: Claude CLI (AI)

If you have Claude CLI installed, simply tell it in natural language:

> Connect to NebulaSSH agent 123-456-789-012 and show me running services

> Check disk space on agent 456-789-012-345

> Run "Get-EventLog -LogName System -Newest 10" on agent 123-456-789-012

Option C: Direct API (curl)

# All control-plane calls require your API key (X-Api-Key header).
KEY="nsk_your_key_here"

# List the agents you own
curl -s -H "X-Api-Key: $KEY" https://app.nebulassh.com/api/connector/agents

# Send a command
curl -s -X POST https://app.nebulassh.com/api/connector/execute \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $KEY" \
  -d '{"agentId":"123-456-789-012","command":"hostname","shell":"powershell"}'
# Returns: {"commandId":"abc123def456"}

# Get result (poll until isCompleted is true)
curl -s -H "X-Api-Key: $KEY" https://app.nebulassh.com/api/connector/result/abc123def456
# Returns: {"isCompleted":true,"output":"DESKTOP-PC\n","error":"","exitCode":0}

Common Commands

System Information

nebulassh exec ID "systeminfo"
nebulassh exec ID "hostname"
nebulassh exec ID "whoami"
nebulassh exec ID "[System.Environment]::OSVersion"

Network

nebulassh exec ID "ipconfig /all" cmd
nebulassh exec ID "netstat -an" cmd
nebulassh exec ID "Get-NetIPAddress | Format-Table"
nebulassh exec ID "Test-NetConnection google.com -Port 443"

Processes & Services

nebulassh exec ID "Get-Process | Sort-Object CPU -Descending | Select -First 10"
nebulassh exec ID "Get-Service | Where-Object Status -eq Running"
nebulassh exec ID "tasklist" cmd

Disk & Files

nebulassh exec ID "Get-PSDrive -PSProvider FileSystem"
nebulassh exec ID "dir C:\" cmd
nebulassh exec ID "Get-ChildItem C:\Users -Recurse -Depth 1"

Event Logs

nebulassh exec ID "Get-EventLog -LogName System -Newest 5"
nebulassh exec ID "Get-EventLog -LogName Application -EntryType Error -Newest 10"

Installed Software

nebulassh exec ID "Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select DisplayName, DisplayVersion | Sort DisplayName"

File Transfer via Agent

Upload files from your machine to a remote Windows PC, or download files from a remote Windows PC — all through the Connector Agent. No direct network access needed.

How It Works

Upload (You → Agent):
  1. You upload file to app.nebulassh.com with agent ID + destination path
  2. Agent picks up the file during its next poll cycle
  3. Agent saves the file to the specified path

Download (Agent → You):
  1. You request a file from the agent with the remote file path
  2. Agent reads the file and uploads it to app.nebulassh.com
  3. You download the file from app.nebulassh.com

Upload a File to Agent

# Upload a file to the agent's C:\Temp folder
curl -X POST https://app.nebulassh.com/api/connector/upload \
  -F "agentId=123-456-789-012" \
  -F "remotePath=C:\Temp\myfile.zip" \
  -F "file=@/path/to/local/myfile.zip"

# Response:
# { "transferId": "abc123def456", "fileName": "myfile.zip", "fileSize": 1048576 }

Download a File from Agent

# Step 1: Request the file
curl -X POST https://app.nebulassh.com/api/connector/download \
  -H "Content-Type: application/json" \
  -d '{"agentId":"123-456-789-012","remotePath":"C:\\Users\\admin\\Documents\\report.pdf"}'

# Response:
# { "transferId": "xyz789abc012" }

# Step 2: Poll until ready
curl -s https://app.nebulassh.com/api/connector/transfer/xyz789abc012/status
# { "isCompleted": true, "isError": false, "fileName": "report.pdf", "fileSize": 204800 }

# Step 3: Download the file
curl -o report.pdf https://app.nebulassh.com/api/connector/transfer/xyz789abc012/content

Check Transfer Status

curl -s https://app.nebulassh.com/api/connector/transfer/{transferId}/status

# Response:
{
  "transferId": "abc123def456",
  "type": "upload",          // "upload" = sending to agent, "download" = getting from agent
  "isCompleted": true,
  "isError": false,
  "errorMessage": null,
  "fileName": "myfile.zip",
  "fileSize": 1048576
}

Notes

  • The agent polls every 2 seconds, so transfers start almost immediately
  • Maximum file size depends on available server memory (files are held in memory during transfer)
  • The agent must be online when you initiate the transfer
  • Directories on the agent are created automatically if they don't exist
  • For folder transfers, zip the folder first, upload, then extract via a command

API Reference

Base URL: https://app.nebulassh.com/api/connector

Agent-Side Endpoints

MethodEndpointDescriptionAuth
POST/registerRegister agent, get unique IDX-Enroll-Token (new agents)
POST/heartbeatHeartbeat + fetch pending commandsHeaders
POST/resultSubmit command outputHeaders
POST/disconnectUnregister agentHeaders

Auth Headers: X-Agent-Id and X-Agent-Token (received during registration)

Client-Side Endpoints

All client-side endpoints require your API key via the X-Api-Key header (or Authorization: Bearer), or a logged-in session cookie. Each call is scoped to the agents you own.

MethodEndpointDescription
GET/agentsList the agents you own
POST/executeSend command to an agent you own
GET/result/{commandId}Get command result
POST/enroll-tokenGenerate a one-time enrollment token
POST/agents/{agentId}/releaseRelease (un-claim) an agent you own
GET/api-keyGet your current API key
POST/api-key/regenerateRegenerate your API key

File Transfer Endpoints

MethodEndpointDescription
POST/uploadUpload file to send to agent (multipart form)
POST/downloadRequest file download from agent
GET/transfer/{id}/statusCheck transfer status
GET/transfer/{id}/contentDownload completed file

File Transfer (Agent-Side)

MethodEndpointDescriptionAuth
GET/transfersGet pending file transfersHeaders
GET/transfer/{id}/dataDownload file data (for upload transfers)Headers
POST/transfer/{id}/dataUpload file data (for download transfers)Headers
POST/transfer/{id}/completeReport transfer success/failureHeaders

Example: Execute Command

# POST /api/connector/execute
# Header: X-Api-Key: nsk_your_key_here
{
  "agentId": "123-456-789-012",
  "command": "Get-Process",
  "shell": "powershell"
}

# Response
{ "commandId": "abc123def456" }

# GET /api/connector/result/abc123def456
{
  "isCompleted": true,
  "output": "Handles  NPM(K)  PM(K) ...",
  "error": "",
  "exitCode": 0
}

MCP Server (AI Agents)

The NebulaSSH MCP server lets an MCP client — Claude Desktop, Claude Code, and other AI tools — list and remotely drive your agents through the connector API. It speaks the Model Context Protocol over HTTP and forwards your API key, so it only ever touches the agents you own.

Tools exposed

ToolWhat it does
list_agentsList the agents you own and their online status
run_commandRun a command on an agent and wait for the output
execute_commandQueue a command and return a commandId immediately
get_command_resultFetch the result of a queued command
generate_enrollment_tokenMint a one-time token to enroll a new agent
release_agentRemove an agent from your account

Connect from Claude Code

Add it as an HTTP MCP server, passing your API key as a bearer header:

# .mcp.json (or: claude mcp add)
{
  "mcpServers": {
    "nebulassh": {
      "type": "http",
      "url": "https://mcp.nebulassh.com/mcp",
      "headers": { "Authorization": "Bearer nsk_your_api_key_here" }
    }
  }
}

Then just ask in natural language, e.g. "list my NebulaSSH agents" or "run Get-Process on agent 123-456-789-012".

Self-host the MCP server

The server ships in connector/nebulassh-mcp/ (Node.js 18+). Build and run it, then put it behind TLS:

cd connector/nebulassh-mcp
npm install && npm run build
cp .env.example .env          # set NEBULASSH_RELAY / PORT
npm start                     # POST http://localhost:8848/mcp

It's stateless and multi-user: each request carries its own API key, so one instance can serve everyone. See the project README for the systemd unit and nginx config.

Troubleshooting

ProblemSolution
Agent shows [FATAL] HTTP ErrorCheck internet connection. Verify the relay URL is reachable.
Agent shows Could not connectEnsure https://app.nebulassh.com is accessible from the Windows PC. Check firewall.
Agent not in agents listAgent may have timed out (5 min idle). Restart the agent.
Command times outCommands have a 120-second timeout. Break long operations into smaller steps.
Agent not found or offlineWrong agent ID or agent not running. Check with nebulassh agents.
SSL/Certificate errorsEnsure system date/time is correct on the Windows PC.
File transfer stuck / not completingAgent must be online. Check transfer status with /transfer/{id}/status. Ensure agent has write permissions to the target path.
Upload fails with "Agent not found"Agent is offline or wrong ID. Verify with /agents endpoint.
SSH terminal not connectingVerify host, port, and credentials. Ensure SSH is enabled on the remote server.
VNC Desktop disconnects immediatelyx11vnc is not installed on the remote server. SSH into the remote machine and run: sudo apt install -y x11vnc