DEV Community

Cover image for I didn't want a web panel on my VPS, so I built a desktop for it over plain SSH
Tran Huu Dang
Tran Huu Dang

Posted on Edited on

I didn't want a web panel on my VPS, so I built a desktop for it over plain SSH

I look after a few Linux servers at work. Every day it's the same loop: check a container, tail a log, fix an nginx config, see why the disk is filling up.

Web panels like aaPanel make that easier, but they come with a cost I didn't want to pay: another port open to the internet, another login page for bots to hammer, and another piece of software running as root on a production box.

Typing everything by hand in a terminal works, but it's slow when you just want to look at things.

So I built Davish: a desktop app that manages servers entirely over SSH, with an interface that feels like an operating system: a menu bar, a dock, and windows for each tool.

Three rules I didn't want to break

1. Open it and you're in. Davish uses the SSH keys and ~/.ssh/config you already have (including ProxyJump through a bastion). There's no account and no login screen. It reconnects to the server you used last.

2. Nothing on the server. No agent, no daemon, no extra port. If the server runs sshd with SFTP, Davish works. Everything else is ordinary commands: /proc, systemctl, journalctl, docker, ss, nginx -t.

3. No surprises. Anything destructive (stopping a service, deleting a file, removing a container, replacing a crontab) shows the exact command before it runs, and a command log records everything Davish ran. When root is needed, Davish doesn't store your sudo password: it opens a terminal with the sudo … command typed in and lets you press Enter.

What's inside

  • Terminal with tabs and GPU rendering
  • Files: Finder-style SFTP, drag and drop, copy between two servers
  • Editor: atomic saves that keep mode and owner, backups for files under /etc
  • Docker: containers grouped by compose project, images and layers, volumes, logs
  • Nginx: sites, nginx -t before every reload, TLS expiry alerts
  • Services, Logs, Cron: systemd units, live journals, cron schedules in plain words
  • Ports & tunnels: see what's listening, tunnel it to 127.0.0.1, or open it in a built-in browser
  • Security: failed logins grouped by IP, ufw and fail2ban status
  • SSH keys, Packages, Git, Disk: authorized_keys, pending security updates, repo status, what's filling the disk Each server is its own workspace (⌘1…⌘9) that remembers its windows, and ⌘K opens a Spotlight-style search for apps, files, services and containers.

How it works

Davish is written in Go with Wails, and the UI is Svelte 5. Wails renders the UI in the operating system's own webview instead of shipping a copy of Chromium, which keeps the app small.

A few details I found interesting while building it:

One SSH connection per server. Terminal, SFTP, metrics and log tails all open channels on the same ssh.Client instead of new connections. Keepalives detect a dead link and the whole chain (including bastion hops) reconnects with backoff.

Agentless metrics. The monitor keeps one long-lived SSH session running a small POSIX sh loop that prints /proc/stat, /proc/meminfo, /proc/net/dev and df every couple of seconds. Go parses the snapshots and computes deltas. When the window is hidden or the app is locked, it slows down to save resources.

Don't trust the login shell. Some servers use zsh or fish, and some have a .bashrc that hangs. Davish runs its own commands under sh and gives every command a deadline, so one bad shell config can't freeze the UI.

Terminal output in batches. Emitting one event per read flooded the webview when you cat a big file. Output is now batched in ~16 ms windows and sent as base64, since it isn't always valid UTF-8.

Safe edits. Files are written to a temp file in the same directory and renamed over the original, so a dropped connection never leaves a half-written config behind.

Secrets stay in the keychain. Passwords and passphrases live only in the OS keychain. Host keys are checked on first connect, and a changed host key is refused outright.

Try it

Davish runs on macOS, Windows and Linux and is open source under GPLv3.

What's next

So far Davish is good at running servers you already have. Next I'm working on setting things up: new nginx sites with one-click SSL, containers and compose stacks from a form, cloning a repo and deploying it, and firewall plus backups.

If you manage a VPS with a web panel today, I'd love to know: what would you need to drop it? Comments and GitHub issues are both welcome.

Top comments (0)