Self-hosted service
lkw199711/smanga avatar
lkw199711/smanga

Smanga turns a folder of manga files into a self-hosted streaming library

A simple manga browser 一款docker直装的漫画浏览器

945 stars43 forksVueGPL-2.0

At a glance

What is it?
A Docker-first manga server with a Vue front end and an AdonisJS back end that indexes CBZ, ZIP, CBR, 7z, RAR and PDF files, serves them as a browsable wall, and tracks your reading progress. It is aimed at NAS and home server users who already own the files.
Who is it for?
Smanga suits someone with a NAS or home server who has already downloaded a manga library and wants it browsable, with decompression, cover art, bookmarks and reading progress, on their own hardware rather than a third party service. It does not suit someone who wants a tool that fetches manga, since the project only reads and organises files you mount, and it is a poor match if you rely on continuous vertical webtoon strips, since the long strip format needs cropping.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 35 days ago.
What is it written in?
Mainly Vue, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A media server for a library you already own

Smanga is a manga streaming reader, described as a simple manga browser that installs directly with Docker. The inspiration is stated in the project description: Emby and Plex. The problem it addresses is a storage problem. A manga collection on a disk is usually a pile of mixed archives, each chapter compressed differently, named in ways that mean nothing, and the files take up space that nobody can search.

The approach is to treat that pile as a media library. Smanga scans a directory, extracts the archives into a cache, generates covers for the library, the series and the chapters, and serves a wall of posters you can click through. The read experience is browser based and works on a phone, a tablet or a desktop, and the project describes several reading modes: webtoon style waterfall for vertical scroll, single page turn, and double page.

The audience is a self-hoster. The documentation is written around Docker, Docker Compose and NAS appliances, and a compose example is provided for finished NAS products. There is also a Windows build, distributed as a download on the releases page that you unpack and run, for people with no Linux server at all.

A few things it does not do. It is not a downloader, so it never fetches anything; it only reads the directories you mount into it. And the earlier LNMP style installation path is marked as retired in the table of contents, which is a hint that the project has consolidated around the container workflow.

Two repositories, one image, one port

Smanga is split across two codebases, and the split is visible in the container build. The front end is what this repository holds: a Vue 3 application with Element Plus for the component library, Pinia for state, vue-router, vue-i18n for translations, axios for requests, echarts with vue-echarts for the statistics view, and vue-pdf-embed for PDF rendering. The build is Vite 7 with TypeScript 5.9, and the package scripts include separate modes for the environments that matter, build-docker, build-baota, serve-docker and serve-baota, with baota named after the BaoTa panel.

The back end lives elsewhere. The Dockerfile clones https://github.com/lkw199711/smanga-adonis.git at image build time, installs its dependencies, builds it, and copies the result into /app/adonis, along with the prisma directory and a sample configuration file. The front end bundle is copied into /app/smanga-website. A separate project, smanga-php, is referenced as the moved back end for the older generation of the software.

The runtime container is built FROM node:22-alpine3.22, installs s6-overlay as the process supervisor, creates an unprivileged user with uid 918, declares a volume at /data, and exposes the web port with the variable ${WEB_PORT:-9797}. The s6 grace time values are tuned so that a slow start does not kill the service during a scan, and the same port serves both the front end and the API, so the log line that tells you the service is up mentions an HTTP server on 0.0.0.0:9797.

For a reader of the code, that arrangement means the front end repository alone is not enough to run the application. The container is the supported unit.

Deploying with a single docker run and one data volume

The current generation of the image is the nodejs one, and the documented run command is short because the new version consolidates its state into a single directory:

bash
docker run -itd --name smanga \
-p 9797:9797 \
-v /mnt:/mnt \
-v /route/smanga:/data \
lkw199711/smanga-nodejs;

Two mounts do the work. The media mount, /mnt here, is where your manga files live, and it is mounted at the same path inside the container so that the library configuration keeps working regardless of the host path. The second mount, /route/smanga to /data, is the application state directory, and it holds the database, the caches, the configuration and the generated covers.

