Webius

A small launcher for every app published on the app server through Tailscale Serve. Open one page, see all your apps, click a card and the app opens in a new tab.

  • SvelteKit (SSR, @sveltejs/adapter-node) — needs a server to read the Tailscale Serve configuration.
  • Tailwind CSS v4 for styling.
  • PWA — installable, standalone window, offline fallback screen.
  • Live discovery — the app list comes from tailscale serve status --json, so new routes appear automatically.
  • Friendly metadata — names, icons, colours and tags you edit in /manage and that persist in a Docker volume.

Production URL (tailnet only): https://app.tail60a042.ts.net:10008

How it works

browser ──HTTPS──▶ Tailscale Serve (app server, :10008)
                       │ proxy
                       ▼
                 Webius container  127.0.0.1:8788 ──▶ node build
                       │ reads /var/run/tailscale/tailscaled.sock
                       ▼
                 `tailscale serve status --json`

Webius asks Tailscale for the current Serve routes, builds one card per route (https://<host>:<port>), and merges them with your saved metadata. Routes are cached to data/discovery-cache.json so the dashboard still renders when the Tailscale daemon is briefly unavailable.

Discovering routes on the app server currently yields:

Port Target App
10000 127.0.0.1:8080 SuperiorNL
10006 127.0.0.1:8765 TaliusTool
10007 127.0.0.1:8093 ImagenContent Studio
10004 127.0.0.1:8092 Excalidraw
443 127.0.0.1:8180 Trilium Notes
8181 127.0.0.1:8180 (duplicate, hidden)
8443 127.0.0.1:3000 Gitea

Usage

  • Dashboard (/) — search (/ focuses the box), filter by tag, click a card to open that app in a new tab. Install appears when the browser offers the PWA install prompt.
  • Manage (/manage) — rename a discovered route, pick an icon/colour/tags, hide duplicate routes, reset to defaults, and add or remove custom apps that are not (yet) behind Tailscale Serve.

Only give trusted users tailnet access: Webius is intentionally unauthenticated, like the other apps on the server. robots.txt disallows indexing.

Configuration

All settings are optional; see .env.example.

Variable Purpose
WEBIUS_DATA_DIR Where apps.json and the discovery cache live (/app/data).
WEBIUS_SERVE_HOST Host used to build URLs when Tailscale is unavailable.
WEBIUS_SELF_TARGET Loopback target of this instance, to flag its own card.
WEBIUS_PORT Host loopback port to publish (default 8788).
WEBIUS_DISCOVERY off skips tailscale serve status (plain local dev).
WEBIUS_DISCOVERY_FILE Read Serve JSON from a file instead of the CLI (tests/dev).
WEBIUS_TAILSCALE_BIN Override the tailscale executable name/path.
ORIGIN Documented canonical origin; adapter-node derives it from the request.

Local development

npm install
npm run dev          # http://127.0.0.1:5173

The Vite dev server has no Tailscale socket, so point discovery at a fixture:

WEBIUS_DISCOVERY_FILE=/tmp/serve.json WEBIUS_SERVE_HOST=app.tail60a042.ts.net npm run dev

(/tmp/serve.json is the output of tailscale serve status --json.)

Checks:

npm run check        # svelte-check + sync
npm test             # unit tests (node --test)
npm run build        # adapter-node output in build/
npm run preview      # serve the production build on :3000

Docker

docker compose up -d --build          # build + run locally on 127.0.0.1:8788
docker compose logs --tail=100 webius

The container binds 127.0.0.1:8788 only and mounts /usr/bin/tailscale and /var/run/tailscale read-only so it can list routes.

Production (app server)

See AGENTS.md for the full, safeguarded procedure. In short:

./scripts/deploy.sh          # rsync source + docker compose up -d --build

Then ensure the HTTPS route exists (only this port is touched):

ssh app@100.119.243.121 \
  'tailscale serve --bg --https=10008 http://127.0.0.1:8788'

Open https://app.tail60a042.ts.net:10008.

Data

data/apps.json holds your overrides and custom apps and is not committed. Back it up; it is small and human-readable. The discovery cache (data/discovery-cache.json) is disposable.

S
Description
No description provided
Readme
81 KiB
Languages
TypeScript 42.7%
Svelte 41.4%
Python 5.6%
JavaScript 3.8%
Shell 2.1%
Other 4.4%