# Sshwifty: a browser-based SSH and Telnet client you self-host

> Sshwifty turns SSH and Telnet into a web application: a Go backend opens the remote connection and a Vue front end renders the terminal in the browser. It suits operators who want browser access to hosts without installing a client on every machine.

**nirui/sshwifty** — Web SSH & Telnet (WebSSH & WebTelnet client) 🔮

- Repository: https://github.com/nirui/sshwifty
- Website: https://sshwifty-demo.nirui.org
- Stars: 3,127 · Forks: 398
- Language: JavaScript
- License: AGPL-3.0
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/nirui-sshwifty

## What Sshwifty actually solves for browser SSH access

The README describes Sshwifty as "a SSH and Telnet client made for the Web", which means the terminal lives in a browser tab while the network connection is opened by a server-side process. That distinction matters. A browser cannot open a raw TCP socket to port 22, so something has to sit in the middle. Sshwifty is that middle layer, and it is the piece you deploy.

The audience is narrow but real. If you administer machines from a locked-down laptop, a tablet, or a jump host where you cannot install a terminal emulator, a URL and a password are a lower-friction entry point than distributing client software. The repository also carries the webssh, webssh2 and webtelnet topics, so the project positions itself in the same space as other browser terminal tools rather than as a desktop client.

Telnet support is the less common half. Most browser terminal projects stop at SSH. Sshwifty keeps Telnet alongside it, which is useful for network gear and legacy consoles that never spoke SSH, though the README does not discuss the security posture of sending Telnet credentials through this stack.

## Architecture: a Go backend, a Vue front end, and a WebSocket between them

The repository layout makes the split explicit. The application directory holds the Go backend, the ui directory holds the front end, and sshwifty.go is the entry point that produces the sshwifty binary. go.mod lists gorilla/websocket, golang.org/x/crypto and golang.org/x/net as the only direct dependencies, which tells you the terminal channel is a WebSocket and the SSH and Telnet protocol work comes from the Go crypto and net packages rather than a third-party SSH library.

On the front end, package.json names the project sshwifty-ui and pulls in @xterm/xterm with the fit, clipboard, unicode11, web-links and webgl addons. So the browser renders an xterm.js terminal, and the WebGL addon handles rendering acceleration. The build is webpack-based, with Vue 2.6.14 and vue-loader, and the output is bundled into the Go binary.

The data flow is therefore: browser terminal to WebSocket to Go process to SSH or Telnet connection to the target host. The configuration confirms this shape. DialTimeout limits how long the backend may spend connecting to a remote host, and the README states the maximum is bounded by the server ReadTimeout. Socks5, Socks5User and Socks5Password let the backend route those outbound connections through a proxy. The backend is the only component that touches the remote network.

## Installing Sshwifty with Docker and opening the login page

The README marks the Docker image as the recommended deployment path and offers prebuilt executables as an alternative, with the caveat that those executables come from an unsupervised automatic procedure and are not guaranteed to be tested by the authors. The image is niruix/sshwifty, and the README explicitly notes it is spelled with an x.

The command below starts the container, publishes port 8182, and restarts it unless stopped. After running it, the service listens on port 8182 of the Docker host and accepts traffic from all clients, including remote ones.

```bash
docker run --detach \
  --restart unless-stopped \
  --publish 8182:8182 \
  --name sshwifty \
  niruix/sshwifty:latest
```

If you want the instance reachable only from the Docker host, the README gives the loopback variant. This is the form to use when a reverse proxy is the only thing that should reach Sshwifty.

```bash
docker run --detach \
  --restart unless-stopped \
  --publish 127.0.0.1:8182:8182 \
  --name sshwifty \
  niruix/sshwifty:latest
```

When TLS should terminate on the container instead of a proxy, the README offers SSHWIFTY_DOCKER_TLSCERT and SSHWIFTY_DOCKER_TLSCERTKEY to import a certificate and key. It also states that in most situations where a reverse proxy or load balancer sits in front, TLS should terminate on the proxy rather than on the Sshwifty instance. That is the more conventional arrangement, and the README treats the environment variables as the fallback for when you do not want to set up Docker volumes.