The documentation is explicit about the consequences of the new layout. The new version needs only the /data directory mapped, and mapping individual subdirectories is no longer supported. Old and new versions are not compatible, so use a separate empty directory for the data mount. The web port moved to 9797. If you have logged into the old version in a browser, clear the old cookies before logging in again. And the new version does not support PDF yet, which is a real gap given that the front end ships a PDF component.

A regional mirror is published for users who cannot pull from Docker Hub quickly. The image name is the only thing that changes:

bash
docker run -itd --name smanga \
-p 9797:9797 \
-v /mnt:/mnt \
-v /route/smanga:/data \
registry.cn-hangzhou.aliyuncs.com/lkw199711/smanga-nodejs:latest;

The mirror keeps the same tags as Docker Hub, so version numbers stay comparable between the two.

Postgres or sqlite, wired through environment variables

The compose file in the repository shows the full topology, and it is the clearest description of what the back end expects:

yaml
services:
  postgres:
    image: postgres:18
    container_name: smanga-postgres
    environment:
      POSTGRES_DB: smanga
      POSTGRES_USER: smanga
      POSTGRES_PASSWORD: smanga

The Smanga service then points at it with a small set of variables:

yaml
services:
  smanga-nodejs:
    image: lkw199711/smanga-nodejs:latest
    container_name: smanga
    ports:
      - "9797:9797"
    environment:
      DB_TYPE: pgsql
      DB_HOST: postgres
      DB_PORT: 5432
      DB_USERNAME: smanga
      DB_PASSWORD: smanga
      DB_DATABASE: smanga
      WEB_PORT: 9797
      TZ: Asia/Shanghai

DB_TYPE is the switch that decides which engine the back end uses. Leave it unset and the application falls back to the default sqlite database, which the log reports at /app/adonis/smanga.db. The project has moved toward external databases because scanning and searching a large library is faster and lighter with a real database server, and the compose example is written for Postgres 18 with persistent volumes for the database and its logs.

Two more environment variables decide who the process runs as. PUID and PGID set the user and group id, and both are set to 0 in the examples, which runs the service as root. The comment in the compose file invites you to change those to match your own machine if you would rather it did not run as root, and for a NAS deployment that is the setting you are most likely to want to change, since the container writes to the mounted media and data directories.

Volume mapping is the other half of the compose example, with one mount per disk or storage pool, each mounted at the same path inside and outside the container, and the note explains that you should map as many volumes as you have.

Decompression, covers and the data directory that holds everything

The feature work since the 3.0.0 release explains what the library manager actually does for you: it added a database for faster scanning and searching, decompression and conversion for zip, cbz, cbr, 7z, rar and pdf, bookmarks that record reading progress, browsing history, device compatibility, and the multiple reading modes.

The data directory layout is the part to read before you back anything up. It is divided into bookmark for bookmark cover images, cache for compressed cover caches, compress for the extracted archive files, config for the configuration, db for the sqlite database, file for files such as apk packages, logs for the nginx and service logs, and poster for the covers of libraries, series and chapters.

The compress directory deserves its own decision. The archives are extracted into it as plain images, and the documentation states plainly that these files are not critical and their loss does not break normal operation, but they consume a lot of space. That is why the recommended mapping puts compress on its own volume, keeping the application pool and the storage pool separate, in the same way you would not keep large media on a system drive.

The older mapping scheme in the documentation goes further, with separate volumes for compress, poster, the MySQL data directory at /var/lib/mysql and the config directory. The new generation collapses all of that into /data, which is simpler to back up and simpler to get wrong.

Scanning is configurable rather than fixed. The interface supports adding media libraries, adding paths to a library, and defining custom scan templates, and a separate section is devoted to the reading interface itself.

The limits: long webtoon strips, PDF in the new build, and a retired old version

The project documents its own limitations in a section of the table of contents dedicated to them, which is rare and useful. The headline item is long webtoon images. The reader was built with vertical scroll in mind, but the long strip format is not supported and has to be cut into pages first, which is a manual step for anyone with a library of that style.

