Ninite for Homelabbers
Pick your self-hosted apps from a catalog, get a one-line curl command, and run it on your server. Docker is installed if missing, your apps are exposed on your Tailscale network with automatic HTTPS via TSDProxy, and your data persists across re-runs.
- Browse the app catalog at tsdeck.rishavnandi.workers.dev
- Select the apps you want
- Copy the generated
curlcommand - Run it on your Linux server
- Access your apps at
https://app-name.your-tailnet.ts.net
The webapp never stores your credentials or connects to your servers. All secrets are prompted at runtime on your own hardware.
User browser:
┌─────────────┐ POST /generate ┌──────────────┐
│ Frontend │ ──────────────────────► │ Hono Worker │
│(Cloudflare │ │(Cloudflare │
│ Pages) │ ◄──── slug + url ────── │ Workers) │
└─────────────┘ └──────────────┘
│
▼
┌──────────────┐
│ Cloudflare KV│
│ (15-min TTL)│
└──────────────┘
User server:
curl -fsSL https://tsdeck.rishavnandi.workers.dev/s/abc123 | bash
│
▼
┌──────────────┐
│ Bootstrap │──► Install Docker (if missing)
│ Script │──► Prompt for Tailscale Auth Key
│ │──► Prompt for app env vars
│ │──► Fetch compose templates from GitHub
│ │──► Assemble docker-compose.yml
│ │──► Start containers (incl. TSDProxy)
└──────────────┘
tsdeck/
├── apps/ # App templates (compose.yaml + meta.yaml)
│ ├── jellyfin/
│ ├── immich/
│ ├── sonarr/
│ ├── radarr/
│ ├── prowlarr/
│ ├── bazarr/
│ ├── qbittorrent/
│ ├── vaultwarden/
│ ├── portainer/
│ └── jellyseerr/
├── frontend/ # Static HTML/JS site (Cloudflare Pages)
│ ├── index.html
│ ├── app.js
│ └── styles.css
├── api/ # Hono API (Cloudflare Workers)
│ ├── src/
│ │ ├── index.ts # API routes
│ │ ├── generator.ts # Bash script generator
│ │ └── apps.ts # App metadata
│ ├── test/
│ ├── wrangler.toml
│ └── package.json
├── scripts/
│ └── validate-apps.js # CI check for app templates
└── package.json
# Install dependencies
cd api && bun install
# Run API locally
bun run dev
# Run tests
bun test
# Validate app templates
bun run validate-appsTSDeck uses Cloudflare Workers Static Assets — the frontend and API are deployed together as a single Worker.
cd api && bunx wrangler deployDeployed at https://tsdeck.rishavnandi.workers.dev
https://tsdeck.rishavnandi.workers.dev/— Frontend (catalog UI)https://tsdeck.rishavnandi.workers.dev/apps— API (app catalog JSON)https://tsdeck.rishavnandi.workers.dev/generate— API (generate slug)https://tsdeck.rishavnandi.workers.dev/s/:slug— API (serve bootstrap script)
- Create
apps/<app-id>/compose.yamlandapps/<app-id>/meta.yaml - Follow the schema in
apps/README.md - Add the app to
apps/manifest.jsonandapi/src/apps.ts - Run
bun run validate-apps - Open a pull request
- Zero server-side secrets: The webapp never collects Tailscale auth keys, passwords, or server credentials.
- Ephemeral slugs: Setup commands expire after 15 minutes.
- Inspectable scripts: Every generated script is plain bash. Read it before piping to
bash. - Dry-run mode: Set
DRY_RUN=1before running the script to preview changes.
WTFPL