Configuration comes from a file or from environment variables. The loader tries the default file paths first and falls back to environment variables when none are found. SSHWIFTY_CONFIG points at a specific file and, per the README, makes Sshwifty load configuration only from that file.

```bash
SSHWIFTY_CONFIG=./sshwifty.conf.json ./sshwifty
```

The repository ships sshwifty.conf.example.json as a starting point. Two keys decide who can reach the interface. HostName, when set, restricts access to the specified host; an empty value accepts requests from all hosts. SharedKey is the web interface access password, and setting it empty allows public access to the web interface by bypassing the Authenticate page. Those two keys are the first thing to review after the container starts, because the prebuilt image with no configuration file is not a locked-down deployment.

## Building from source, and what the README does not cover

For development, the README lists git, node with npm, and go as prerequisites, then gives a four-step build. The result is a sshwifty binary in the working directory.

```bash
git clone https://github.com/nirui/sshwifty
cd sshwifty
npm install
npm run build
```

The README points at the Dockerfile as the authoritative record of the full build procedure and says to consult it when compile or build issues appear. That is an honest admission that the four commands above are a summary, not the whole story. The Dockerfile confirms the shape: it installs build-essential, curl, git, nodejs, npm and golang-go, then runs npm install -g n to move to a stable Node release. If your local toolchain differs from what the image pins, the Dockerfile is the reference, not the README snippet.

The larger gap is around operations. The README documents SharedKey as a single web interface password, and nothing in the repository documentation describes per-user accounts, key-based authentication for the web layer, or session recording. The configuration schema references server-side hooks launched as external processes, with a HookTimeout and an SSHWIFTY_HOOK_DEADLINE environment variable carrying an RFC3339 deadline. The README's own warning is blunt: the hook process runs with the same system permission as Sshwifty, so it must be designed and operated securely. The visible text cuts off mid-sentence at "commandline injec", which reads as a warning about command line injection. Treat hooks as a sharp tool and read the full section in the repository before enabling them.

## Where Sshwifty is the wrong tool

The single shared password is the clearest limitation. If two people use the same Sshwifty instance, they present the same SharedKey, and the documentation describes no mechanism to tell them apart. Any environment that needs to attribute a session to a named person, or revoke one person's access without changing everyone's password, is outside what this configuration documents.

The second limitation is trust placement. Sshwifty's backend opens the connection to the remote host, so credentials for that host pass through the Sshwifty process. That is inherent to the design, not a defect, but it means the Sshwifty host sits inside your trust boundary. Running it on a shared or lightly administered machine moves the risk rather than removing it. The Socks5 options let you route outbound connections through a proxy, which helps with network placement, but they do not change who can reach the web interface.

Telnet deserves its own caution. The README treats Telnet as a supported protocol alongside SSH and does not describe any transport protection for it. Telnet is a cleartext protocol, and wrapping it in a web UI does not encrypt what the backend sends to the target. Use it for devices that have no alternative, not as a general-purpose path.

Finally, the prebuilt executables carry the README's own disclaimer that they are generated by an automatic procedure and not guaranteed to be tested. If your platform has a binary in the Releases section, that is convenient, but the authors are telling you the artifact is unverified.

## Alternatives and how their approach differs

Bastillion appears in the related searches, and the contrast is instructive. Bastillion is an SSH console that manages the target hosts itself, holding keys and access rules centrally. Sshwifty does not manage hosts. It gives the browser a terminal and dials whatever host the user types in, subject to HostName and the Socks5 settings. If your problem is "I need a browser terminal to a host I already know", Sshwifty fits directly. If your problem is "I need a central inventory of hosts with per-user key distribution", Sshwifty does not attempt it, and adding that layer means putting something else in front.

