A self-hosted manga server with an admin dashboard that implements the Mankai HTTP API for the Mankai manga reader.
Point the Mankai app at http://<host>:3000/api, sign in, and your library and reading progress sync across devices.
- Full Mankai API support: server info, JWT auth, manga browsing, search, suggestions, and the in-app editor API.
- Web admin dashboard for managing manga, chapter groups, chapters, page images, covers, and users.
- Semantic search and autocomplete powered by local sentence embeddings (
Xenova/bge-m3) indexed with pgvector. - Installed plugins, browsable plugins, reading progress, and saved-library sync with an incremental endpoint.
- PostgreSQL + pgvector in production, or embedded PGlite for zero-config setups.
- JWT Bearer tokens for the app, session cookies for the dashboard, and auto-generated API keys per user.
docker-compose.yml runs the server alongside a pgvector/pgvector:pg18 Postgres instance.
- Edit
docker-compose.ymland change the placeholder secrets under theappservice'senvironmentblock:
environment:
SESSION_SECRET: changeme123-make-sure-it-is-at-least-32-characters
JWT_SECRET: changeme123-make-sure-it-is-at-least-32-characters
SERVER_ID: mankai-server
ADMIN_EMAIL: admin@mankai.local
ADMIN_PASSWORD: changeme123
# Optional, takes precedence over ADMIN_PASSWORD. Escape each $ as $$.
# ADMIN_PASSWORD_HASH: "$$argon2id$$..."
# BASE_API_URL: https://api.example.app
# EMBEDDING_QUANTIZED: "0"
# FORCE_SECURE_COOKIE: "true"
# LOG_LEVEL: debug- Build and start:
docker compose up -d --buildOn startup the container runs migrations, seeds the admin user from ADMIN_EMAIL and either ADMIN_PASSWORD_HASH or ADMIN_PASSWORD (idempotent), and serves the app on port 3000.
ADMIN_PASSWORD_HASH takes precedence when both are set and is stored directly without rehashing. It must be a valid password hash supported by Bun.password.verify, such as Argon2 or bcrypt. An invalid hash stops admin seeding. If no hash is provided, ADMIN_PASSWORD must contain at least 8 characters.
Generate a hash with Bun, escaped for use in docker-compose.yml:
bun -e 'console.log((await Bun.password.hash("your-password-here")).replaceAll("$", () => "$$"))'- Open
http://localhost:3000for the dashboard, or add a server in the Mankai app with base URLhttp://<host>:3000/api.
Data is persisted on the host under ./data.
docker compose logs -f app
docker compose restart app
docker compose down