A fast, Termius-style SSH client built with Tauri 2 (Rust + TypeScript), with self-hosted, end-to-end encrypted sync.
- Hosts organised by groups (folders) and tags, instant search (
Ctrl+K) - Multi-tab SSH terminals (xterm.js + WebGL), password / private key / keyboard-interactive auth
- Mosh, Telnet (auto-login), serial consoles and VNC remote desktops (noVNC) in tabs
- Copy password from host cards, the right-click menu, the editor, or the terminal toolbar
- Local port forwarding rules per host
- Jump hosts, SOCKS5/HTTP proxies, agent forwarding, environment variables and a startup snippet per host
- Nearby Share (desktop): send and receive files on the local network, compatible with the LocalSend apps
- Trust-on-first-use host key checking (synced across devices)
- Local vault encrypted at rest (XChaCha20-Poly1305)
- Sync to your own server; data is encrypted on-device with Argon2id(passphrase) — the server only sees ciphertext
npm install
npx tauri devnpx tauri build # desktop bundles for the current OS
npx tauri android build # needs Android SDK + NDK
npx tauri ios build # needs macOS + Xcode.github/workflows/build.yml builds Linux (x64 + arm64 / Raspberry Pi), Windows, macOS (universal), Android (APK) and iOS (when APPLE_DEVELOPMENT_TEAM is set), plus the sync server image.
Export hosts in Termix (JSON), then either use Settings → Import from Termix, or:
kermius --import-termix ~/termix-hosts.jsonGroups, tags, passwords, keys, notes and local port-forward rules are kept. Re-importing updates hosts instead of duplicating them.
cd server
cp .env.example .env
sed -i "s/^KERMIUS_TOKEN=.*/KERMIUS_TOKEN=$(openssl rand -hex 32)/" .env
docker compose up -d # pulls hienanh/kermius-sync, listens on port 8080 (change KERMIUS_PORT in .env)Put it behind HTTPS (Caddy, Traefik, nginx…). In Kermius → Settings → Sync, enter the server URL, the token and an encryption passphrase. Use the same passphrase on every device; it never leaves the device and lost passphrases cannot be recovered.
API: GET /v1/vault → blob + x-version; PUT /v1/vault with x-base-version (409 on conflict; the client re-pulls and merges per host by last update).
- Mosh needs
moshon this computer (the .deb/.rpm installs it; macOS:brew install mosh) andmosh-serveron the host, with UDP ports 60000–61000 open. The host editor has a copyable install command. Kermius signs in over SSH with the host's stored credentials. - Serial on Linux needs the
dialoutgroup:sudo usermod -aG dialout $USER, then log out and back in. - VNC needs nothing extra; the VNC password is the host's password.
Two-way sync or one-way mirror between local disks and SSH hosts, with change watching, schedules, multiple routes per device and conflict resolution.
Folder Sync (two-way sync / mirror between disks or with SSH hosts) uses rsync. Linux and macOS only.
This computer needs rsync 3.1+:
| OS | Command |
|---|---|
| Debian / Ubuntu | sudo apt install rsync |
| Fedora / RHEL | sudo dnf install rsync |
| Arch | sudo pacman -S rsync |
| macOS | brew install rsync (the bundled rsync/openrsync is too old) |
Remote hosts (Linux) need rsync and GNU find; inotify-tools makes remote changes sync instantly (otherwise Kermius checks every minute). Nothing else is installed on the remote.
| OS | Command |
|---|---|
| Debian / Ubuntu / Raspberry Pi OS | sudo apt install -y rsync inotify-tools |
| Fedora / RHEL / Rocky | sudo dnf install -y rsync inotify-tools |
| Arch / Manjaro | sudo pacman -S --needed rsync inotify-tools |
| Alpine | sudo apk add rsync inotify-tools findutils |
| openSUSE | sudo zypper install -y rsync inotify-tools |
Watching only runs while Kermius is open. On Linux, very large trees may hit the inotify watch limit; raise it with echo fs.inotify.max_user_watches=1048576 | sudo tee /etc/sysctl.d/99-zz-inotify.conf && sudo sysctl -p /etc/sysctl.d/99-zz-inotify.conf (the 99-zz- name makes it win over a lower value in /etc/sysctl.conf).
Send and receive files, folders, text and the clipboard on the local network (desktop, Android and iOS). It speaks the LocalSend v2 protocol, so it works with the LocalSend apps on phones and computers as well as other Kermius devices.
- Build a selection (File, Folder, Text, Paste, or drop files on the page), then tap a device to send it. With Clear after sending off, the same selection can go to several devices.
- Incoming files need your approval and go to the Downloads folder, or a folder you pick (per device). Text arrives as a message you can copy.
- Transfers show progress and speed; up to 4 files are uploaded at once.
Devices find each other by UDP multicast, which does not cross VPNs or routers. For those, turn on Use this address for Nearby Share on a host: it appears under Your hosts and is reached directly at its address (greyed out while Kermius / LocalSend is not running there). The setting syncs with your hosts. iOS cannot discover devices by multicast, so there Nearby Share only uses these saved addresses (devices reached this way can send back while Kermius is open); received files are in the Files app under Kermius.
| Keys | Action |
|---|---|
Ctrl+K (Ctrl+Shift+K in a terminal) |
Search hosts |
Ctrl+T (Ctrl+Shift+T in a terminal) |
Vault tab |
Ctrl+Shift+W |
Close terminal tab |
Ctrl+Tab / Ctrl+1…9 |
Switch tabs |
Ctrl+Shift+C / Ctrl+Shift+V |
Copy / paste in terminal |
Ctrl+S / Esc |
Save / close host editor |
Ctrl+Shift+L (Control on macOS too) |
New local terminal |
Other apps (file managers, launchers, scripts) can drive Kermius. If Kermius is already running, the request goes to that window (it comes to the front); otherwise Kermius starts and handles it once its window is ready.
| Command | Does |
|---|---|
kermius --new-terminal |
Opens a local terminal in the home folder |
kermius --new-terminal --cwd DIR |
Opens a local terminal in DIR (relative to the caller's folder; falls back to home if missing) |
kermius --share PATH... |
Puts the files and folders into the Nearby Share selection and opens Nearby Share; the user picks the device. Missing paths are skipped. |
Example, a file manager "Share with Kermius" action: kermius --share "/home/me/Pictures/a.png" "/home/me/Docs".
For apps that keep driving terminal tabs (Kolphin opens a tab, cds it as you browse, runs claude in another).
Kermius listens on a Unix socket, $XDG_RUNTIME_DIR/kermius/control.sock (else /tmp/kermius-$UID/control.sock),
folder 0700, socket 0600. One JSON object per line: requests {"id", "method", "params"}, one reply each
({"id", "result"} or {"id", "error": {"code", "message"}}), and events {"event", "params"}.
If the socket is missing, start kermius --background (no window, no focus) and retry for a few seconds.
| Method | Params | Result / behaviour |
|---|---|---|
hello |
client, version |
{"app", "version", "api": 1, "capabilities"}. Must come first. |
session.open |
key?, cwd?, title?, icon? (SVG/PNG path), focus? (true) |
{"session", "reused"}. A live tab with the same key is reused (and cded to cwd if idle). |
session.run |
argv, cwd?, title?, icon?, env?, focus? |
{"session"}. Runs argv through the login shell (your PATH); when it exits the tab shows the status and keeps a shell. |
session.cd |
session, path |
{}; busy unless the shell is idle at its prompt (nothing is typed into running programs or a shell still starting); no-op if already there. |
session.focus / session.close |
session |
{}; close frees the key before replying |
session.list |
key? |
{"sessions": [{"session", "key", "cwd", "busy", "title"}]} |
share |
paths (absolute) |
{}, like kermius --share |
Events to every client that sent hello: session.closed {session, key} (tab closed or shell exited) and
session.cwd {session, key, cwd} (tabs with a key). Error codes: bad_request, unknown_method, not_found, busy.
Example: printf '%s\n' '{"id":1,"method":"hello"}' '{"id":2,"method":"session.open","params":{"key":"t","cwd":"/tmp"}}' | socat - UNIX-CONNECT:$XDG_RUNTIME_DIR/kermius/control.sock.


