A webapp to browse TLDR-Pages, as a docker container
1.6K
A self-hosted web interface for browsing tldr-pages — the community-maintained collection of simplified, practical command reference pages. Packaged as a single Docker container with automatic data synchronization.
Note: tldr-webui is a viewer only. All command reference content is sourced from the tldr-pages project and is licensed under CC BY 4.0.
common, linux, osx, windows, android, freebsd, netbsd, openbsd, sunos, cisco_ios/ or Ctrl+K from anywhere on the page/api/health returns uptime and version, suitable for container health checks and monitoringThe application has two distinct layouts depending on whether a search is active.


On narrow screens the sidebar and content panel are shown one at a time. Tapping a result collapses the list to show full-width content; a ← results button at the top brings the list back.
| Home | Results — list | Results — content |
|---|---|---|
![]() | ![]() | ![]() |
Key UI behaviours visible in the screenshots above:
common, linux, macos, windows, android, freebsd, netbsd, openbsd, sunos, cisco) are available both on the home screen and in the compact sidebar.EN label.{{path}} are highlighted in amber.curl -O https://raw.githubusercontent.com/acaranta/tldr-webui/main/docker-compose.yml
docker compose up -d
git clone https://github.com/acaranta/tldr-webui.git
cd tldr-webui
docker compose up --build -d
The application will be available at http://localhost:8129.
On first start, the container clones the tldr-pages repository into the tldr-data volume. This takes roughly 30–60 seconds depending on network speed. The UI is accessible immediately and displays an amber sync banner until the clone completes. On subsequent restarts, the container performs a fast git pull instead.
docker run -d \
--name tldr-webui \
-p 8129:3000 \
-v ./tldr-data:/tldr-pages \
--restart unless-stopped \
acaranta/tldr-webui:latest
The container exposes port 3000 internally. The docker-compose.yml maps it to 8129 on the host. Change the host-side port by editing the ports mapping:
ports:
- "YOUR_PORT:3000"
tldr-pages data is stored in the tldr-data bind mount defined in docker-compose.yml. The path inside the container is /tldr-pages. The entrypoint fixes ownership at startup so the unprivileged nextjs user can write to it regardless of the host UID that created the directory.
| Variable | Default | Description |
|---|---|---|
TLDR_PATH | /tldr-pages | Override the path where tldr-pages data is read from |
NODE_ENV | production | Node environment (set automatically in the container) |
NEXT_TELEMETRY_DISABLED | 1 | Disables Next.js telemetry (set automatically) |
To use a custom tldr-pages path, add it to the environment section of docker-compose.yml:
environment:
- TLDR_PATH=/data/my-tldr-pages
The docker-compose.yml includes a health check that polls /api/health every 30 seconds:
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
npm install
npm run dev
The development server starts at http://localhost:3000.
PWA features are disabled in development mode (NODE_ENV=development). To test with real tldr-pages data locally, clone the repository and point the app at it:
git clone --depth=1 https://github.com/tldr-pages/tldr /tmp/tldr-pages
TLDR_PATH=/tmp/tldr-pages npm run dev
npm run build
npm start
npm run lint
entrypoint.sh) runs as root./tldr-pages volume mount so the nextjs user can write to it.{"status":"syncing"} file to /tmp/tldr-sync.json.git, then updates the status file to ready or error.su-exec and starts the Next.js standalone server.The UI polls /api/sync-status and shows or hides the sync banner based on the response.
Browser → Next.js API routes → src/lib/tldr.ts → /tldr-pages filesystem
The tldr.ts library performs all reads directly from the filesystem — no database, no in-memory index. Search is a prefix scan over directory entries. Page content is read and returned as raw Markdown, rendered client-side by react-markdown.
When a page is requested in a non-English language and no translation exists, the library returns the English page with fallback: true. The UI shows a blue informational notice to the user.
The Dockerfile uses a three-stage build:
| Stage | Base image | Purpose |
|---|---|---|
deps | node:20-alpine | Install npm dependencies with npm ci |
builder | node:20-alpine | Copy source, download PWA icons, run next build |
runner | node:20-alpine | Copy standalone output, add git and su-exec, run |
The final image contains only the standalone Next.js output and no build-time tooling.
All endpoints are served by Next.js API routes under /api/.
GET /api/healthReturns application status, version, and uptime. Used by the Docker health check.
Response
{
"status": "ok",
"version": "0.1.0",
"uptime": 142
}
GET /api/sync-statusReturns the current state of the background tldr-pages git synchronization.
Response
{ "status": "syncing" }
{ "status": "ready" }
{ "status": "error" }
GET /api/commandsSearch for commands by name.
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | — | Search query (required) |
platform | string | common | One of the supported platform values |
lang | string | en | BCP 47 language code |
Response — array of matching command entries:
[
{ "command": "git", "platform": "common", "hasTranslation": true }
]
GET /api/pageRetrieve the Markdown content of a specific command page.
| Parameter | Type | Default | Description |
|---|---|---|---|
command | string | — | Command name (required) |
platform | string | common | One of the supported platform values |
lang | string | en | BCP 47 language code |
Response
{
"content": "# git\n\n> ...",
"fallback": false,
"platform": "common",
"lang": "en"
}
Returns 404 if the command is not found on any platform.
All command reference content is provided by the tldr-pages project and its contributors, licensed under Creative Commons Attribution 4.0 (CC BY 4.0).
The tldr logo used as the PWA icon is downloaded directly from the tldr-pages repository during the Docker build.
tldr-webui is an independent viewer and is not affiliated with or endorsed by the tldr-pages project.
The tldr-webui application code is provided as-is. Content displayed by the application is licensed under CC BY 4.0 by the tldr-pages contributors.
To be transparent : This project was developed with the assistance of AI language models under human supervision. by a bearded NERD :)
Content type
Image
Digest
sha256:cef8224d4…
Size
82.7 MB
Last updated
4 months ago
docker pull acaranta/tldr-webui