Guides (English): installation, usage and plugin authoring # 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*`.