April 2026·workspace tooling·
sshfile managerdockerself-hosted

A browser-based server console with a real file explorer, SSH tabs, and Docker controls

Konek turns the browser into a small ops desk. Instead of juggling SSH, SFTP, log tails, and container commands across different tools, I built one workspace that can browse remote files, open tabbed terminals, inspect processes, and manage containers from the same session.

konek · dashboard
lab-node · online
Explorer
/srv/media
frontend
backend
docker-compose.yml
logs
ops-01dockerlogs
$ docker ps
konek-backend        Up 3 days
konek-frontend       Up 3 days

$ ls -la /srv/media
drwxr-xr-x frontend  backend  logs

$ tail -n 3 /var/log/nginx/access.log
CONTEXT

SSH is enough until you need the whole machine.

Terminal access solves one layer of remote work, but not the rest of it. The moment I want to browse directories, inspect uploads, open a config file, watch container status, or wake a sleeping box on the LAN, the workflow usually explodes into five separate tools.

Konek compresses that into one browser surface. The frontend is a Vue 3 and Vite workspace with xterm tabs, Monaco editing, and a dedicated file manager. The backend is a Hono service that owns the SSH session, proxies file operations, tracks terminal tabs, and exposes Docker, process, and host actions behind one auth layer.

OVERVIEW

One browser tab, several admin surfaces.

The point was not to clone a full desktop. It was to make the common server tasks feel contiguous: file browsing, SSH commands, container operations, metrics, recent activity, and media tooling all under one session-aware UI.

The file manager is not cosmetic. It lists remote directories over SSH, supports uploads, delete and archive actions, opens text files in Monaco, and handles media preview. The terminal area keeps multiple tabs alive, so logs and shell commands can stay open while the rest of the interface keeps moving.

Stack
Vue 3ViteHonoTypeScriptssh2xterm.jsMonaco Editorbetter-sqlite3DrizzleDocker Engine
9backend routes
32frontend components
15composables
6backend services
notable detail The backend keeps the SSH connection and terminal tabs stateful, so the browser UI can switch between files, metrics, and shell output without re-establishing a new session for every click.
SURFACES

The useful parts of a remote desktop without pretending to be one.

01

File manager

Browse remote directories, search the current path, upload files, archive selections, delete entries, open text in Monaco, and preview media without dropping back to a separate SFTP client.

02

Tabbed SSH terminal

Keep multiple shells alive at once. One tab can tail logs, another can run Docker commands, and another can stay in an interactive shell without forcing the whole interface to behave like a terminal app.

03

Docker and process tooling

Container state, logs, process inspection, and quick operational actions live alongside the terminal instead of behind a second admin panel.

04

Host actions

The host list keeps session context, online checks, and Wake-on-LAN in one place, which makes the tool useful before the SSH connection even exists.

ARCHITECTURE

The browser talks to one API, the API fans into one owned SSH session.

01
Browser UIVue workspace
02
HTTP layerHono API
03
Session stateowned terminal + SSH tabs
04
Transportssh2 client channel
05
Targetremote Linux host

File operations stay plain on purpose.

The file route translates a browser action into a straightforward shell listing on the remote host. That keeps the UI responsive while staying grounded in the real filesystem instead of a copied mirror or sync cache.

backend/src/routes/files.ts
GET /api/files/list?sessionId=abc123&path=/srv/media
session.client.exec('ls -la --time-style=long-iso /srv/media')

frontend
backend
logs

Terminal tabs are first-class, not a single giant console.

The terminal panel keeps multiple tabs alive, which matters when one pane is tailing logs, another is in a shell, and a third is poking Docker. The UI chooses the active terminal tab, but the backend owns the lifecycle.

frontend/src/components/ssh-terminal/SshTabbedTerminal.vue
listTerminalTabs(sessionId)
createTerminalTab(sessionId)
closeTerminalTab(sessionId, tabId)

activeTabId stays in the browser
tab state stays on the server
LEARNINGS

The win is not complexity. The win is fewer tool switches.

01

Remote tooling becomes coherent when the backend owns the session state. That lets the frontend switch surfaces quickly without renegotiating the connection every time.

02

A file explorer and a terminal should complement each other, not compete. The terminal is still the escape hatch, but the explorer removes low-value command churn.

03

The fastest path is usually small primitives glued together well: SSH, shell commands, focused endpoints, and a UI that exposes the right actions without pretending to be magic.

Konek is the kind of project that gets more valuable the more boring the interaction becomes. Open the browser, pick a host, browse files, open a shell, inspect containers, and get out. That is the whole pitch.