
ShellCN
Self-hosted access gateway for SSH, files, containers, Kubernetes, databases, and remote desktops, with out-of-tree plugins and one audited UI.
Go, gRPC, Vue 3, PrimeVue, Tailwind, WebSockets, SQLite, Casbin +2
Reaching your own servers takes too many apps. A terminal for SSH, something else for file transfer, Docker Desktop, kubectl, a database client, an RDP window. Six tools, six copies of your passwords, and no record of who connected to what.
ShellCN replaces all of that with one page in your browser. You run a single program on your own machine, open it, and everything you log into is behind one login, one permission system, and one audit trail. It brokers access to your infrastructure. It does not host any of it.
What it reaches
Twenty protocols come built in: SSH and file transfer, Docker and Kubernetes and Proxmox, PostgreSQL and MySQL and MongoDB and Redis, remote desktops over VNC and RDP, plus LDAP and server monitoring.
Everything else arrives as a plugin. The maintained plugin repository already holds more than forty, from ClickHouse and Oracle to Kafka, Vault, Elasticsearch, and vector databases.

Why I built it
Every one of those tools stores its own credentials, and none of them can tell you afterwards who opened what. That is fine for one person on one laptop. It stops being fine the moment a second person needs access, or a client asks what happened last Tuesday.
I wanted one process holding the credentials, one place to say who can do what, one log, and session recording where a connection warrants it.
Everything is a plugin, including the built-in ones
The trick that keeps this from becoming twenty special cases is that every protocol is written the same way, built-ins included.
A protocol describes itself in a single file: what it connects to, what settings it needs, what panels it shows, and what actions it offers. The core owns everything else. Routing, sessions, login, permissions, secrets, and audit are written once and apply to every protocol without the protocol author touching them.
Adding a new one is a single Go package and one line in a registry. No frontend changes at all, because the interface builds itself from that description file. It fetches the description, lays out the workspace, and fills it from a fixed set of components: a terminal, a table, a file browser, a query editor, a remote desktop view, and about a dozen more.

The same table component for SQL and MongoDB
The same table component that renders SQL results renders MongoDB documents, and neither plugin knows about the other.

The part I spent the most care on
Third-party plugins are the interesting risk. Anyone can write one, and it runs on your gateway, next to your credentials.
So a plugin from outside the project runs as its own separate program, talking to the gateway over a defined channel. It opens no network connections of its own, touches no database, and writes no audit entries. Every action with real consequences is a request back to the core, which checks permission, applies the connection's network route, and writes the log itself. A plugin author writes protocol logic and nothing else.
Two things follow from that. A plugin crash becomes a brief unavailability rather than a missing protocol, because the supervisor restarts it and swaps the connection underneath while the registration stays in place. And an update needs no gateway restart: start the new version, check it, swap it in, drain the old sessions, stop the old process.
Distribution gets the same treatment. A plugin is submitted as one file listing its download URLs and a checksum per platform. Continuous integration verifies the checksums and actually loads the binary before a submission can be merged, then re-publishes the files from the registry so an upstream author deleting a release breaks nobody. The marketplace shows a summary taken from the verified binary itself rather than text the submitter typed, so the permissions you review are the ones the code actually asks for. The gateway checks the checksum again at install.
Getting to machines you cannot reach directly
Plenty of servers sit behind a firewall with no way in. A connection either dials out from the gateway, or a small agent inside the private network dials back and holds one tunnel open.
Plugins never know which one is in use. The core hands each protocol whatever kind of connection it expects, and the tunnel carries it either way.

Permissions, audit, and recording
Stored passwords are encrypted, write-only through the interface, and stripped from logs. Credentials are records in their own right, so someone can connect through a credential without ever seeing its value, and rotating it means editing one record instead of every connection that used it.
Every action carries a risk level: safe, write, destructive, or privileged. That makes rules expressible in terms people actually use, such as Docker socket access being privileged by default, or a destructive database statement needing confirmation. Admin is a role for managing users, not a master key. An admin gets no access to anyone else's connections, credentials, or recordings.
Recording is off unless a protocol asks for it, and the core never starts recording just because a panel happens to be a terminal. Recordings stay private to the person who made them.
What is not solved
Remote desktops are decoded on the server and streamed to the browser. The Go library that decodes RDP is licensed GPL-3.0, which puts the whole gateway under GPL-3.0 as well. That was the price of keeping everything in one binary, and I took it deliberately.
Running several gateway instances works, but there is no automatic failover. If the instance holding a live session dies, that session dies with it and reconnects on next use.
Plugin trust is half solved. Checksums and verified summaries cover integrity and review. Signing and provenance for third-party plugins are still open. Login through OIDC, SAML and LDAP is still ahead.
Stack
Go for the gateway, with pure Go database drivers so the binary needs no C toolchain. Vue 3 and TypeScript for the interface, xterm.js for terminals, noVNC for desktops. Casbin for permissions, AES-256-GCM for stored secrets, gRPC for external plugins. Terminal sessions record in asciicast format.