The second limit is the one that catches people out. The new nodejs generation does not support PDF, even though the decompression feature list names pdf among the formats it handles and the front end includes a PDF rendering component. The old generation handled PDF and compressed archives; the new one does not, which makes this a genuine regression for anyone whose library is PDF only.

The third limit is version confusion. The old image is still documented, with a different port layout that exposes 3333 for the database and maps the web interface from the container's port 80, and with a MySQL data volume. The documentation states that the old version will no longer be updated, and that old and new should be deployed separately if you keep both.

There is also a startup detail that looks like an error and is not. On a first deployment the log may report that /app/adonis/smanga.db does not exist, which the documentation explains is normal because the program creates the database and the cache directories itself. The service has to complete an initialisation pass before it starts serving, so the advice is not to open the page immediately, and to wait until the log prints the line "Server is running on port 9797" followed by an informational entry that an HTTP server was started on 0.0.0.0:9797.

Once both appear, the front end and the API are both served from port 9797.

GPL-2.0 terms, an Electron default branch and a version number that outruns the tags

The licence field on the repository says GPL-2.0, and the software is distributed as a Docker image rather than as a library, so the practical question for most people is whether they intend to modify and redistribute it. Self hosting a stock container for personal use is a different question from shipping a modified image, and the GPL-2.0 text is the thing to read if the second case applies. The project also publishes to Docker Hub under the lkw199711 organisation, with a mirror on Aliyun for users inside China.

The release history shows regular work. Version 4.3.30 shipped on 2026-07-30, 4.2.80 on 2026-02-20 and 4.2.79 on 2026-02-17, and the last push was on 2026-09-18 with the repository not archived. The version in package.json is 4.3.34, which is ahead of the newest tagged release, so the front end source tree is running slightly ahead of what the published image contains.

The default branch is named electron, a leftover from when the Windows desktop shell was the primary target, and the Windows build is still distributed through the releases page. Updating that build is a manual procedure rather than an in-app upgrade: download the newest package, then copy the data directory from the old installation over the new one so the library and settings survive the swap.

For a self hosted service, the practical upgrade path is the container tag. The image and the front end repository move at their own pace, and the compose example pins an explicit version in one place, lkw199711/smanga-nodejs:4.2.80, which is a reminder that pinning is available and worth doing before a database schema change catches you out.

Editorial conclusion

Smanga suits someone with a NAS or home server who has already downloaded a manga library and wants it browsable, with decompression, cover art, bookmarks and reading progress, on their own hardware rather than a third party service. It does not suit someone who wants a tool that fetches manga, since the project only reads and organises files you mount, and it is a poor match if you rely on continuous vertical webtoon strips, since the long strip format needs cropping. Verify first that your terminal reaches the container at port 9797 and that the log line "Server is running on port 9797" appears, then check the /data mount before importing anything, because the data directory holds the sqlite database, the decompression cache and the covers.

Frequently asked questions

How do I deploy Smanga with Docker?

The documented command is docker run -itd --name smanga with port 9797 published, your media directory mounted at the same path inside and outside the container, and a data directory mounted to /data. The image is lkw199711/smanga-nodejs.

Does Smanga need a separate database server?

No. Without a database configured it uses the default sqlite database, which the back end creates on first start. The compose example shows the alternative, Postgres 18, selected with DB_TYPE: pgsql along with DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD and DB_DATABASE.

Can Smanga read PDF manga?

The decompression feature list names pdf among the supported formats for the older generation, but the documentation states that the new nodejs version does not support PDF yet. Old and new versions are not compatible and are meant to be deployed separately.

How do I update the Windows version of Smanga?

Download the latest package from the releases page and copy the data directory from the old installation over the new one, so the library, configuration and covers are preserved. The data directory also holds the sqlite database and the decompression cache.

Official sources

  1. Issues
  2. License: GPL-2.0
  3. lkw199711/smanga on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lkw199711-smanga.svg)](https://hysenlabs.com/projects/lkw199711-smanga)

Was this useful?