On the front end, the difference between Sshwifty and other browser terminals is mostly implementation language and packaging. Sshwifty compiles the UI into a single Go binary, which makes deployment a file copy or one container. Projects built on a Python stack, the kind that show up under webssh Python searches, typically need a Python runtime and a separate front-end asset step. Neither approach is better in the abstract. A single static binary is easier to drop onto a host; a Python or Node service is easier to patch in place if that is already how your environment works. The deciding factor is which runtime you already operate.

There is also the third-party Homebrew formula for macOS maintained by @unbeatable-101. The README is explicit that the Sshwifty authors provide no audit, warranty or support for it and that questions should go to that maintainer. If you are on macOS and want a packaged build, that is the route the README points to, with the caveat attached.

## Maintenance, licence and what to check before you commit

The repository is not archived, and the most recent release listed is 0.4.11-beta-release-prebuild, pushed on 2026-09-03. The two releases before it, 0.4.10 and 0.4.9, are dated 2026-08-19. The release names carry a beta marker, and the prebuild suffix indicates these are the automatically generated artifacts the README warns about. Treat the beta label as a signal about the stability guarantee you are getting, not as a reason to avoid the project, but do not assume a stable release channel exists in this list.

Upgrade cost is low if you deploy the container. Pulling a new image and restarting is the whole procedure, and the configuration file format is the thing that could change between versions. That is the argument for keeping your settings in sshwifty.conf.json and mounting it, rather than baking configuration into the image or passing a long list of environment variables. A file is easier to diff against sshwifty.conf.example.json after an upgrade.

The licence is AGPL-3.0, stated in the repository metadata and in the header of go.mod, which carries the full GNU Affero General Public License notice. The AGPL's distinguishing feature is the network clause: if you modify Sshwifty and let users interact with it over a network, the licence's terms reach that interaction in a way the plain GPL's do not. Running an unmodified copy for internal use is a different situation from shipping a modified version as a service. This is a real consideration for anyone planning to fork the UI. It is not legal advice, and if you are modifying and redistributing, read LICENSE.md and talk to someone qualified.

As for what to verify first: confirm that HostName is set to the name you actually serve, confirm SharedKey is not empty, and decide whether TLS terminates on your proxy or on the container. Those three decisions cover most of the exposure surface the README describes.

## Conclusion

Adopt Sshwifty when you need a browser entry point to SSH or Telnet hosts and you can run the backend on a host you already trust. Do not adopt it as a replacement for a hardened bastion with per-user audit, because the configuration shown here offers a single shared web password and no documented per-user accounts. Before exposing it, verify how HostName, SharedKey and your reverse proxy interact, and check the AGPL-3.0 obligations if you plan to modify and redistribute it.

## FAQ

### What do people use SSH for?

The README does not answer this directly. It describes Sshwifty as a client that lets you access SSH and Telnet services from a web browser, which is the use case the project itself addresses.

### Does anyone still use Telnet?

The README does not discuss Telnet usage trends. It does treat Telnet as a supported protocol alongside SSH, and the repository carries the webtelnet topic, so the project keeps a Telnet client available for hosts that need one.

### Is a SSH connection safe?

The README does not make security claims about SSH itself. What it does document is that the Sshwifty backend opens the remote connection, so host credentials pass through the Sshwifty process, and that the web interface is protected by the SharedKey option.

### Which SSH client is best?

The README does not compare clients. It positions Sshwifty as a web-based SSH and Telnet client, so the relevant distinction is that it runs in a browser instead of as a desktop or terminal application.

## Sources

- [License: AGPL-3.0](https://github.com/nirui/sshwifty/blob/master/LICENSE)
- [nirui/sshwifty on GitHub](https://github.com/nirui/sshwifty)
- [Project website](https://sshwifty-demo.nirui.org)
- [README](https://github.com/nirui/sshwifty/blob/master/README.md)
- [Releases](https://github.com/nirui/sshwifty/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nirui-sshwifty
