This is the abridged developer documentation for LANrurugi
# LANrurugi 文档
> 以漫画为主、也能读 PDF / EPUB 等电子书的自托管书库,以 LANraragi 为起点、用 Rust + React 大幅改造与强化——现有 LANraragi 部署的数据与 API 直接可用。
## 这个站点里有什么 [Section titled “这个站点里有什么”](#这个站点里有什么) * **[安装(Docker / NAS)](guide/install/)**——把 LANrurugi 跑起来,并让它读到你已有的库。 * **[原生安装](guide/install-native/)**——不用容器,直接在 Linux、Apple Silicon Mac 或 FreeBSD 上运行。 * **[快速开始](guide/quickstart/)**——首次登录、扫描库、导入旧数据。 * **[支持的格式](guide/formats/)**——能放进书库的压缩包和电子书(PDF、EPUB、MOBI/AZW3、DjVu、FB2、TXT),以及各自怎么显示。 * **[用文档站测试 API](guide/api-testing/)**——在浏览器里直接对**你自己的实例**发请求,以及它不生效时的处理方式。 * **[插件开发入门](plugin/getting-started/)**——写一个元数据/登录/下载插件。 * **[API 参考](api/)**——完整的 HTTP API:每个端点、参数、响应,以及可直接复制的命令行。 ## 关于 API 参考 [Section titled “关于 API 参考”](#关于-api-参考) API 参考**不是手写的**。它由 `crates/lanrurugi-api-docgen` 从服务端自己的路由注册里生成,因此: * 服务端提供的每个端点都在里面,**不会**出现“代码里有、文档里没有”; * 它**不会**列出服务端其实不提供的端点; * 与 LANraragi 共有的端点,直接沿用 LANraragi 官方 OpenAPI 文档的字段级描述(路径前缀与鉴权部分除外); * 尚未写清请求/响应结构的端点会被明确标出,而不是被编造出一份看起来很像真的 schema。 CI 会在生成结果与代码不一致时直接失败,所以这份参考不会像手写文档那样慢慢过期。
# LANrurugi documentation
> A self-hosted library for manga first, and for e-books such as PDF and EPUB too, built on LANraragi and extensively reworked and extended in Rust + React — data- and API-compatible with an existing LANraragi deployment.
## What is in here [Section titled “What is in here”](#what-is-in-here) * **[Install (Docker / NAS)](guide/install/)** — get LANrurugi running and pointed at the library you already have. * **[Native install](guide/install-native/)** — run it directly on Linux, an Apple Silicon Mac or FreeBSD, without containers. * **[Quickstart](guide/quickstart/)** — first login, scanning the library, importing existing data. * **[Supported formats](guide/formats/)** — the archives and e-books (PDF, EPUB, MOBI/AZW3, DjVu, FB2, TXT) the library accepts, and how each is shown. * **[Testing the API from these docs](guide/api-testing/)** — send requests from your browser straight to **your own instance**, and what to do when it does not work. * **[Plugin authoring](plugin/getting-started/)** — write a metadata, login, or download plugin. * **[API reference](api/)** — the complete HTTP API: every endpoint, its parameters and responses, and a command line you can copy. ## About the API reference [Section titled “About the API reference”](#about-the-api-reference) The API reference is **not hand-written**. `crates/lanrurugi-api-docgen` generates it from the server’s own route registrations, which means: * Every endpoint the server serves is in it — “in the code but not in the docs” **cannot** happen; * It does **not** list endpoints the server does not actually serve; * For endpoints shared with LANraragi, it carries that project’s field-level descriptions verbatim (apart from the path prefix and the authentication section); * Endpoints whose request/response shapes have not been written down yet are **marked as such**, rather than being given an invented schema that merely looks plausible. CI fails outright when the generated result disagrees with the code, so this reference cannot rot the way a hand-maintained document does.
# Testing the API from these docs
> Send requests from your browser straight to your own running LANrurugi instance — preconditions, security boundaries, and what to do when it does not work.
Every endpoint in the [API reference](../../api/) has a request panel: enter a server address, enter a token, press send. This page explains exactly where that request goes, what it requires, and how to continue when the browser blocks it. ## Where the request goes [Section titled “Where the request goes”](#where-the-request-goes) **From your browser, straight to the address you type into the panel.** * The address and token you enter below live only in your browser’s local storage, and are sent only to that address. * This project has **no** intermediate server and **no** proxy. There is no path by which a user’s token or internal address reaches this project’s infrastructure. * The one exception is the page itself: the API description document (`openapi.json`) and the JavaScript that renders it are served from this documentation site’s own origin, not a CDN. This feature therefore needs no “public demo instance” — it was always aimed at your own instance. ## Preconditions [Section titled “Preconditions”](#preconditions) ### 1. Your instance must be reachable from this browser [Section titled “1. Your instance must be reachable from this browser”](#1-your-instance-must-be-reachable-from-this-browser) The address you enter must be reachable from **this browser**. If you are running the docs site on one machine and the instance on another, then `localhost` means the machine the browser is running on, not the machine the instance is running on. ### 2. Enable cross-origin access on the instance [Section titled “2. Enable cross-origin access on the instance”](#2-enable-cross-origin-access-on-the-instance) **“Enable CORS for the client API”** in the settings page must be on. It is off by default, and the browser will refuse cross-origin requests while it is. Once enabled, the instance permits the headers a browser needs to preflight — including the `Content-Type` that any JSON-bodied request requires. If your instance is on an older version and calls with a body always fail, that is usually this setting not covering it. ### 3. An HTTPS page can only call HTTPS instances and `http://localhost` [Section titled “3. An HTTPS page can only call HTTPS instances and http://localhost”](#3-an-https-page-can-only-call-https-instances-and-httplocalhost) This rule is enforced by the browser, not by LANrurugi: | Docs site | Instance address you enter | Result | | ----------- | -------------------------- | -------------------------------------------------------- | | `https://…` | `https://lrr.example.com` | ✅ works | | `https://…` | `http://localhost:3000` | ✅ works (browsers treat `localhost` as a trusted origin) | | `https://…` | `http://192.168.1.10:3000` | ❌ blocked as mixed content | | `http://…` | anything | ✅ works (the site itself is HTTP) | A LAN IP does **not** get `localhost`’s exemption. To test a LAN instance from an HTTPS docs site, there are two routes: * **Give the instance HTTPS**: a reverse proxy (Caddy / Traefik / nginx), a Cloudflare Tunnel, or a certificate-bearing entry point inside a VPN. * **Forward the port to localhost**:
```sh
ssh -L 3000:127.0.0.1:3000
```
then enter `http://localhost:3000` in the panel. The browser treats it as a trusted origin and it works directly. ## When the browser will not allow it: use the command line [Section titled “When the browser will not allow it: use the command line”](#when-the-browser-will-not-allow-it-use-the-command-line) **Every endpoint has a copyable command line (cURL)** in its code-sample panel. It is generated from the endpoint itself and depends on neither the browser, CORS, nor HTTPS, so it always works — reach for it whenever sending from the panel fails.
```sh
curl -H "Authorization: Bearer " \
"http://192.168.1.10:3000/api/archives?start=0&count=10"
```
## Reading a panel error [Section titled “Reading a panel error”](#reading-a-panel-error) * **Network error / failed to fetch**: check the three preconditions above first. Most often it is CORS not being enabled, a wrong address, or the mixed-content combination. * **401**: the token is wrong, or it has no permission for this endpoint. * **403**: the token is a guest token and this endpoint is administrator-only. * **404**: the path or the archive ID is wrong. ## Tokens [Section titled “Tokens”](#tokens) Create one under token management in the settings page. The token field in the panel only puts it into an `Authorization: Bearer ` header, stores it in your browser’s local storage, and sends it only to the address you entered. Do not enter a token on somebody else’s documentation site The premise of this page is that the documentation site is a static page. But “static page” is not the same as “trusted page” — only enter a token on a deployment you trust. If you are unsure whether a docs site is an official deployment, use cURL instead.
# Supported formats
> The archive and e-book formats the library accepts, how each is displayed, and where its table of contents comes from.
Every file in the library is an “archive” that you read page by page in the same reader. Besides archives of images, e-books such as PDF and EPUB can be dropped into the library directory or added from the upload page as they are, with no conversion step. ## Archives [Section titled “Archives”](#archives) | Format | Extensions | | -------------------- | -------------------------------------------------------------------------------------------- | | ZIP | `.zip` `.cbz` | | RAR (including RAR5) | `.rar` `.cbr` | | 7-Zip | `.7z` `.cb7` | | TAR | `.tar` `.cbt`, and tar compressed with gzip / bzip2 / xz / lzma (`.gz` `.bz2` `.xz` `.lzma`) | | LZH | `.lzh` `.lha` | Images that can be pages inside an archive: PNG, JPEG (`.jpg` `.jpeg` `.jfif`), GIF, BMP, WebP, AVIF, JPEG XL and HEIF/HEIC. Formats the browser cannot display (such as AVIF, JPEG XL or animated images on some browsers) are converted by the server first; HEIF/HEIC cannot be converted yet and only shows in browsers that support it natively (such as Safari). zstd-compressed files (`.zst`) are not supported yet and are not picked up. ## E-books [Section titled “E-books”](#e-books) | Format | Extensions | How pages are shown | Where the table of contents comes from | | ------------------- | ----------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | PDF | `.pdf` | Scanned pages are the picture stored in the PDF; text and vector pages are rendered | PDF bookmarks | | EPUB (fixed layout) | `.epub` | Each page is the picture stored in the book | The book’s own contents (nav / NCX) | | EPUB (reflowable) | `.epub` | Typeset into pages on the server, illustrations in place | The book’s own contents, down to where each chapter starts | | MOBI / AZW / AZW3 | `.mobi` `.azw` `.azw3` `.prc` | Comics: the stored picture per page; text books: typeset on the server | The book’s contents page or chapter headings | | DjVu | `.djvu` `.djv` | Rendered | DjVu bookmarks | | FB2 | `.fb2` | Typeset on the server, illustrations in place | The book’s sections | | Plain text | `.txt` | Typeset on the server | Chapter lines detected automatically (“Chapter 3”, “Prologue”, 第一章, 第十二回, …) | Notes: * **Pictures are never re-compressed.** Where a page is a picture stored in the book (scanned PDFs, fixed-layout EPUB, comic MOBI/AZW3, FB2 illustrations), the reader gets that exact picture. * **Text books are typeset by the server**, with a Simplified Chinese, Japanese or Korean font chosen by the book’s language; headings, paragraphs and illustrations all land on the page. Only horizontal text is supported for now. * **The table of contents is imported once, on first import**, and only into an archive that has no chapters yet, so chapters you edited are never overwritten. When the book’s own contents are missing or have just one or two entries (a cover or a licence page, say), they are completed from the headings and chapter lines in the text. * **Only `.txt` files of 8 KB or more are picked up**, so readme files and notes next to your archives are not mistaken for books. The encoding is detected automatically (UTF-8, UTF-16, GBK/GB18030, Big5, Shift_JIS, EUC-JP, EUC-KR and others), and text hard-wrapped at a fixed width is joined back into paragraphs. * **The library marks the format.** E-books show a small `PDF`, `EPUB`, … label beside their title, and a PDF can also be opened as-is in the browser from the reader. * Split suggestions only make sense for archives and are not offered for e-books. * Rendered pages of text books and text PDF pages are cached, and count towards the same “Settings → Archive Files → Maximum Reader Cache Size” limit as the reader’s other caches. ## What is not supported [Section titled “What is not supported”](#what-is-not-supported) * **DRM- or password-protected books** (for example store-bought Kindle books whose protection was not removed, or a PDF with an open password) cannot be read. They still appear in the library (with 0 pages); opening one shows why it cannot be read (protected by DRM or a password), and the server log records it too. * **Damaged or incomplete files** likewise report the reason and do not affect the rest of the library. * Kindle’s KFX format and HUFF/CDIC-compressed MOBI files (mostly Kindle dictionaries) are not supported yet.
# Install (Docker / NAS)
> Deploy LANrurugi on a server or NAS with Docker or Compose.
The LANrurugi server is one resident process holding the static frontend, the HTTP API, the file watcher and background jobs; plugins, e-book parsing and AI inference run in subprocesses started on demand. It has its own database and neither reads nor changes LANraragi’s, so the two can run side by side. Prefer not to use containers? There are [native packages](../install-native/) for Linux, macOS (Apple Silicon) and FreeBSD. ## Deploy with Compose (recommended) [Section titled “Deploy with Compose (recommended)”](#deploy-with-compose-recommended) Save the following as `compose.yaml`, change the host directories on the left as the comments describe, then start it:
```yaml
services:
lanrurugi:
image: ghcr.io/thelastfantasy/lanrurugi:latest
container_name: lanrurugi
ports:
- "3000:3000"
volumes:
# Library — can point straight at LANraragi's content directory
- ./data/manga:/home/koyomi/lanrurugi/content
# Thumbnail cache
- ./data/thumb:/home/koyomi/lanrurugi/thumb
# Redis data, LANrurugi only; LANraragi's metadata is imported from its backup JSON
- ./data/database:/home/koyomi/lanrurugi/database
# Embedding model for recommendations, downloaded on first use
- ./data/models:/home/koyomi/lanrurugi/models
environment:
# Set to true when served over HTTPS through a reverse proxy
- LANRURUGI_FORCE_SECURE_COOKIES=false
restart: unless-stopped
```
```sh
docker compose up -d # or: podman compose up -d
```
On a NAS (Synology Container Manager, Portainer and the like), create a compose project and paste the same text. Then open `http://:3000` in a browser. Redis is bundled in the image; no separate database container is needed. The four mounted directories: | Host path | Path in the container | Purpose | | ----------------- | --------------------------------- | ----------------------------------------- | | `./data/manga` | `/home/koyomi/lanrurugi/content` | Your library | | `./data/thumb` | `/home/koyomi/lanrurugi/thumb` | Thumbnail cache | | `./data/database` | `/home/koyomi/lanrurugi/database` | Redis data (LANrurugi only) | | `./data/models` | `/home/koyomi/lanrurugi/models` | Embedding model cache for recommendations | To serve it on a domain over HTTPS, see [Reverse proxy](../reverse-proxy/). ## Run it with plain Docker [Section titled “Run it with plain Docker”](#run-it-with-plain-docker)
```sh
docker run -d --name lanrurugi -p 3000:3000 \
-v /path/to/library:/home/koyomi/lanrurugi/content \
-v /path/to/thumb:/home/koyomi/lanrurugi/thumb \
-v /path/to/database:/home/koyomi/lanrurugi/database \
ghcr.io/thelastfantasy/lanrurugi:latest
```
## Where the image is published [Section titled “Where the image is published”](#where-the-image-is-published) The same image, for amd64 and arm64, is published to two registries: | Registry | Image | | --------------------------------------- | ---------------------------------- | | GitHub Container Registry (recommended) | `ghcr.io/thelastfantasy/lanrurugi` | | Docker Hub | `jade913/lanrurugi` | The examples above use GitHub’s registry. Docker Hub limits how often anonymous users can pull; if your NAS panel only searches Docker Hub, or you simply prefer it, use `jade913/lanrurugi` instead. `latest` points at the newest release; a specific version number works too. ## Build the image from source [Section titled “Build the image from source”](#build-the-image-from-source) The repository’s own `compose.yaml` builds from source for a trial run (`network_mode: host`, listening on port 3000):
```sh
podman compose up -d --build # or: docker compose up -d --build
```
## First login [Section titled “First login”](#first-login) The first visit opens the first-run wizard: change the admin password, add a DeepSeek API key for the AI features, and import a LANraragi backup. Every step can be skipped, and the wizard can be rerun from Settings later. A brand-new instance — or one migrated from an old installation whose password was never changed — uses LANraragi’s own default administrator password, **`kamimamita`**. Change the password first thing Change it in the settings page immediately after logging in. Do not leave an instance reachable from outside your local network while it still uses the default password. ## Reading this documentation offline [Section titled “Reading this documentation offline”](#reading-this-documentation-offline) The documentation site, the API reference, the Swagger UI and the plugin SDK reference are all baked into the image and served by the instance itself under `/docs`:
```text
http://:3000/docs/ guides and the per-group API reference (Chinese)
http://:3000/docs/en/ the same, in English
http://:3000/docs/swagger/ Swagger UI, Chinese content (schemas; send requests)
http://:3000/docs/swagger/en/ Swagger UI, English content
http://:3000/docs/sdk/ plugin SDK reference
```
No internet access is required: even Swagger UI’s JavaScript bundle and the SDK’s search index ship inside the image — nothing is loaded from a CDN. ## Toolchain (building from source) [Section titled “Toolchain (building from source)”](#toolchain-building-from-source) Versions are pinned in `.mise.toml`, and `mise install` reproduces them exactly (Rust, Node, Deno, pnpm, plus `sccache`/`mold`).
```sh
# Backend
cargo build --release -p lanrurugi-server
./target/release/lanrurugi-server serve --redis-url redis://127.0.0.1:6379 \
--library-path /path/to/existing/library
# Frontend dev server (proxies /api to the backend above)
pnpm --filter lanrurugi-frontend run dev
```
### CLI subcommands [Section titled “CLI subcommands”](#cli-subcommands) * `lanrurugi serve` — runs the HTTP API, static frontend, file watcher and plugin pool in one process. * `lanrurugi rebuild-index` — recomputes every archive’s ID with the size-aware algorithm and surfaces files that were historically hidden by a mistaken merge. * `lanrurugi bench` — generates a synthetic library and runs a concurrency/throughput comparison against a running legacy instance. ## Next [Section titled “Next”](#next) * [Quickstart](../quickstart/) * [Testing the API from these docs](../api-testing/)
# Native install (Linux / macOS / FreeBSD)
> Run LANrurugi directly on Linux, an Apple Silicon Mac or FreeBSD, without containers.
Besides the [Docker image](../install/), every release ships native packages for: | Package | Systems | | ------------------------------------------- | ----------------------------------------------------------------------------------- | | `lanrurugi--linux-x86_64.tar.gz` | 64-bit Linux with glibc 2.35 or newer (Debian 12, Ubuntu 22.04, Fedora 36, Arch, …) | | `lanrurugi--linux-aarch64.tar.gz` | ARM64 Linux, same baseline (e.g. Raspberry Pi 5, ARM servers) | | `lanrurugi--macos-arm64.tar.gz` | Apple Silicon Macs, macOS 13 or newer | | `lanrurugi--freebsd-x86_64.tar.gz` | FreeBSD 14 | Download them from the GitHub [Releases](https://github.com/thelastfantasy/LANrurugi/releases) page; `SHA256SUMS` lists every file’s checksum. Docker remains the least work if you would rather not manage dependencies; on Windows, use Docker Desktop. ## 1. Install the prerequisites [Section titled “1. Install the prerequisites”](#1-install-the-prerequisites) The database server, plugin runtime, DjVu tools and fonts come from your system’s package manager and are not in the package: | | Debian / Ubuntu | Fedora | Arch | macOS (Homebrew) | FreeBSD | | --------------------------------- | ------------------------------------ | -------------------------------------------------------------------- | ---------------------------- | -------------------------- | ------------------------------------------------------------------- | | Redis 7.4 or newer | `apt install redis-server` ¹ | `dnf install redis` ² | `pacman -S redis` | `brew install redis` | `pkg install redis` | | Deno (plugins) | [install script](https://deno.com) | [install script](https://deno.com) | `pacman -S deno` | `brew install deno` | `pkg install deno` | | DjVu books | `apt install djvulibre-bin` | `dnf install djvulibre` | `pacman -S djvulibre` | `brew install djvulibre` | `pkg install djvulibre` | | CJK fonts (text books) | `apt install fonts-noto-cjk` | `dnf install google-noto-serif-cjk-fonts google-noto-sans-cjk-fonts` | `pacman -S noto-fonts-cjk` | built in | `pkg install noto-serif-sc noto-sans-sc noto-serif-jp noto-sans-jp` | | Colour emoji font (text books) | `apt install fonts-noto-color-emoji` | `dnf install google-noto-color-emoji-fonts` | `pacman -S noto-fonts-emoji` | built in | `pkg install noto-emoji` | | Archive codecs | built in | built in | built in | `brew install xz lz4 zstd` | `pkg install lz4 zstd` | | PDF books | bundled | bundled | bundled | bundled | `pkg install pdfium` | | OCR, translation, recommendations | bundled | bundled | bundled | bundled | `pkg install onnxruntime` | | CA certificates (HTTPS) | `apt install ca-certificates` ³ | built in | built in | built in | `pkg install ca_root_nss` | ¹ Debian 12 ships Redis 7.0, which is fine for a new library; reusing data from a Docker deployment needs 7.4 or newer (use the redis.io repository). ² Recent Fedora installs Valkey, a Redis-compatible server. It is fine for a new library but cannot open data files written by Redis 7.4. ³ Minimal systems (slim containers, VMs) may lack them. It still runs without: when no system certificates are found, HTTPS falls back to the Mozilla roots built into the binary, which the startup log reports as `tls_roots=bundled`. System certificates follow your OS’s updates and also trust any certificate you add yourself. ## 2. Unpack and start [Section titled “2. Unpack and start”](#2-unpack-and-start)
```sh
tar -xzf lanrurugi--.tar.gz
cd lanrurugi--
redis-server --daemonize yes # or enable your system's Redis service
./bin/lanrurugi-server serve \
--library-path ~/manga \
--thumb-dir ~/.local/share/lanrurugi/thumb \
--temp-dir ~/.local/share/lanrurugi/temp \
--log-dir ~/.local/share/lanrurugi/log
```
Then open `http://:3000`. The first-run wizard changes the default password, takes the API key for the AI features and can import a LANraragi backup. The web interface, plugins, documentation, bundled libraries and models are found relative to the program itself, so the package works wherever you unpack it. It connects to `redis://127.0.0.1:6379` by default; change that with `--redis-url` or `LANRURUGI_REDIS_URL`. ## 3. Translation models (optional) [Section titled “3. Translation models (optional)”](#3-translation-models-optional)
```sh
./fetch-models.sh # text recognition and removal, several hundred MB
./fetch-models.sh --with-bubbles # also builds the speech-bubble model (needs uv)
```
The library and reader work without them; without the bubble model, translation erases text with rectangles. ## 4. Run as a service [Section titled “4. Run as a service”](#4-run-as-a-service)
```sh
sudo ./install-service.sh /var/lib/lanrurugi # Linux (systemd), FreeBSD (rc.d)
./install-service.sh ~/LANrurugi # macOS (launchd, current user)
```
The script creates the data directories and `lanrurugi.env` (library location, Redis URL, port), installs the service definition for your system and prints the command that starts it. Add `--print` to see the generated definition without installing it. ## Moving from a Docker deployment [Section titled “Moving from a Docker deployment”](#moving-from-a-docker-deployment) Reuse the container’s three mounted directories: `content` as the library and `thumb` as the thumbnail directory. Give the `database` directory to a Redis 7.4+ configured like `service/redis.conf.example` (its `dir` pointing there, port 16379), and set `LANRURUGI_REDIS_URL` to `redis://127.0.0.1:16379`. ## Features by platform [Section titled “Features by platform”](#features-by-platform) | Feature | Linux | macOS | FreeBSD | | ----------------------------------------- | -------------------------- | ------- | ---------------------------------------- | | Library, reader, search, archives | ✓ | ✓ | ✓ | | PDF / DjVu / EPUB / MOBI / FB2 / TXT | ✓ | ✓ | ✓ (PDF needs the `pdfium` package) | | Plugins, downloads, subscriptions | ✓ | ✓ | ✓ | | Recommendations, OCR, in-page translation | ✓ | ✓ (CPU) | ✓ (CPU; needs the `onnxruntime` package) | | GPU-accelerated inference | ✓ (as in the Docker image) | — | — | When an optional component is missing the server still starts; its start-up log prints `optional components` and `some features are unavailable on this system`, naming what is missing and which features it affects, and those features report the reason when used. ## Platforms not supported yet [Section titled “Platforms not supported yet”](#platforms-not-supported-yet) * **Windows**: use Docker Desktop. * **Intel Macs, other BSDs, musl distributions (e.g. Alpine)**: no packages; musl distributions can use the Docker image. * **HarmonyOS / OpenHarmony**: not supported. Apps there run in a sandbox with no supported way to keep a server running in the background, and none of Redis, Deno, PDFium or ONNX Runtime has a HarmonyOS build. The realistic route is a separate HarmonyOS reader app that connects to an existing LANrurugi server, rather than running the server on the device.
# llms.txt for AI tools
> What each llms.txt file on the homepage and the documentation site contains, and which one to give an AI assistant.
[llms.txt](https://llmstxt.org/) is a convention: a Markdown file at a site’s root that tells AI tools what a project is and where to read more. LANrurugi’s homepage and this documentation site both publish them. Give an AI assistant the right address and it can answer questions, help you deploy, write scripts against the API or write plugins from the documentation, instead of guessing from whatever it saw in training. ## The files [Section titled “The files”](#the-files) | Address | Contents | Size (approx.) | | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -------------- | | [`lrrg.dev/llms.txt`](https://lrrg.dev/llms.txt) | Entry point: what the project is, the HTTP API and the plugin SDK, and links to the main docs | 3.5 KB | | [`docs.lrrg.dev/llms.txt`](https://docs.lrrg.dev/llms.txt) | Index of this site: links to the files below, plus the API and SDK overview | 3 KB | | [`docs.lrrg.dev/llms-full.txt`](https://docs.lrrg.dev/llms-full.txt) | Every documentation page, in both languages, as one Markdown file | 800 KB | | [`docs.lrrg.dev/llms-small.txt`](https://docs.lrrg.dev/llms-small.txt) | Abridged: guides and plugin authoring only, without the API pages and asides | 80 KB | | [`…/_llms-txt/guides-english.txt`](https://docs.lrrg.dev/_llms-txt/guides-english.txt) | Guides and plugin authoring, English only | 40 KB | | [`…/_llms-txt/guides-simplified-chinese.txt`](https://docs.lrrg.dev/_llms-txt/guides-simplified-chinese.txt) | The same, Simplified Chinese | 40 KB | | [`…/_llms-txt/api-reference-english.txt`](https://docs.lrrg.dev/_llms-txt/api-reference-english.txt) | The API reference, English only, one section per group | 300 KB | | [`…/_llms-txt/api-reference-simplified-chinese.txt`](https://docs.lrrg.dev/_llms-txt/api-reference-simplified-chinese.txt) | The same, Simplified Chinese | 300 KB | Two structured files are linked from the llms.txt files as well: * [`docs.lrrg.dev/openapi.json`](https://docs.lrrg.dev/openapi.json): the complete HTTP API as OpenAPI 3.1. It is generated from the server’s own route registrations, so it lists exactly the endpoints the server serves. * [`sdk.lrrg.dev/plugin-sdk.json`](https://sdk.lrrg.dev/plugin-sdk.json): the plugin SDK reference as JSON, generated by `deno doc` from the TypeScript the plugin runtime loads. All of them are regenerated with every documentation release, from the same source as the pages, so they never drift apart. ## Which one to give an AI [Section titled “Which one to give an AI”](#which-one-to-give-an-ai) | You want the AI to | Give it | | ---------------------------------------------------- | --------------------------------------------------------------------------- | | Explain the project, answer general questions | `lrrg.dev/llms.txt` | | Help you deploy, debug an install or a reverse proxy | One language’s guides (`guides-*.txt`) or `llms-small.txt` | | Write a script or client for the API | `openapi.json`: more precise than the API pages’ Markdown, and fewer tokens | | Write a plugin | [Plugin authoring](../../plugin/getting-started/) plus `plugin-sdk.json` | | Have all the background, with a large enough context | `llms-full.txt` | If you only need a metadata, login or download plugin for one site, the instance’s own **AI Plugin Creation Wizard** fetches the target pages, writes the code and trial-runs it, which is usually less work than having an outside assistant start from nothing. ## How to hand it over [Section titled “How to hand it over”](#how-to-hand-it-over) * **AI tools that can browse** (chat assistants with web reading, coding agents): send the address, for example “Read `https://lrrg.dev/llms.txt` first, then …”. It follows the links inside for the parts it needs. * **Tools without web access**: download the files you need and attach or paste them. * **Coding agents working in a repository**: download `openapi.json` or `plugin-sdk.json` into the project, which is steadier than fetching it every time.
# Quickstart
> First login, creating an API token, scanning the library, importing existing data.
## 1. Log in [Section titled “1. Log in”](#1-log-in) Open `http://:3000`, log in with the default password `kamimamita`, then **change it in the settings page immediately**. ## 2. Point it at your library [Section titled “2. Point it at your library”](#2-point-it-at-your-library) `--library-path` (or `LANRURUGI_LIBRARY_PATH`) points at the directory holding your archives. It defaults to `./library`; under the Compose deployment that corresponds to the container’s `/home/koyomi/lanrurugi/content`. ## 3. Scan [Section titled “3. Scan”](#3-scan) Trigger a full scan from the settings page. Scanning is concurrent (Rayon) and does **not** delete archive records by itself — “a file disappeared during the scan” only cleans up path bookkeeping. Removing archive records is the separate, explicitly-triggered database cleanup. ## 4. Create an API token [Section titled “4. Create an API token”](#4-create-an-api-token) The request panels throughout the API reference need a token. Create one under token management in the settings page, then:
```sh
curl -H "Authorization: Bearer " http://localhost:3000/api/archives
```
Tokens come in two roles, administrator and guest; a guest token can only read. ## 5. Migrating from LANraragi [Section titled “5. Migrating from LANraragi”](#5-migrating-from-lanraragi) LANrurugi has its own database and neither reads nor changes LANraragi’s, so the two can run side by side. The steps are under “Moving from LANraragi” on the [install](../install/) page: mount the same manga directory as the library, give thumbnails and the database new directories, then import LANraragi’s backup JSON in the first-run wizard. The import pairs archives in the backup with the ones LANrurugi scanned by file name, never by ID: LANrurugi’s IDs are a size-aware fingerprint (`hash(first 512KB ++ big-endian u64 file size)`), unlike LANraragi’s `SHA-1(first 512KB)`. When several files share a name nothing is guessed; they count as ambiguous. Let the library scan finish before importing — archives not scanned yet count as skipped with no match. Different files that LANraragi wrongly merged as duplicates because their leading bytes matched show up separately in LANrurugi. ## 6. Try the API [Section titled “6. Try the API”](#6-try-the-api) Open the [API reference](../../api/) and, in the request panel, set the server address to your own instance (it already defaults to `http://localhost:3000`), fill in a token, and send the request. Requests go from your browser straight to your instance, never through this project. When the browser will not allow it (for example, this documentation is served over HTTPS while your instance is plain HTTP on a LAN address), every endpoint also carries a command line you can copy. Details are in [Testing the API from these docs](../api-testing/).
# Reverse proxy
> Serve LANrurugi on a domain over HTTPS with Nginx, Caddy, Traefik, Apache or Nginx Proxy Manager.
LANrurugi itself only speaks HTTP (by default on `0.0.0.0:3000`). To serve it on a domain over HTTPS, put a reverse proxy in front of it. Whichever proxy you use, it has to meet the conditions below. ## What the proxy has to do [Section titled “What the proxy has to do”](#what-the-proxy-has-to-do) * **Serve it at the root of a host.** The frontend requests the API at absolute `/api/...` paths, so mounting it under a sub-path (such as `example.com/lanrurugi/`) is not supported. Use a dedicated domain or subdomain such as `manga.example.com`. * **Forward three headers.** `X-Forwarded-Proto` (whether the request came in over HTTPS), `X-Forwarded-Host` (correct addresses for cross-domain login handoff and OpenSearch) and `X-Forwarded-For` (the real client IP in the activity log). Keep the original `Host` as well. * **Don’t buffer SSE.** Download-queue progress, the AI plugin wizard and archive-split suggestions stream over Server-Sent Events. If the proxy buffers the response, those screens stall and then update all at once when the request ends. The server sends a heartbeat every 15 seconds, so the usual 60-second read timeout is enough — but buffering has to be off. * **Allow large uploads.** Archive uploads are sent in chunks of up to 64 MB, and a legacy data import can be up to 100 MB in one request. The proxy’s body-size limit has to be at least that; the simplest choice is no limit. * **Turn on secure cookies once you’re on HTTPS.** Set `LANRURUGI_FORCE_SECURE_COOKIES=true` in the compose file. The server does not infer this from `X-Forwarded-Proto`: that header can be forged and this service has no trusted-proxy allowlist. Do **not** turn it on over plain HTTP — browsers would drop the login cookies and you could not sign in. WebSockets are not used. The examples assume LANrurugi and the proxy run on the same machine with LANrurugi on `127.0.0.1:3000`; if they share a compose network, use `lanrurugi:3000` instead. ## Nginx [Section titled “Nginx”](#nginx)
```nginx
server {
listen 443 ssl;
http2 on;
server_name manga.example.com;
ssl_certificate /etc/ssl/manga.example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/manga.example.com/privkey.pem;
# No upload size limit (chunked uploads send up to 64 MB per chunk)
client_max_body_size 0;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection "";
# SSE: no buffering, no timeout on long-lived streams
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 1h;
proxy_request_buffering off;
}
}
server {
listen 80;
server_name manga.example.com;
return 301 https://$host$request_uri;
}
```
## Caddy [Section titled “Caddy”](#caddy) Caddy obtains certificates automatically, forwards `X-Forwarded-*` by default and flushes `text/event-stream` responses immediately, so the configuration is as short as it gets:
```caddyfile
manga.example.com {
reverse_proxy 127.0.0.1:3000
}
```
## Traefik [Section titled “Traefik”](#traefik) Add labels to the LANrurugi compose service (this assumes Traefik already has an entrypoint named `websecure` and a certificate resolver named `letsencrypt`, on the same Docker network):
```yaml
services:
lanrurugi:
image: ghcr.io/thelastfantasy/lanrurugi:latest
# Traefik serves it, so port 3000 no longer needs publishing
volumes:
- ./data/manga:/home/koyomi/lanrurugi/content
- ./data/thumb:/home/koyomi/lanrurugi/thumb
- ./data/database:/home/koyomi/lanrurugi/database
- ./data/models:/home/koyomi/lanrurugi/models
environment:
- LANRURUGI_FORCE_SECURE_COOKIES=true
labels:
- traefik.enable=true
- traefik.http.routers.lanrurugi.rule=Host(`manga.example.com`)
- traefik.http.routers.lanrurugi.entrypoints=websecure
- traefik.http.routers.lanrurugi.tls.certresolver=letsencrypt
- traefik.http.services.lanrurugi.loadbalancer.server.port=3000
restart: unless-stopped
```
Traefik forwards `X-Forwarded-*`, doesn’t buffer responses and doesn’t limit request bodies by default, so no extra middleware is needed. ## Apache httpd [Section titled “Apache httpd”](#apache-httpd) Enable `mod_proxy`, `mod_proxy_http`, `mod_headers` and `mod_ssl`:
```apache
ServerName manga.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/manga.example.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/manga.example.com/privkey.pem
ProxyPreserveHost On
# mod_proxy sets X-Forwarded-For and X-Forwarded-Host itself
RequestHeader set X-Forwarded-Proto "https"
# flushpackets=on delivers SSE events to the browser immediately
ProxyPass / http://127.0.0.1:3000/ flushpackets=on timeout=3600
ProxyPassReverse / http://127.0.0.1:3000/
# No upload size limit
LimitRequestBody 0
```
## Nginx Proxy Manager [Section titled “Nginx Proxy Manager”](#nginx-proxy-manager) Many NAS users manage certificates with it. Create a Proxy Host: * **Details**: Domain `manga.example.com`, Scheme `http`, Forward Hostname / IP and Port pointing at LANrurugi and `3000`. * **SSL**: request a certificate and tick *Force SSL*. * **Advanced**: paste
```nginx
client_max_body_size 0;
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 1h;
proxy_set_header X-Forwarded-Host $host;
```
Nginx Proxy Manager already forwards `Host`, `X-Forwarded-Proto` and `X-Forwarded-For` by default. ## Checking the setup [Section titled “Checking the setup”](#checking-the-setup) 1. Open `https://manga.example.com`; you can sign in, and you stay signed in after a refresh. 2. Add a task to the download queue; its progress bar should advance steadily rather than jump to 100% only when it finishes. 3. On the activity log page (`/activity`), sign-ins show your client IP rather than the proxy’s address.
# Plugin authoring
> Write LANrurugi's metadata / login / download plugins in TypeScript.
A LANrurugi plugin is a **single `.ts` file**, placed under `plugins//` or uploaded through the settings page / `POST /api/plugins/upload` (which lands in `plugins/custom//`). It runs in a **separate Deno subprocess** holding only the permissions the plugin itself declares (`--allow-net` / `--allow-read` and so on), with no access to anything in the host process. ## Minimal plugin [Section titled “Minimal plugin”](#minimal-plugin) A plugin file must export exactly two things: 1. `pluginInfo()` — synchronous, side-effect free, returning only the plugin’s own metadata: namespace, name, parameters, declared permissions. The host calls it in a **zero-permission** one-shot subprocess purely to read that metadata, and only then requests the real permissions it declared. 2. The execution function for its category — `execMetadata` (metadata fetching), `execLogin` (login), or `execDownload` (downloading). For the exact signatures, the types, and what every field means, see the **[SDK reference](../sdk/)**: `deno doc` generates it directly from the same TypeScript the runtime loads, so it cannot drift from the real behaviour. ## Permissions [Section titled “Permissions”](#permissions) A plugin has to **declare up front** what it needs, and the host grants exactly that. This is what stops a misbehaving or malicious plugin from taking down the host process or reading files it should not. Any network or file access beyond the declaration fails. ## Debugging [Section titled “Debugging”](#debugging) * The settings page’s plugin list shows each plugin’s `pluginInfo()` result, including its declared permissions. * When a plugin call fails, the host records the subprocess’s stderr alongside it; the logs page can be filtered by category. * HTTP requests are relayed through the host and minimised on demand — plugin requests are proxied by the host, so a plugin needs nothing beyond `--allow-net`, and they can be rate-limited and logged in one place. ## Next [Section titled “Next”](#next) * [SDK reference](../sdk/) — every exported type and function, with its documentation comments. * [API reference](../../api/) — the endpoints under `/api/plugins*` (list, upload, execute, export).
# SDK Reference
> The API reference for the TypeScript the plugin runtime actually loads.
Every type and function a plugin author can use, generated by `deno doc` straight from **the same TypeScript the plugin runtime loads** (`plugin-sdk.ts` and `dispatcher.ts` under `crates/lanrurugi-plugin/dispatcher/`, plus `plugins/legacy-globals.d.ts`) — so it cannot drift from what the host actually does. [Open the SDK reference →](https://sdk.lrrg.dev/) That reference supports symbol search, grouping by type/interface/function, and shows each symbol’s own documentation comment. The same content is also published as machine-readable JSON (`plugin-sdk.json`) for tooling. ## Related [Section titled “Related”](#related) * [Plugin authoring intro](../getting-started/) — a minimal plugin, the permission model, debugging. * [API reference](../../api/) — the endpoints under `/api/plugins*`.
# 用文档站测试 API
> 在浏览器里直接对你自己正在运行的 LANrurugi 实例发请求——前置条件、安全边界,以及它不生效时怎么办。
[API 参考](../../api/) 里每个端点都有一个请求面板:填服务器地址、填令牌、点发送。这一页说明它到底 把请求发到哪里、需要什么前置条件,以及浏览器拦下来的时候怎么继续。 ## 请求发到哪里 [Section titled “请求发到哪里”](#请求发到哪里) **从你的浏览器,直接发到你在面板里填的那个地址。** * 你在下面填的地址与令牌,只存在你浏览器的本地存储里,也只发往那个地址。 * 本项目**没有**中间服务器、**没有**代理。绝不会有一条路径把用户的令牌或内网地址送到本项目的基础设施。 * 唯一的例外是页面本身:API 描述文档(`openapi.json`)和 Scalar 的运行时都由文档站同源提供,不走外部 CDN。 因此这个功能不需要任何“公开 demo 实例”——它的目标从来就是你自己的实例。 ## 前置条件 [Section titled “前置条件”](#前置条件) ### 1. 你的实例要对这个浏览器可达 [Section titled “1. 你的实例要对这个浏览器可达”](#1-你的实例要对这个浏览器可达) 面板里填的地址必须是**当前浏览器**能访问到的。你在这台机器上跑文档站、实例在另一台机器上,那么 `localhost` 指的是浏览器所在的机器,不是实例所在的机器。 ### 2. 在实例上打开跨源访问 [Section titled “2. 在实例上打开跨源访问”](#2-在实例上打开跨源访问) 设置页面里的 **「为客户端 API 启用 CORS」** 必须打开。默认是关闭的,此时浏览器会拒绝跨源请求。 打开之后,实例会允许浏览器预检所需的头——包括带 JSON 请求体时必需的 `Content-Type`。如果你的实例版本较 旧、带请求体的调用总是失败,多半就是这一项没有覆盖到。 ### 3. HTTPS 页面只能调用 HTTPS 实例和 `http://localhost` [Section titled “3. HTTPS 页面只能调用 HTTPS 实例和 http://localhost”](#3-https-页面只能调用-https-实例和-httplocalhost) 这是浏览器强制执行的规则,和 LANrurugi 无关: | 文档站 | 你填的实例地址 | 结果 | | ----------- | -------------------------- | ----------------------------- | | `https://…` | `https://lrr.example.com` | ✅ 可用 | | `https://…` | `http://localhost:3000` | ✅ 可用(浏览器把 `localhost` 当作可信来源) | | `https://…` | `http://192.168.1.10:3000` | ❌ 被当作混合内容拦掉 | | `http://…` | 任意 | ✅ 可用(站点本身也是 HTTP) | 局域网 IP **不**享受 `localhost` 那个豁免。想在 HTTPS 文档站上测试局域网里的实例,两条路: * **给实例配 HTTPS**:反向代理(Caddy / Traefik / nginx)、Cloudflare Tunnel,或者 VPN 里带证书的入口。 * **把端口转发到 localhost**:
```sh
ssh -L 3000:127.0.0.1:3000 <跑着实例的机器>
```
然后在面板里填 `http://localhost:3000`。浏览器把它当作可信来源,直接可用。 ## 浏览器不允许的时候:用命令行 [Section titled “浏览器不允许的时候:用命令行”](#浏览器不允许的时候用命令行) **每个端点都有一份可直接复制的命令行(cURL)**,在代码示例面板里。它由端点本身生成,不依赖浏览器、 不依赖 CORS、不依赖 HTTPS,永远可用——面板里发送失败时,用它。
```sh
curl -H "Authorization: Bearer <你的令牌>" \
"http://192.168.1.10:3000/api/archives?start=0&count=10"
```
## 面板报错时怎么读 [Section titled “面板报错时怎么读”](#面板报错时怎么读) * **网络错误 / failed to fetch**:先看上面三条前置条件。最常见的是 CORS 没开、地址填错,或者那份「 混合内容」的组合。 * **401**:令牌不对,或者令牌没有这个端点的权限。 * **403**:令牌是访客类型的,而这个端点只允许管理员。 * **404**:路径或档案 ID 不对。 ## 令牌 [Section titled “令牌”](#令牌) 在设置页面的令牌管理里创建。面板里的令牌字段只是把它放进 `Authorization: Bearer ` 头,存在你 浏览器的本地存储里,也只会发往你填的那个地址。 别在别人的文档站上填令牌 这一页的前提是文档站只是个静态页面。但“静态页面”不等于“可信页面”——对你信任的部署再填令牌。如果你不 确定某个文档站是不是官方部署,直接用 cURL。
# 支持的格式
> 能放进书库的压缩包与电子书格式,以及每种格式怎么显示、目录从哪里来。
书库里的每个文件都是一本「档案」,在同一个阅读器里一页一页地读。除了装着图片的压缩包,PDF、EPUB 等 电子书也可以直接放进书库目录或通过上传页加入,不需要先转换。 ## 压缩包 [Section titled “压缩包”](#压缩包) | 格式 | 扩展名 | | ----------- | ----------------------------------------------------------------------------- | | ZIP | `.zip` `.cbz` | | RAR(含 RAR5) | `.rar` `.cbr` | | 7-Zip | `.7z` `.cb7` | | TAR | `.tar` `.cbt`,以及 gzip / bzip2 / xz / lzma 压缩的 tar(`.gz` `.bz2` `.xz` `.lzma`) | | LZH | `.lzh` `.lha` | 压缩包里能作为页面的图片:PNG、JPEG(`.jpg` `.jpeg` `.jfif`)、GIF、BMP、WebP、AVIF、JPEG XL、HEIF/HEIC。 浏览器显示不了的格式(例如部分浏览器上的 AVIF、JPEG XL 和动画图)会由服务端转换后再显示;HEIF/HEIC 目前 无法转换,只有原生支持它的浏览器(例如 Safari)能显示。 用 zstd 压缩的文件(`.zst`)目前不支持,不会被收录。 ## 电子书 [Section titled “电子书”](#电子书) | 格式 | 扩展名 | 页面怎么显示 | 目录从哪里来 | | ----------------- | ----------------------------- | ------------------------------ | ----------------------------------- | | PDF | `.pdf` | 扫描页直接输出 PDF 里存的原图;文字页、矢量页渲染成图片 | PDF 书签 | | EPUB(固定版式) | `.epub` | 每一页输出书里存的原图 | 书自带的目录(nav / NCX) | | EPUB(流式文字) | `.epub` | 服务端排版成页,插图随文排入 | 书自带的目录,精确到章节所在的位置 | | MOBI / AZW / AZW3 | `.mobi` `.azw` `.azw3` `.prc` | 漫画:每页输出原图;文字书:服务端排版 | 书里的目录页或章节标题 | | DjVu | `.djvu` `.djv` | 渲染成图片 | DjVu 书签 | | FB2 | `.fb2` | 服务端排版,插图随文排入 | 书的章节结构 | | 纯文本 | `.txt` | 服务端排版 | 自动识别「第一章」「第十二回」「序章」「Chapter 3」这类章节行 | 几点说明: * **原图不重新压缩。** 书里存的是图片的页面(扫描版 PDF、固定版式 EPUB、漫画 MOBI/AZW3、FB2 插图), 阅读器拿到的就是书里那张图本身。 * **文字书由服务端排版。** 正文按书的语言选用简体中文、日文或韩文字体,标题、段落、插图都会排进页面; 目前只支持横排。 * **目录只在首次入库时导入**,而且只在档案还没有章节目录时才导入,不会覆盖你手动编辑过的目录。书自带的 目录缺失或只有一两条(比如只有封面、版权页)时,会从正文里的标题和章节行补全。 * **TXT 只收录 8 KB 以上的文件**,避免把书库里的说明文件、备注当成书。编码自动识别(UTF-8、UTF-16、 GBK/GB18030、Big5、Shift_JIS、EUC-JP、EUC-KR 等);按固定宽度折行的文本会重新拼回段落。 * **书库里会标出格式。** 电子书在标题旁显示 `PDF`、`EPUB` 之类的小标签;PDF 还可以在阅读页里直接用浏览器 打开原文件。 * 拆包建议只对压缩包有意义,电子书不提供。 * 文字书和 PDF 文字页渲染出的页面会缓存起来,与阅读器的其它缓存一起受 「设置 → 档案文件 → 最大阅读缓存大小」限制。 ## 不支持的情况 [Section titled “不支持的情况”](#不支持的情况) * **带 DRM 或密码保护的书**(例如从商店购买、未去除保护的 Kindle 书,或加了打开密码的 PDF)无法读取。 这类文件仍会出现在书库里(0 页),打开时阅读器会显示无法读取的原因(受 DRM 或密码保护),服务端日志里也会 记录。 * **损坏或不完整的文件**同样会提示具体原因,不影响书库里的其它书。 * Kindle 的 KFX 格式,以及使用 HUFF/CDIC 压缩的 MOBI(多见于 Kindle 词典)暂不支持。
# 安装(Docker / NAS)
> 用 Docker 或 Compose 在服务器/NAS 上部署 LANrurugi。
LANrurugi 的服务端是一个常驻进程,前端静态资源、HTTP API、文件监视器和后台任务都在里面;插件、电子书解析和 AI 推理在按需启动的子进程里运行。它有自己的数据库,不读取也不改动 LANraragi 的数据库,两者可以同时运行。 不想用容器的话,也可以用 Linux、macOS(Apple Silicon)和 FreeBSD 的[原生安装包](../install-native/)。 ## 用 Compose 部署(推荐) [Section titled “用 Compose 部署(推荐)”](#用-compose-部署推荐) 把下面这段保存为 `compose.yaml`,按注释把左侧的宿主机目录改成你自己的,然后启动:
```yaml
services:
lanrurugi:
image: ghcr.io/thelastfantasy/lanrurugi:latest
container_name: lanrurugi
ports:
- "3000:3000"
volumes:
# 书库,可以直接指向旧版 LANraragi 的 content 目录
- ./data/manga:/home/koyomi/lanrurugi/content
# 缩略图缓存
- ./data/thumb:/home/koyomi/lanrurugi/thumb
# Redis 数据,LANrurugi 专用;LANraragi 的元数据通过备份 JSON 导入
- ./data/database:/home/koyomi/lanrurugi/database
# 推荐功能的嵌入模型,首次用到时自动下载
- ./data/models:/home/koyomi/lanrurugi/models
environment:
# 经 HTTPS 反向代理访问时改为 true
- LANRURUGI_FORCE_SECURE_COOKIES=false
restart: unless-stopped
```
```sh
docker compose up -d # 或 podman compose up -d
```
NAS 上(群晖 Container Manager、Portainer 等)新建一个 compose 项目,粘贴同一段文本即可。 启动后在浏览器打开 `http://<服务器地址>:3000`。镜像自带 Redis,不需要额外的数据库容器。四个挂载目录: | 宿主机路径 | 容器内路径 | 用途 | | ----------------- | --------------------------------- | ---------------------- | | `./data/manga` | `/home/koyomi/lanrurugi/content` | 你的档案库 | | `./data/thumb` | `/home/koyomi/lanrurugi/thumb` | 缩略图缓存 | | `./data/database` | `/home/koyomi/lanrurugi/database` | Redis 数据(LANrurugi 专用) | | `./data/models` | `/home/koyomi/lanrurugi/models` | 推荐功能的嵌入模型缓存 | 要通过域名和 HTTPS 访问,见[反向代理](../reverse-proxy/)。 ## 直接用 Docker 运行 [Section titled “直接用 Docker 运行”](#直接用-docker-运行)
```sh
docker run -d --name lanrurugi -p 3000:3000 \
-v /path/to/library:/home/koyomi/lanrurugi/content \
-v /path/to/thumb:/home/koyomi/lanrurugi/thumb \
-v /path/to/database:/home/koyomi/lanrurugi/database \
ghcr.io/thelastfantasy/lanrurugi:latest
```
## 镜像来源 [Section titled “镜像来源”](#镜像来源) 同一个镜像同时发布在两个仓库,内容完全相同,都包含 amd64 和 arm64 两种架构: | 仓库 | 镜像名 | | ----------------------------- | ---------------------------------- | | GitHub Container Registry(推荐) | `ghcr.io/thelastfantasy/lanrurugi` | | Docker Hub | `jade913/lanrurugi` | 上面的示例用的是 GitHub 的仓库。Docker Hub 对未登录用户有拉取次数限制;如果你的 NAS 面板只能从 Docker Hub 搜索镜像,或者你更习惯用它,把镜像名换成 `jade913/lanrurugi` 即可。`latest` 指向最新的正式版本, 也可以写具体的版本号。 ## 从源码构建镜像 [Section titled “从源码构建镜像”](#从源码构建镜像) 仓库根目录的 `compose.yaml` 用于从源码构建并试运行(`network_mode: host`,监听 3000 端口):
```sh
podman compose up -d --build # 或 docker compose up -d --build
```
## 首次登录 [Section titled “首次登录”](#首次登录) 首次打开时会出现首次运行向导:修改管理员密码、填写 AI 功能用的 DeepSeek API 密钥、从 LANraragi 备份导入 数据,每一步都可以跳过,之后也能在设置页面重新运行。 一个全新实例——或者从一个从未修改过密码的旧版安装迁移过来的实例——使用的是旧版 LANraragi 自身的默认 管理员密码 **`kamimamita`**。 第一件事就是改密码 登录后请立刻在设置页面修改密码。不要让一个还在用默认密码的实例可以从本地网络之外访问。 ## 离线阅读本文档 [Section titled “离线阅读本文档”](#离线阅读本文档) 文档站、API 正文参考、Swagger UI 和插件 SDK 参考都打包在镜像里,由实例自己在 `/docs` 下提供:
```text
http://<你的实例地址>:3000/docs/ 指南与按分组的 API 正文参考(中文)
http://<你的实例地址>:3000/docs/en/ 同上,英文版
http://<你的实例地址>:3000/docs/swagger/ Swagger UI,中文内容(可看 schema,可试发请求)
http://<你的实例地址>:3000/docs/swagger/en/ Swagger UI,英文内容
http://<你的实例地址>:3000/docs/sdk/ 插件 SDK 参考
```
不需要外网:连 Swagger UI 的 JS 打包和 SDK 的搜索索引都在镜像里,没有任何资源来自 CDN。 ## 工具链(从源码构建) [Section titled “工具链(从源码构建)”](#工具链从源码构建) 版本固定在 `.mise.toml` 里,`mise install` 会精确复现它们(Rust、Node、Deno、pnpm,以及 `sccache`/`mold`)。
```sh
# 后端
cargo build --release -p lanrurugi-server
./target/release/lanrurugi-server serve --redis-url redis://127.0.0.1:6379 \
--library-path /path/to/existing/library
# 前端开发服务器(把 /api 代理到上面的后端)
pnpm --filter lanrurugi-frontend run dev
```
### CLI 子命令 [Section titled “CLI 子命令”](#cli-子命令) * `lanrurugi serve`——在同一个进程里运行 HTTP API、静态前端、文件监视器与插件池。 * `lanrurugi rebuild-index`——用大小感知算法重新计算每个档案的 ID,并发现历史上曾被误判合并而隐藏的 文件。 * `lanrurugi bench`——生成合成库,并针对一个正在运行的旧版实例做并发/吞吐量对比。 ## 下一步 [Section titled “下一步”](#下一步) * [快速开始](../quickstart/) * [用文档站测试 API](../api-testing/)
# 原生安装(Linux / macOS / FreeBSD)
> 不用容器,直接在 Linux、Apple Silicon Mac 或 FreeBSD 上运行 LANrurugi。
除了 [Docker 镜像](../install/),每个版本还提供以下平台的原生安装包: | 安装包 | 适用系统 | | -------------------------------------- | ------------------------------------------------------------------ | | `lanrurugi-<版本>-linux-x86_64.tar.gz` | 64 位 Linux(glibc 2.35 及以上:Debian 12、Ubuntu 22.04、Fedora 36、Arch 等) | | `lanrurugi-<版本>-linux-aarch64.tar.gz` | ARM64 Linux(同上,例如树莓派 5、ARM 服务器) | | `lanrurugi-<版本>-macos-arm64.tar.gz` | Apple Silicon Mac(macOS 13 及以上) | | `lanrurugi-<版本>-freebsd-x86_64.tar.gz` | FreeBSD 14 | 安装包在 GitHub 的 [Releases](https://github.com/thelastfantasy/LANrurugi/releases) 页面,`SHA256SUMS` 里有每个文件的校验值。 不想管理依赖的话,Docker 仍然是最省事的方式;Windows 用户请使用 Docker Desktop。 ## 1. 安装依赖 [Section titled “1. 安装依赖”](#1-安装依赖) 数据库、插件运行环境、DjVu 工具和字体由系统的包管理器安装,安装包里不附带: | | Debian / Ubuntu | Fedora | Arch | macOS(Homebrew) | FreeBSD | | ---------------- | ------------------------------------ | -------------------------------------------------------------------- | ---------------------------- | -------------------------- | ------------------------------------------------------------------- | | Redis 7.4 及以上 | `apt install redis-server` ¹ | `dnf install redis` ² | `pacman -S redis` | `brew install redis` | `pkg install redis` | | Deno(插件) | [官方安装脚本](https://deno.com) | [官方安装脚本](https://deno.com) | `pacman -S deno` | `brew install deno` | `pkg install deno` | | DjVu 阅读 | `apt install djvulibre-bin` | `dnf install djvulibre` | `pacman -S djvulibre` | `brew install djvulibre` | `pkg install djvulibre` | | 中日韩字体(文字书) | `apt install fonts-noto-cjk` | `dnf install google-noto-serif-cjk-fonts google-noto-sans-cjk-fonts` | `pacman -S noto-fonts-cjk` | 系统自带,无需安装 | `pkg install noto-serif-sc noto-sans-sc noto-serif-jp noto-sans-jp` | | 彩色 emoji 字体(文字书) | `apt install fonts-noto-color-emoji` | `dnf install google-noto-color-emoji-fonts` | `pacman -S noto-fonts-emoji` | 系统自带,无需安装 | `pkg install noto-emoji` | | 压缩包解码库 | 系统自带 | 系统自带 | 系统自带 | `brew install xz lz4 zstd` | `pkg install lz4 zstd` | | PDF 阅读 | 安装包自带 | 安装包自带 | 安装包自带 | 安装包自带 | `pkg install pdfium` | | OCR、翻译、推荐 | 安装包自带 | 安装包自带 | 安装包自带 | 安装包自带 | `pkg install onnxruntime` | | CA 证书(HTTPS) | `apt install ca-certificates` ³ | 系统自带 | 系统自带 | 系统自带 | `pkg install ca_root_nss` | ¹ Debian 12 自带的是 Redis 7.0,用于新书库没有问题;要沿用 Docker 部署留下的数据,需要 7.4 及以上(可使用 redis.io 的软件源)。 ² 较新的 Fedora 实际安装的是兼容 Redis 的 Valkey,用于新书库没有问题,但它读不了 Redis 7.4 写出的数据文件。 ³ 精简系统(最小化容器、虚拟机)可能没有装。不装也能运行:程序找不到系统证书时,HTTPS 会改用内置的 Mozilla 根证书,启动日志里的 `tls_roots=bundled` 表示这种情况。装上系统证书则跟随系统更新,也能识别你自己添加的证书。 ## 2. 解压并启动 [Section titled “2. 解压并启动”](#2-解压并启动)
```sh
tar -xzf lanrurugi-<版本>-<平台>.tar.gz
cd lanrurugi-<版本>-<平台>
redis-server --daemonize yes # 或启用系统自带的 Redis 服务
./bin/lanrurugi-server serve \
--library-path ~/manga \
--thumb-dir ~/.local/share/lanrurugi/thumb \
--temp-dir ~/.local/share/lanrurugi/temp \
--log-dir ~/.local/share/lanrurugi/log
```
然后打开 `http://<你的机器>:3000`,首次运行向导会引导你修改默认密码、填写 AI 功能用的 API 密钥、导入 LANraragi 备份。 前端、插件、文档、自带的原生库和模型都按程序自己的位置查找,解压到哪里都可以,不需要再设置其它路径。 默认连接 `redis://127.0.0.1:6379`,用 `--redis-url` 或环境变量 `LANRURUGI_REDIS_URL` 修改。 ## 3. 下载翻译模型(可选) [Section titled “3. 下载翻译模型(可选)”](#3-下载翻译模型可选)
```sh
./fetch-models.sh # 文字识别与擦除模型,几百 MB
./fetch-models.sh --with-bubbles # 另外生成对话框分割模型(需要 uv)
```
不下载也能正常使用书库和阅读器;没有对话框分割模型时,翻译用矩形框擦除原文。 ## 4. 作为系统服务运行 [Section titled “4. 作为系统服务运行”](#4-作为系统服务运行)
```sh
sudo ./install-service.sh /var/lib/lanrurugi # Linux(systemd)、FreeBSD(rc.d)
./install-service.sh ~/LANrurugi # macOS(launchd,当前用户)
```
脚本会创建数据目录和 `lanrurugi.env`(书库位置、Redis 地址、监听端口),并为当前系统安装服务定义,最后提示启动命令。 只想看生成的服务文件而不安装,加 `--print`。 ## 从 Docker 部署迁移 [Section titled “从 Docker 部署迁移”](#从-docker-部署迁移) 把容器挂载的三个目录直接拿过来用:`content` 作为书库,`thumb` 作为缩略图目录。`database` 目录交给一个按 `service/redis.conf.example` 配置的 Redis(7.4 及以上),它的 `dir` 指向这个目录,端口 16379;再把 `LANRURUGI_REDIS_URL` 设为 `redis://127.0.0.1:16379`。 ## 各平台功能 [Section titled “各平台功能”](#各平台功能) | 功能 | Linux | macOS | FreeBSD | | ------------------------------------ | ---------------- | ------ | ------------------------ | | 书库、阅读、搜索、压缩包 | ✓ | ✓ | ✓ | | PDF / DjVu / EPUB / MOBI / FB2 / TXT | ✓ | ✓ | ✓(PDF 需 `pdfium` 包) | | 插件、下载、订阅 | ✓ | ✓ | ✓ | | 推荐、OCR、页面翻译 | ✓ | ✓(CPU) | ✓(CPU,需 `onnxruntime` 包) | | GPU 加速推理 | ✓(与 Docker 镜像相同) | — | — | 缺少某个可选组件时服务照常启动,启动日志会列出 `optional components` 和 `some features are unavailable on this system`,说明缺了什么、影响哪些功能;用到这些功能时也会显示原因。 ## 尚未支持的平台 [Section titled “尚未支持的平台”](#尚未支持的平台) * **Windows**:请使用 Docker Desktop。 * **Intel Mac、其它 BSD、musl 发行版(如 Alpine)**:没有提供安装包;musl 发行版请使用 Docker 镜像。 * **鸿蒙(HarmonyOS / OpenHarmony)**:暂不支持。鸿蒙系统上的应用运行在沙箱里,不支持长期在后台运行的 服务端程序,LANrurugi 依赖的 Redis、Deno、PDFium、ONNX Runtime 也都没有鸿蒙版本。可行的方向是另做 一个连接现有 LANrurugi 服务端的鸿蒙阅读客户端,而不是在设备上运行服务端。
# 给 AI 工具用的 llms.txt
> 项目主页和文档站提供的 llms.txt 系列文件各自包含什么,以及让 AI 助手了解 LANrurugi 时该给它哪一份。
[llms.txt](https://llmstxt.org/) 是一种约定:在站点根目录放一份 Markdown 文件,告诉 AI 工具这个项目是什么、 更详细的内容去哪里读。LANrurugi 的项目主页和文档站都提供了这类文件。把对应的地址交给 AI 助手, 它就能按文档回答问题、帮你部署、写调用 API 的脚本或者写插件,而不必只凭训练时的印象猜。 ## 文件一览 [Section titled “文件一览”](#文件一览) | 地址 | 内容 | 大小(约) | | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------ | | [`lrrg.dev/llms.txt`](https://lrrg.dev/llms.txt) | 入口:项目简介、HTTP API 与插件 SDK 的说明,以及主要文档的链接 | 3.5 KB | | [`docs.lrrg.dev/llms.txt`](https://docs.lrrg.dev/llms.txt) | 文档站目录:下面各文件的链接,以及 API 与 SDK 的说明 | 3 KB | | [`docs.lrrg.dev/llms-full.txt`](https://docs.lrrg.dev/llms-full.txt) | 全部文档页,中英两种语言,合成一个 Markdown 文件 | 800 KB | | [`docs.lrrg.dev/llms-small.txt`](https://docs.lrrg.dev/llms-small.txt) | 精简版:只含指南和插件开发,去掉 API 参考页与提示框 | 80 KB | | [`…/_llms-txt/guides-simplified-chinese.txt`](https://docs.lrrg.dev/_llms-txt/guides-simplified-chinese.txt) | 只含中文的指南与插件开发 | 40 KB | | [`…/_llms-txt/guides-english.txt`](https://docs.lrrg.dev/_llms-txt/guides-english.txt) | 同上,英文 | 40 KB | | [`…/_llms-txt/api-reference-simplified-chinese.txt`](https://docs.lrrg.dev/_llms-txt/api-reference-simplified-chinese.txt) | 只含中文的 API 参考,每组一节 | 300 KB | | [`…/_llms-txt/api-reference-english.txt`](https://docs.lrrg.dev/_llms-txt/api-reference-english.txt) | 同上,英文 | 300 KB | 另有两份结构化数据,llms.txt 里也有链接: * [`docs.lrrg.dev/openapi.json`](https://docs.lrrg.dev/openapi.json):完整的 HTTP API,OpenAPI 3.1 格式。它由服务器 自己注册的路由生成,列出的正是服务器实际提供的全部端点。 * [`sdk.lrrg.dev/plugin-sdk.json`](https://sdk.lrrg.dev/plugin-sdk.json):插件 SDK 参考的 JSON 版,由 `deno doc` 从插件运行时实际加载的 TypeScript 生成。 这些文件在每次发布文档时与网页一同重新生成,内容和网页同源,不会各自过时。 ## 该给 AI 哪一份 [Section titled “该给 AI 哪一份”](#该给-ai-哪一份) | 你想让 AI 做什么 | 给它 | | ---------------- | ------------------------------------------------------------ | | 介绍这个项目、回答一般问题 | `lrrg.dev/llms.txt` | | 帮你部署、排查安装与反向代理问题 | 一种语言的指南(`guides-*.txt`)或 `llms-small.txt` | | 写调用 API 的脚本或客户端 | `openapi.json`:比 API 参考页的 Markdown 更精确,也更省 token | | 写插件 | [插件开发入门](../../plugin/getting-started/) 加上 `plugin-sdk.json` | | 需要全部背景、上下文足够大 | `llms-full.txt` | 如果只是想为某个站点生成元数据、登录或下载插件,实例里自带的 **「AI 创建插件」** 会直接抓取目标页面、 生成代码并试运行,通常比让外部 AI 助手从零写更省事。 ## 怎么交给 AI [Section titled “怎么交给 AI”](#怎么交给-ai) * **能联网的 AI 工具**(带网页读取的聊天助手、编程代理等):直接把地址发给它,例如 「先读 `https://lrrg.dev/llms.txt`,再回答……」。它会按里面的链接继续读需要的部分。 * **不能联网的工具**:先下载需要的文件,再作为附件上传或粘贴进对话。 * **编程代理**(在代码仓库里工作的 AI):把 `openapi.json` 或 `plugin-sdk.json` 下载进项目目录,比每次 联网读取更稳定。
# 快速开始
> 首次登录、建立 API 令牌、扫描库、导入旧数据。
## 1. 登录 [Section titled “1. 登录”](#1-登录) 打开 `http://<你的实例地址>:3000`,用默认密码 `kamimamita` 登录,然后**立刻在设置页面改掉它**。 ## 2. 指向你的库 [Section titled “2. 指向你的库”](#2-指向你的库) `--library-path`(或 `LANRURUGI_LIBRARY_PATH`)指向放档案的目录。默认是 `./library`;Compose 部署里 对应容器的 `/home/koyomi/lanrurugi/content`。 ## 3. 扫描 [Section titled “3. 扫描”](#3-扫描) 在设置页面触发一次全量扫描。扫描是并发的(Rayon),并且**不会**自动删除档案记录——「扫描时发现文件消失」 只会清理路径簿记,档案记录本身归「数据库清理」管,是一个独立的、需要你明确触发的操作。 ## 4. 建立 API 令牌 [Section titled “4. 建立 API 令牌”](#4-建立-api-令牌) API 参考里的「Test it」面板需要令牌。在设置页面的令牌管理里创建一个,然后:
```sh
curl -H "Authorization: Bearer <你的令牌>" http://localhost:3000/api/archives
```
令牌按权限分为管理员与访客两类;访客令牌只能读取。 ## 5. 从旧版 LANraragi 迁移 [Section titled “5. 从旧版 LANraragi 迁移”](#5-从旧版-lanraragi-迁移) LANrurugi 用自己的数据库,不读取也不改动 LANraragi 的数据,两边可以同时运行。步骤见[安装](../install/)页的 「从 LANraragi 迁移」:书库挂载同一个漫画目录,缩略图和数据库用新的目录,再在首次运行向导里导入 LANraragi 的 备份 JSON。 导入按文件名把备份里的档案对应到 LANrurugi 扫描到的档案,不比较档案 ID:LANrurugi 用大小感知指纹 (`hash(前 512KB ++ 大端 u64 文件大小)`)作为 ID,和 LANraragi 的 `SHA-1(前 512KB)` 不同。同名文件有多个时 不会猜测,计入「匹配不唯一」。导入前请等书库扫描完成,还没扫描到的档案会被算作「无匹配而跳过」。 LANraragi 曾把开头字节相同的不同文件误判为重复并合并,这些文件在 LANrurugi 里会各自出现。 ## 6. 试试 API [Section titled “6. 试试 API”](#6-试试-api) 打开 [API 参考](../../api/),在请求面板里把服务器地址改成你自己的实例(默认已经是 `http://localhost:3000`),填上令牌,然后直接发请求。请求从你的浏览器直接到你的实例,不经过本项目。 浏览器不允许的时候(例如文档站是 HTTPS 而你的实例是局域网里的纯 HTTP),每个端点都提供了一份可直接 复制的命令行。 细节见[用文档站测试 API](../api-testing/)。
# 反向代理
> 用 Nginx、Caddy、Traefik、Apache 或 Nginx Proxy Manager 为 LANrurugi 配置域名与 HTTPS。
LANrurugi 本身只提供 HTTP(默认 `0.0.0.0:3000`)。要通过域名和 HTTPS 访问,在它前面放一个反向代理。 无论用哪一种代理,都要满足下面几条。 ## 代理需要满足的条件 [Section titled “代理需要满足的条件”](#代理需要满足的条件) * **挂在域名根路径下。** 前端以绝对路径 `/api/...` 请求接口,不支持挂在子路径(如 `example.com/lanrurugi/`)下。请用独立的域名或子域名,例如 `manga.example.com`。 * **转发三个请求头。** `X-Forwarded-Proto`(判断是否走 HTTPS)、`X-Forwarded-Host`(跨域登录交接与 OpenSearch 生成正确的地址)、`X-Forwarded-For`(活动记录里显示真实客户端 IP)。同时保留原始 `Host`。 * **不要缓冲 SSE。** 下载队列进度、AI 插件向导与拆包建议使用 Server-Sent Events 实时推送。代理一旦缓冲 响应,这些界面就会卡住、直到请求结束才一次性刷新。服务端每 15 秒发送一次心跳,所以默认的读超时 (通常 60 秒)够用,但缓冲必须关闭。 * **放开上传大小。** 档案上传以每片最多 64 MB 分片发送,旧版数据导入单次最多 100 MB。代理的请求体 上限要不小于这个值,最简单的做法是不设上限。 * **走 HTTPS 后打开安全 Cookie。** 在 compose 里设置 `LANRURUGI_FORCE_SECURE_COOKIES=true`。服务端不会 根据 `X-Forwarded-Proto` 自动推断这一项——那个请求头可以被伪造,而本服务没有可信代理白名单。只走 HTTP 时**不要**打开它,否则浏览器会丢弃登录 Cookie,导致无法登录。 不需要 WebSocket。 下面的示例都假设 LANrurugi 与代理在同一台机器上,监听 `127.0.0.1:3000`;如果代理和 LANrurugi 在同一个 compose 网络里,把地址换成 `lanrurugi:3000`。 ## Nginx [Section titled “Nginx”](#nginx)
```nginx
server {
listen 443 ssl;
http2 on;
server_name manga.example.com;
ssl_certificate /etc/ssl/manga.example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/manga.example.com/privkey.pem;
# 不限制上传大小(分片上传每片最多 64 MB)
client_max_body_size 0;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection "";
# SSE:不缓冲,长连接不超时
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 1h;
proxy_request_buffering off;
}
}
server {
listen 80;
server_name manga.example.com;
return 301 https://$host$request_uri;
}
```
## Caddy [Section titled “Caddy”](#caddy) Caddy 自动申请证书、默认转发 `X-Forwarded-*`,并且会立即刷新 `text/event-stream` 响应,所以配置最短:
```caddyfile
manga.example.com {
reverse_proxy 127.0.0.1:3000
}
```
## Traefik [Section titled “Traefik”](#traefik) 在 LANrurugi 的 compose 服务上加 labels(假设 Traefik 已经有名为 `websecure` 的 entrypoint 与名为 `letsencrypt` 的证书解析器,且两者在同一个 Docker 网络里):
```yaml
services:
lanrurugi:
image: ghcr.io/thelastfantasy/lanrurugi:latest
# 由 Traefik 对外提供服务时,不需要再发布 3000 端口
volumes:
- ./data/manga:/home/koyomi/lanrurugi/content
- ./data/thumb:/home/koyomi/lanrurugi/thumb
- ./data/database:/home/koyomi/lanrurugi/database
- ./data/models:/home/koyomi/lanrurugi/models
environment:
- LANRURUGI_FORCE_SECURE_COOKIES=true
labels:
- traefik.enable=true
- traefik.http.routers.lanrurugi.rule=Host(`manga.example.com`)
- traefik.http.routers.lanrurugi.entrypoints=websecure
- traefik.http.routers.lanrurugi.tls.certresolver=letsencrypt
- traefik.http.services.lanrurugi.loadbalancer.server.port=3000
restart: unless-stopped
```
Traefik 默认转发 `X-Forwarded-*`、不缓冲响应、不限制请求体大小,无需额外中间件。 ## Apache httpd [Section titled “Apache httpd”](#apache-httpd) 需要启用 `mod_proxy`、`mod_proxy_http`、`mod_headers` 与 `mod_ssl`:
```apache
ServerName manga.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/manga.example.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/manga.example.com/privkey.pem
ProxyPreserveHost On
# mod_proxy 会自动设置 X-Forwarded-For 与 X-Forwarded-Host
RequestHeader set X-Forwarded-Proto "https"
# flushpackets=on 让 SSE 事件立即送达浏览器
ProxyPass / http://127.0.0.1:3000/ flushpackets=on timeout=3600
ProxyPassReverse / http://127.0.0.1:3000/
# 不限制上传大小
LimitRequestBody 0
```
## Nginx Proxy Manager [Section titled “Nginx Proxy Manager”](#nginx-proxy-manager) 许多 NAS 用户用它管理证书。新建一个 Proxy Host: * **Details**:Domain 填 `manga.example.com`,Scheme 选 `http`,Forward Hostname / IP 与 Port 填 LANrurugi 的地址和 `3000`。 * **SSL**:申请证书,勾选 *Force SSL*。 * **Advanced** 中粘贴:
```nginx
client_max_body_size 0;
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 1h;
proxy_set_header X-Forwarded-Host $host;
```
Nginx Proxy Manager 默认已经转发 `Host`、`X-Forwarded-Proto` 与 `X-Forwarded-For`。 ## 检查是否配置正确 [Section titled “检查是否配置正确”](#检查是否配置正确) 1. 打开 `https://manga.example.com`,能正常登录且刷新后仍保持登录。 2. 在下载队列里添加一个任务,进度条应当连续推进,而不是在结束时才一次跳到 100%。 3. 活动记录页(`/activity`)里,登录记录显示的是你的客户端 IP,而不是代理的地址。
# 插件开发入门
> 用 TypeScript 写 LANrurugi 的元数据 / 登录 / 下载插件。
LANrurugi 的插件是**单个 `.ts` 文件**,放在 `plugins/<类别>/` 下,或者通过设置页面/`POST /api/plugins/upload` 上传(会上传到 `plugins/custom/<类别>/`)。它在**独立的 Deno 子进程**里运行,只带插件自己声明的权限 (`--allow-net` / `--allow-read` 等),拿不到宿主进程的任何东西。 ## 最小插件 [Section titled “最小插件”](#最小插件) 一个插件文件必须导出恰好两样东西: 1. `pluginInfo()`——同步、无副作用,只返回插件自己的元数据:命名空间、名称、参数、声明的权限。 宿主会用一个**零权限**的一次性子进程调用它,就为了读元数据,然后再按声明去申请真正的权限。 2. 对应类型的执行函数——`execMetadata`(元数据抓取)、`execLogin`(登录)、`execDownload`(下载)。 具体签名、类型与每个字段的含义,见 **[SDK 参考](../sdk/)**:它由 `deno doc` 直接从运行时会加载的那份 TypeScript 源码生成,所以不会和实际行为脱节。 ## 权限 [Section titled “权限”](#权限) 插件必须**预先声明**它需要什么,宿主才会授予什么。这是为了让一个行为异常或者恶意的插件没法拖垮宿主进程, 也没法读它不该读的文件。声明之外的任何网络/文件访问都会失败。 ## 调试 [Section titled “调试”](#调试) * 设置页面的插件列表会显示每个插件的 `pluginInfo()` 结果,包括它声明的权限。 * 插件调用失败时,宿主会把子进程的 stderr 一并记录;日志页面按类别可查。 * HTTP 请求走宿主中继,并按需最小化——插件发出的请求由宿主代理,因此插件不需要 `--allow-net` 之外的东西, 也能被统一限流与记录。 ## 下一步 [Section titled “下一步”](#下一步) * [SDK 参考](../sdk/)——所有导出类型与函数,含文档注释。 * [API 参考](../../api/)——`/api/plugins*` 下的端点(列表、上传、执行、导出)。
# SDK 参考
> 插件运行时实际加载的那份 TypeScript 的 API 参考。
插件作者可用的每个类型与函数,都由 `deno doc` 直接从**插件运行时实际加载的那份 TypeScript** (`crates/lanrurugi-plugin/dispatcher/` 下的 `plugin-sdk.ts`、`dispatcher.ts`,以及 `plugins/legacy-globals.d.ts`)生成,所以它不会和真实行为脱节。 [打开 SDK 参考 →](https://sdk.lrrg.dev/) 那份参考里可以搜索符号、按类型/接口/函数分组浏览,也能看到每个符号自身的文档注释。同一份内容还有一个 机器可读的 JSON 版本(`plugin-sdk.json`),便于工具消费。 ## 相关 [Section titled “相关”](#相关) * [插件开发入门](../getting-started/)——最小插件、权限模型、调试。 * [API 参考](../../api/)——`/api/plugins*` 下的端点。