Self-hosted Youtube subscription follower and notification system
- Rust 46.3%
- CSS 33.6%
- HTML 18.3%
- Dockerfile 1.8%
|
Some checks failed
Security scan / Docker Scout CVE scan (push) Has been cancelled
- Added a logo image for better branding. - Centered the header for improved visual appeal. |
||
|---|---|---|
| .github | ||
| assets | ||
| docker | ||
| migrations | ||
| src | ||
| templates | ||
| .dockerignore | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| cliff.toml | ||
| diesel.toml | ||
| LICENSE | ||
| README.md | ||
Laneya
Self-hosted YouTube subscription follower and notification system

Name definition
lanéya - Quenya adverb. recently, not long ago
| Element | Gloss |
|---|---|
la- |
"not, in-, un-; [ᴹQ.] none, not any" |
néya |
"once, at one time" |
Features
- Tracks YouTube channels via their public RSS feeds - no API key required
- Real-time new-video notifications via WebSocket
- Bulk import channels from a Google Takeout CSV export
- Single-container Docker deployment with a persistent SQLite database
- Built with Rust (Axum), HTMX and Tailwind CSS v4
Deploying with Docker
services:
laneya:
image: ghcr.io/akasiek/laneya:latest
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- laneya_data:/data
# If mounting data volume as a path on the host, ensure it has appropriate permissions for the container user.
user: "${UID:-1000}:${GID:-1000}"
environment:
# Timezone for videos timestamps
TZ: "UTC"
# Set to true to skip YouTube Shorts
FILTER_OUT_SHORTS: "true"
# Number of videos to show per page
VIDEOS_PER_PAGE: "24"
# How often to fetch new videos from YouTube
FEED_REFRESH_INTERVAL_MINS: "5"
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL # Drop all Linux capabilities. The application doesn't need any special permissions.
volumes:
laneya_data:
Save the above as compose.yaml, then run:
docker compose up -d
The app will be available at http://localhost:8080.
Data is stored in the laneya_data Docker volume which can be changed if needed.
Environment variables
| Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0:8080 |
Address and port the server listens on |
TZ |
UTC |
Timezone used for video timestamps |
FILTER_OUT_SHORTS |
false |
Set to true to hide YouTube Shorts |
VIDEOS_PER_PAGE |
24 |
Number of videos displayed per page |
FEED_REFRESH_INTERVAL_MINS |
5 |
How often (in minutes) feeds are refreshed |
Container security
- The container runs as a non-root system user with no home directory and no login shell
- The container filesystem is read-only - only the
/datavolume can be written to - All Linux capabilities are dropped
no-new-privilegesis enforced - the process cannot gain elevated privileges via setuid/setgid binaries- Multi-stage Docker build - the runtime image contains only the compiled binary and static assets; no compiler, build tools, or source code
Adding channels
Single channel
You need the channel ID - a string starting with UC (e.g. UCXuqSBlHAE6Xw-yeJA0Tunw).
Way to find it:
- On the channel page click ...more

- Scroll to the very bottom of the modal and click Share channel

- Click Copy channel ID

- Paste the ID into the form on the Channels page and submit
Bulk import via Google Takeout
- Go to Google Takeout
- Deselect all products, then scroll down and select only YouTube and YouTube Music

- Click All Youtube data included and make sure only subscriptions is selected

- Click Next step, then choose your delivery method and export frequency, and click Create export. Export should take about a minute.
- Inside the downloaded archive find
YouTube and YouTube Music/subscriptions/subscriptions.csv. This should be the only file in that archive. - Upload that file using the Bulk Import form on the Channels page
Development
Prerequisites
- Rust (stable)
- systemfd (if you want to use the hot-reload server)
- pnpm
- diesel_cli
Setup
.env file
Create a .env file in the project root with the following content:
DATABASE_URL=./database.db
Install dependencies and apply database migrations
# Install JS dependencies
cd templates && pnpm install && cd ..
# Apply database migrations
diesel migration run
Running the server
With hot-reload (restarts server on code changes):
systemfd --no-pid -s http::8080 -- cargo watch -x run
or without hot-reload:
cargo run
Tailwind CSS watch
In a separate terminal from the templates/ directory:
cd templates && pnpm run watch:css
Watches styles/styles.css and rebuilds styles/tailwind.css on every change.
Database migrations
# Apply pending migrations
diesel migration run
# Revert the last migration
diesel migration revert