TubeHaus
English · 한국어
Your own YouTube, on your own server: fast, private, and it doesn't get blocked.
It looks and works exactly like YouTube (same layout, same URLs, same keyboard shortcuts), with no ads and no tracking. It also plays live streams with real-time captions, keeps one library for all your devices, and keeps working even from a cheap cloud VPS.
👉 Try it without installing: try.168-107-27-85.sslip.io (a small public instance: up to 15 viewers at a time, 720p; your history stays in your own browser)
**📱 No server? Get the app: Android APK
(Android 8+) · Windows · macOS · Linux .deb · .rpm**
(beta). It runs entirely on your device with its own YouTube engine: no server, no account.
Source and install notes per platform: android-app, windows-app, mac-app and linux-app.
TubeHaus is built on top of Invidious and invidious-companion, which do the hard work of talking to YouTube. TubeHaus adds its own front end and a small server next to them. All credit to the Invidious team.
Why TubeHaus
⚡ Fast
- Instant clicks. Video pages come from a local cache that refreshes in the background, and the videos you are most likely to open next are fetched before you click (measured: about 1-2 s cold, a few milliseconds warm)
- Live streams that don't stall. The server pulls segments ahead of the player over kept-alive connections and serves a longer, gap-free playlist with exact segment timing, so the timeline never jumps
- Always the best quality. It never lowers resolution on its own. It prefers 60 fps and the codec your device decodes in hardware (checked with MediaCapabilities), switches codec instead of resolution when frames drop, and sizes the buffer from the bitrate so even 8K fits the browser's media buffer
- Your devices never talk to Google. Video, thumbnails and pages are streamed through your own server; no Google account, cookies or YouTube scripts in your browser
- YouTube never sees your home IP. Everything your server asks YouTube goes out through Cloudflare WARP
- No accounts, no telemetry. Subscriptions, history, resume positions and playlists are files on your server, shared by your household and nobody else
- YouTube refuses most VPS and cloud addresses ("Sign in to confirm you're not a bot"). TubeHaus routes YouTube traffic through Cloudflare WARP in proxy mode, and when YouTube flags the address anyway it reconnects WARP for a fresh one and replays the request automatically (rate-limited). Playback, live streams and downloads keep working on a cheap cloud VM
- YouTube gives no captions for live streams. TubeHaus transcribes them on the fly with whisper.cpp, a few seconds ahead of playback, on a single CPU core
- One switch in Settings turns YouTube back into a tool: the home screen is only new videos from your subscriptions, Shorts, trending and recommended videos disappear everywhere, nothing autoplays after a video, and comments stay folded until you open them. Search still works, so you watch what you came for
- The Shorts feed learns what you like from how you watch: how long you watched, whether you looped it, liked it or swiped it away. It keeps a score per channel and per topic (tags, hashtags, genre) in a small file on your server, and picks the next Shorts from your subscriptions, channels you like, topics you like and what's popular, with every fourth slot left for something new. No Google account, nothing leaves your server, and you can reset it any time under History
Everything else
- YouTube-identical UI: home, search, channels, playlists, subscriptions, history, library, trending
- Custom player on Shaka Player (DASH/HLS): chapters, storyboard seek previews, SponsorBlock, speed, sleep timer, stats, mini player, theater mode, ambient mode, Media Session (lock screen / Bluetooth keys)
- One library for every device: subscriptions (with an RSS-based feed), watch history, resume positions, Watch Later, likes, playlists
- Send to TV: pick a video on your phone and it starts on the TV (no Chromecast; open screens long-poll the server)
- High-quality offline save: 1080p/4K come as separate video and audio; the server fetches both and merges them with ffmpeg
- Translated subtitles for videos that have none in your language
- TV mode: full remote-control navigation (arrows / OK / Back) for TV browsers
- Dislike counts (Return YouTube Dislike), comments, transcripts
(Formerly HomeTube, renamed to avoid a clash with an unrelated project of the same name.)
How it fits together
browser ──► Caddy ─┬─ /y/*, page navigations ─────────► web/ (the app)
├─ /api/p/, /api/v1/videos/ ─────► TubeHaus server ──┐
├─ /companion/* ───────────────────► invidious-companion ─┤
└─ everything else ────────────────► Invidious │
▼
Cloudflare WARP (proxy mode)
│
YouTube
TubeHaus uses Invidious as its YouTube backend and adds its own server next to it. Invidious' companion private_url points at the TubeHaus server, which passes everything
through and patches in what is missing (live HLS URLs, an empty storyboards key some old
videos lack, WARP rotation when YouTube blocks).
Requirements
- Server: Linux with Docker and docker compose, x86-64 or ARM64 (a free Oracle Cloud ARM VM works fine)
- CPU / RAM: 2+ cores and about 4 GB RAM for the whole stack. Live captions use about one more core, only while someone watches a live stream with captions on
- Disk: about 10-20 GB, mostly Docker images. Videos are streamed, not stored, so this doesn't grow with use
- A hostname for HTTPS (a domain, or a free wildcard DNS name such as sslip.io), or plain HTTP on a LAN
Quick start (Docker)
One command brings up everything: Caddy, the TubeHaus server with Cloudflare WARP built in, the PO-token provider for live streams, whisper.cpp for live captions, and the official Invidious + companion + PostgreSQL images. Works on x86-64 and ARM64.
git clone https://github.com/biolend83/tubehaus && cd tubehaus
cp .env.example .env # set your domain and three secrets
docker compose pull # prebuilt images, amd64 and arm64
docker compose up -d
To build the TubeHaus image yourself instead (for example after changing the code), use
docker compose up -d --build. The first build takes a few minutes because of whisper.cpp.
Then open your domain. WARP registers itself on first start and keeps its registration in a volume; the companion reaches YouTube through it as well.
No domain, or your own reverse proxy? Caddy can serve plain HTTP on any port. In .env:
# plain HTTP on a LAN, at http://192.168.1.10:8080
TUBEHAUS_SITE=:80
TUBEHAUS_HTTP_BIND=8080
TUBEHAUS_URL=http://192.168.1.10:8080
TUBEHAUS_DOMAIN=192.168.1.10
TUBEHAUS_HTTPS=false
TUBEHAUS_EXTERNAL_PORT=8080
behind your own nginx, Traefik or Caddy, which handles HTTPS for tube.example.com
TUBEHAUS_SITE=:80
TUBEHAUS_HTTP_BIND=127.0.0.1:8080 # only your proxy reaches it
TUBEHAUS_HTTPS_BIND=127.0.0.1:8443 # unused, kept off the public 443
TUBEHAUS_URL=https://tube.example.com
TUBEHAUS_DOMAIN=tube.example.com
TUBEHAUS_HTTPS=true
TUBEHAUS_EXTERNAL_PORT=443
Then point your proxy at http://127.0.0.1:8080 for everything, unbuffered (video and live streams), e.g. in nginx:
proxy_pass http://127.0.0.1:8080; proxy_buffering off; proxy_read_timeout 1h; proxy_set_header Host $host;
Add a login before you expose it. TubeHaus has no accounts of its own. The simplest option is the built-in
password: set TUBEHAUS_AUTH=basic, TUBEHAUS_USER and TUBEHAUS_PASSWORD_HASH in .env (the hash comes from
docker compose run --rm caddy caddy hash-password; write every $ as $$). Or put Authelia, Authentik or a
passkey gate in front with forward_auth.
Check that everything works:
docker compose exec tubehaus python3 /app/server/tubehaus_server.py --doctor
It tests WARP, YouTube, Invidious, a real video lookup and the optional tools, one line each. If something fails, see Troubleshooting. To update or back up, see Updating and backups.
Manual setup
You need a Linux server with Python 3.10+, Caddy, and Docker for Invidious.
1. Cloudflare WARP in proxy mode
Install the official client (pkg.cloudflareclient.com), then — set proxy mode before connecting, or the whole server's routing moves into WARP:
warp-cli --accept-tos registration new
warp-cli --accept-tos mode proxy # listens on 127.0.0.1:40000
warp-cli --accept-tos connect
curl -x http://127.0.0.1:40000 https://www.cloudflare.com/cdn-cgi/trace # warp=on
Containers can't reach 127.0.0.1 on the host, so re-expose it on the Docker bridge for the companion:
socat TCP-LISTEN:18080,bind=172.17.0.1,fork,reuseaddr TCP:127.0.0.1:40000 # run it as a service
(Unofficial WARP clients such as wgcf get rate-limited by Cloudflare; use the official one.)
2. Invidious + companion
Follow the Invidious installation guide with invidious-companion. Then:
- companion:
PROXY=socks5://172.17.0.1:18080(WARP) and publish it on127.0.0.1:8282 - Invidious config: point the companion's
private_urlat TubeHaus, e.g.
invidious_companion: [{ private_url: "http://172.17.0.1:3010/companion", public_url: "https://tube.example.com/companion" }]
(then bind TubeHaus to an address the container can reach, e.g. HT_BIND=172.17.0.1)
3. TubeHaus server
git clone https://github.com/biolend83/tubehaus /opt/tubehaus
cd /opt/tubehaus && cp .env.example .env # edit it
sudo cp deploy/tubehaus.service /etc/systemd/system/ && sudo systemctl enable --now tubehaus
Optional extras:
- Live streams: yt-dlp with the
- Live captions: build whisper.cpp and download
ggml-base-q5_1.bin; setHT_WHISPER_BIN/HT_WHISPER_MODEL - Offline save:
ffmpeg
4. Reverse proxy: Caddy or nginx
Copy web/ to /srv/tubehaus/web and adapt deploy/Caddyfile.example for Caddy. If you use nginx instead, start from deploy/nginx.conf.example and replace the hostname, TLS certificate paths and upstream addresses for your setup. The nginx example keeps long-lived API, companion and download requests unbuffered with extended timeouts.
TubeHaus has no accounts. Anyone who can open it shares the same library. Put your own
login in front (Caddy basic_auth, or forward_auth to Authelia / Authentik / a passkey gate)
before exposing it. Set window.TUBEHAUS_LOGIN_URL in index.html if expired sessions should
be sent to your login page.
FAQ
Is this a replacement for Invidious? No, it runs alongside it. Invidious and its companion fetch everything from YouTube; TubeHaus is a YouTube-style front end plus a server that adds live streams, live captions, a shared library, send to TV, downloads and WARP egress. The docker compose file runs the official Invidious images for you.
Can I use my existing Invidious instance (or keep using Yattee, FreeTube, ...)? Yes, follow Manual setup and point TubeHaus at it. Apps that talk to Invidious keep working, and if the companion goes out through WARP they benefit from it too. Live streams and WARP rotation work best when TubeHaus sits in front of the companion as described.
Where does the content come from? Does it store videos? Everything comes from YouTube. Nothing is stored except your library (subscriptions, history, playlists) and short-lived files for offline downloads.
Is there a recommendation algorithm? For Shorts, yes, and it runs entirely on your server (see Shorts that learn from you above). For regular videos you get your subscriptions feed, trending and category tabs, and YouTube's per-video related list. Nothing is learned by Google, since no Google account is involved.
Age-restricted videos? They usually don't play, since there's no signed-in account to pass the age check. That is the same as Invidious.
Can I bring my subscriptions in, and take my data out?
Yes. Under Settings → My data (or the subscriptions page), Import from file takes Google Takeout (the
subscriptions CSV and watch-history.json), Invidious, NewPipe and FreeTube exports, OPML, and TubeHaus backups.
Export gives you a full TubeHaus backup (subscriptions, history, resume points, playlists, likes), an
Invidious-format file, a Takeout-style CSV, or OPML for any feed reader. Your data is never stuck here.
Does anything phone home? No. There are no accounts and no telemetry. The only outside requests are YouTube (through Invidious and WARP) and, from the browser, the optional SponsorBlock and Return YouTube Dislike lookups.
How do phones and TVs connect? It's a web app: open your address in the browser, or use "Add to Home Screen" to install it like an app. TV browsers get a TV mode with remote-control navigation. On Android you can also skip the server entirely with the TubeHaus app.
Running a public instance
Want to let people try TubeHaus without installing it? Set TUBEHAUS_PUBLIC=1 in .env (or HT_PUBLIC_MODE=1
for a manual install). Then:
- Every visitor's library lives in their own browser. Subscriptions, history, resume points and playlists are
- The server only does stateless work: fetching feeds for the channels a browser sends, parsing imports and
- Switched off: send to TV and server-side downloads (they would be shared between strangers), and Shorts
Handling a crowd. TubeHaus protects itself, and your YouTube access, when many people show up at once:
| Setting (.env) | Default | What it does |
|---|---|---|
| TUBEHAUS_MAX_VIEWERS | 0 (off) | people watching at once; newcomers beyond it get "busy, try again in a few minutes", people already watching are never cut off |
| TUBEHAUS_MAX_HEIGHT | 0 (off) | highest quality offered, e.g. 1080, to keep bandwidth in check |
| TUBEHAUS_RATE_PER_MIN | 120 on public instances | API requests per visitor per minute; more get "slow down" (429) |
| HT_MAX_CONNECTIONS | 256 | requests handled at the same time; beyond it the server answers "busy" at once instead of falling over |
Always on: when many people open the same video (or the same channel feeds) at once, YouTube is asked once and the answer is shared; live streams are fetched once per stream however many people watch; idle connections are dropped after 30 seconds; and public instances don't pre-load recommended videos.
The ready-made public setup. deploy/docker-compose.public.yml puts all of this together the way the instance
above runs:
- Anubis in front: every visitor's browser solves a short proof-of-work check ("Making sure you're not a bot")
- Sign-up required (
HT_ACCOUNTS=1): a user name and a password, no e-mail or other personal details. Passwords are
- Invidious' own accounts and admin pages switched off, only the player's reads allowed on the companion, load limits,
docker compose --env-file .env -f deploy/docker-compose.public.yml up -d
Also firewall the box so the containers can reach the internet only: no private networks, no cloud metadata service, none of your other servers.
Before you open one, keep in mind:
- Bandwidth: video is streamed through your server. Watch your provider's traffic limits
- YouTube blocks: many viewers on one address get it flagged sooner; WARP rotation helps but has limits
- Trust: visitors' requests pass through your server. Be clear about what you log (TubeHaus logs no viewing
- Leave
TUBEHAUS_AUTH=none, and consider rate limiting in Caddy
| Address | Region | Limits | Run by | |---|---|---|---| | try.168-107-27-85.sslip.io | South Korea | 15 viewers, 720p | the maintainer |
Running one? Add it here (or in the discussion) so others can find it.
Configuration
All settings are environment variables — see .env.example.
| Variable | Default | |
|---|---|---|
| HT_BIND, HT_PORT | 127.0.0.1, 3010 | where the API listens |
| HT_STATE | ./state | library and subtitle cache |
| HT_INVIDIOUS | http://127.0.0.1:3000 | Invidious |
| HT_COMPANION | http://127.0.0.1:8282 | invidious-companion |
| HT_PUBLIC_URL | http://localhost:8080 | the address browsers use |
| HT_YT_PROXY | 127.0.0.1:40000 | WARP proxy (empty = direct) |
| HT_WARP_ROTATE | 1 | reconnect WARP when YouTube blocks |
| HT_YTDLP | yt-dlp | for live streams |
| HT_WHISPER_BIN, HT_WHISPER_MODEL, HT_WHISPER_LANG | empty, empty, auto | live captions |
| HT_SUB_LANG, HT_LIBRETRANSLATE | en, empty | default subtitle translation target (the app asks for its own language), optional fallback |
| HT_DOWNLOAD_DIR | /var/tmp/tubehaus-dl | offline save workspace |
| HT_PUBLIC_MODE | 0 | public instance: libraries stay in visitors' browsers (see above) |
| HT_ACCOUNTS, HT_MAX_ACCOUNTS | 0, 1000 | require sign-up (user name + password) before anything else |
| HT_MAX_VIEWERS, HT_MAX_HEIGHT, HT_RATE_PER_MIN, HT_MAX_CONNECTIONS | 0, 0, 120 public / 0, 256 | load limits (see Handling a crowd) |
Translations
Interface text lives in web/y/lang/.js (the key is the original Korean text). The 13 languages are complete
and no new ones are being added for now, so each can be kept up to date with every release. Corrections to the
existing translations are very welcome.
Community
- Questions and setup help: Discussions (please include the
--doctoroutput) - Bugs and feature requests: Issues
- Contributing: see CONTRIBUTING.md. Start with a
good first issue; ROADMAP.md shows what's planned and docs/ARCHITECTURE.md maps the code - Security problems: report them privately, see SECURITY.md
- What changed: CHANGELOG.md and Releases
Thanks
People who made TubeHaus better, with code, translations, testing or ideas:
Code and design
@Aaqibhafeezkhan: the house-and-play icon, remembering the playback speed, an nginx example, Spanish polish (#28, #29, #30, #31)
@bh-official: the exact upload date on hover, and tests for exact upload times (#26, #27)
@onyks-os: the first contribution, fixing the install instructions (#1)
@SakarPaisen: Turkish (#8)
@rahul05ranjan: Bengali, and a Hindi review by a native speaker (#16, #17)
@JamesMowery: import from file and data export (which became v0.4.0), and the wrong posted time on new videos (#14, #15, #20)
- u/Proper_Witness9173: brightness and volume swipes, the tablet layout, comments beside the video, picture-in-picture and most of 0.3.8
- u/DryYam2258: the first Mac tester; asked for text size, removing subscriptions and channel pictures, and suggested subscription groups
- u/Gloomy_Acadia_445: asked for Linux, which led to the .deb, .rpm and tar.gz builds
- u/Victor_Orbis35: reported "mpv is missing" on Windows, which turned out to be a missing Vulkan runtime (fixed in 0.3.5)
Credits
- Invidious and invidious-companion (AGPL-3.0) — the backend this sits on
- Shaka Player (Apache-2.0) — bundled in
web/y/lib/ - Layout after varun-jasti/Youtube-UI-UX (MIT); progress bar and volume after pncsoares/youtube-video-player-clone (MIT)
- Icons: Material Symbols (Apache-2.0)
- whisper.cpp (MIT), SponsorBlock, Return YouTube Dislike
- Cloudflare WARP
License
AGPL-3.0, like Invidious.
This project is not affiliated with YouTube or Google. Use it for your own household, and respect the terms of the services you connect to.