Use case · Reading server

Kavita self hosted on a dedicated server: install, first admin, OPDS, backups

Kavita self hosted is one self-contained program that serves a web reader and an OPDS feed on port 5000, reads manga, comics and ebooks from folders you choose, and keeps its database and settings in a config folder beside it. On a whole machine you pick the disks the library sits on, the firewall in front of the port and the proxy that terminates TLS, and no other tenant shares the box.

See the machines

What Kavita asks of the hardware

Very little. The wiki says every build is self-contained, with no runtime to install, and names one hard requirement: a processor with the SSE4.2 instruction set, because NetVips, the image library behind cover generation, depends on it. Without it, the FAQ says, Kavita either crashes or draws black-and-white covers.

ResourceWhat the project statesWhat it means here
ProcessorSSE4.2 required; users report running it on a single 1 GHz coreCheck Instruction Set Extensions on Intel's specification page; the Intel processor list links one per CPU
MemoryUsers report 256 MB; Server Settings has a Cache Size field for hot API responses, default 75The smallest line on the service page has 8 GB, so memory is not the constraint
Disk I/OFirst scans are slow, worse on network or rclone storage; cover refresh and file analysis are heavy on I/O and memoryKeep the library on local disks in the machine
CapacityNot stated: it depends on your libraryThe library, plus config: database, covers, bookmarks and up to 30 days of backup zips

Formats, per the README: cbr, cbz, zip, rar and rar5, 7zip and loose images for comics and manga; epub and pdf for books.

Choosing the line

Kavita is a light service, so the numbers that decide the machine are disk capacity and the city nearest your readers. On the dedicated server range that leaves three shapes:

  • A Moonshot cartridge for a personal or household library: one service per machine is what the cartridges are sold for. The Xeon D-1587 cartridge pairs 16 cores with one NVMe disk of 1.92 TB.
  • A single-socket rack server once the collection outgrows one disk, with its own chassis and out-of-band console.
  • A build to order when you need drive bays: you pick drives, count and RAID level, up to 24 bays on the largest lines, delivered in 4 to 24 hours.

Handover of a ready server takes about 30 minutes once payment is approved. Every racked single-, dual- and quad-socket server has an out-of-band console (HPE iLO, Dell iDRAC or a Supermicro BMC); among the cartridges only the m510 and m710x have one, the rest have power control. Ports are unmetered, so readers paging through large scans from outside your network count against no transfer allowance.

Leave the X-Gene ARM cartridge out. It boots Ubuntu 16.04 and 18.04 and nothing else, which is our reason to keep Kavita on an x86 line, where current Ubuntu releases install from the control panel.

Native install under systemd

This follows the wiki's Linux steps and its example unit, with changes of ours: ufw is enabled before the first start, the service account is a system user with no login shell, and the library sits under /srv, readable by that account. Kavita's default bind is 0.0.0.0 and :: (every IPv4 and IPv6 address, per Configuration.cs in the source), so ufw must cover IPv6 before anything listens. Run as root; you is your own login:

sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw
ufw allow OpenSSH
ufw --force enable
useradd --system --user-group --home-dir /opt/Kavita --shell /usr/sbin/nologin kavita
cd /tmp && wget https://github.com/Kareadita/Kavita/releases/latest/download/kavita-linux-x64.tar.gz
tar -xzf kavita-linux-x64.tar.gz -C /opt && chmod +x /opt/Kavita/Kavita
chown -R kavita:kavita /opt/Kavita && chmod 700 /opt/Kavita/config
install -d -o you -g kavita -m 2750 /srv/library /srv/library/manga /srv/library/comics /srv/library/books
printf '%s\n' '[Unit]' 'Description=Kavita Server' 'After=network.target' '[Service]' 'User=kavita' 'Group=kavita' 'Type=simple' 'WorkingDirectory=/opt/Kavita' 'ExecStart=/opt/Kavita/Kavita' 'TimeoutStopSec=20' 'KillMode=process' 'Restart=on-failure' '[Install]' 'WantedBy=multi-user.target' > /etc/systemd/system/kavita.service
systemctl daemon-reload && systemctl enable --now kavita

The archive unpacks to /opt/Kavita. On first start Kavita renames config/appsettings-init.json to appsettings.json and replaces the placeholder session-signing key in it with a random one (Program.cs in the source). That file and the kavita.db database next to it are the instance, hence mode 700 on config.

The first registration is the admin

Kavita ships with no default login. The first account registered gets the Admin role, and the register endpoint refuses further sign-ups once an admin exists (RegisterFirstUser in AccountController.cs). Make that registration yours while ufw still blocks port 5000: from your workstation run ssh -L 5000:127.0.0.1:5000 you@your-server and load http://localhost:5000 in a browser to register with a long password.

Still in the tunnel, open Server Settings > General and set IP Address to 127.0.0.1, so Kavita listens on loopback only; the source keeps that value in appsettings.json. Run systemctl restart kavita and reconnect. On the same page, Allow Anonymous Usage Collection is on by default and, per the wiki, first sends after 24 hours; switch it off if you want no install statistics leaving the box.

The wiki advises against reading from the admin account day to day: admins bypass age restrictions and see full disk paths. Create an ordinary account for yourself under Users.

Library layout the scanner accepts

Kavita works out series, volume and chapter from filenames and embedded metadata, not by mirroring your folders, and the wiki sets two hard rules: no files at a library's root, and every series in a folder of its own, never split across two sibling folders. A publisher level above the series folders is fine.

  • Manga: /srv/library/manga/Series Name/Series Name v01.cbz, then v02 and on, with a Specials subfolder whose files carry SP01, SP02 markers.
  • Volume and chapter markers go in the filename: v01, vol. 1 or tome 2; c01, ch. 1 or chapter 1.
  • EPUBs are grouped by the metadata inside the file first; the wiki points to Calibre for fixing series and volume fields.
  • Set the library type to match the content: Manga, Comic, Comic (Flexible), Book, Light Novels or Image. Pick the library root in the folder picker, not a series folder.

Upload only books and comics you own or hold the rights to, over your own login: rsync -rlt ~/manga/ you@your-server:/srv/library/manga/. The setgid bit on those folders puts new files in the kavita group, so the service can read them.

OPDS and Kavita+

OPDS is enabled on every install by default. Each user gets a personal feed URL carrying an auth key; set Host Name under Server Settings > General so that URL uses your domain. Kavita serves plain OPDS and OPDS-PS, the page-streaming extension, and the wiki's client tables list KOReader, Panels and Chunky among the apps that handle page streams. The key in the URL signs in as that user, so treat the URL like a password.

Kavita+ is an optional subscription run by Kavita's main developer, majora2007, for features that depend on outside services: metadata from Mangabaka, Hardcover and ComicBookRoundup; scrobbling, meaning progress sync, to Hardcover, MAL, AniList and MangaBaka; and external recommendations, reviews and ratings. A licence is node-locked to one instance and covers every user on it. The wiki says changing hardware or OS, or reinstalling, can trip its already-tied-to-another-server check, which recent versions resolve by offering to overwrite. It supports the latest three stable releases, and the wiki states no base feature will ever be moved behind it.

TLS through nginx

The wiki recommends a VPN for one or two readers and a reverse proxy for many. For the first, a WireGuard server on the same machine keeps Kavita off the public internet entirely. For the second, Kavita trusts forwarding headers only from localhost, so nginx on the same host needs no extra setting. nginx is an ordinary host process, so without a ufw rule it is blocked on IPv4 and IPv6 alike. In order:

  1. Point the A and AAAA records for your name, kavita.example.com here, at the server.
  2. Open the web ports: ufw allow 80,443/tcp.
  3. With nginx, Certbot and Certbot's nginx plugin installed, get the certificate before writing the site: certbot certonly --nginx -d kavita.example.com.
  4. Save the block below as /etc/nginx/sites-available/kavita and link it in with ln -s /etc/nginx/sites-available/kavita /etc/nginx/sites-enabled/kavita.
  5. Check the syntax and load it: nginx -t && systemctl reload nginx.

The block is the wiki's NGINX example aimed at loopback, with an IPv6 listener and the certificate paths Certbot writes:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name kavita.example.com;
    ssl_certificate     /etc/letsencrypt/live/kavita.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/kavita.example.com/privkey.pem;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://127.0.0.1:5000;
    }
}

The Docker route instead

  • Image: jvmilazz0/kavita:latest, the same build as ghcr.io/kareadita/kavita:latest. The old kizaing/kavita repository is unsupported, and the wiki advises against nightly tags for a main instance.
  • Mounts: config at /kavita/config (the wiki says that path must not change) and each library folder at its own path such as /manga.
  • Publish 127.0.0.1:5000:5000, not the wiki's 5000:5000. A mapping with no address is published on 0.0.0.0 and [::]; that traffic skips ufw's rules on IPv4, and on IPv6 too when Docker's own IPv6 networking is on. With Docker Engine 28 or later the loopback binding is reachable from the host alone.
  • The IP Address setting is disabled under Docker, per the wiki, so the mapping is your bind.
  • Our reading of the forwarded-header rule: a host proxy connects to the container from the Docker bridge's gateway IP, not from localhost, so put that address in KnownProxies in appsettings.json, as the wiki shows for proxies on another host.
  • Keep secrets out of the container environment: docker inspect prints every value in it.

Backups, restores and updates

Kavita backs itself up. The source seeds the backup task as daily (Seed.cs), the wiki's Daily is midnight in the server's time zone, and Days of Backups defaults to 30. Each zip in config/backups holds kavita.db, appsettings.json with its signing key, logs, every collection, library and reading-list cover plus the series, volume and chapter covers you have locked (the unlocked ones are not copied), bookmarks, themes, fonts and favicons (BackupService.cs), but none of your library files. The zips sit on the same disks as everything else, so copy them off the machine yourself. This root block stages a private copy for you to pull, keeping 30 days of it:

install -d -m 700 -o you -g you /srv/kavita-out
printf '%s\n' '15 2 * * * root umask 077; cp -u /opt/Kavita/config/backups/kavita_backup_*.zip /srv/kavita-out/ && chown you:you /srv/kavita-out/*.zip; find /srv/kavita-out -name "kavita_backup_*.zip" -mtime +30 -delete' > /etc/cron.d/kavita-out
chmod 644 /etc/cron.d/kavita-out

Pull it from another machine with rsync -rt you@your-server:/srv/kavita-out/ ~/kavita-backups/, and copy the library itself the same way.

Restoring, per the wiki, means stopping Kavita, copying everything in a backup zip into config/ and starting it. Check first: unzip -l on the zip you mean to use shows it exists and its index reads, though not that every entry is intact (install unzip with apt if it is missing). Then systemctl stop kavita, unzip -o the zip into /opt/Kavita/config, chown -R kavita:kavita /opt/Kavita/config and systemctl start kavita. Nothing is emptied beforehand; the zip's files overwrite their namesakes.

Updating a native install, per the wiki: extract the new tarball in a temporary folder, delete the config folder inside that temporary copy, stop the service, copy the files over /opt/Kavita and start it again. Two steps are our additions, not the wiki's: run Backup Database from the Tasks tab before you begin, and run chown -R kavita:kavita /opt/Kavita before the restart, because files copied as root arrive owned by root. Coming from anything older than v0.7.6, the wiki says to step through v0.7.1.4, v0.7.3.1, v0.7.6 and v0.7.14 rather than jump.

Questions

Which port does Kavita listen on, and can I move it?

Port 5000 by default. On a native install you change it in Server Settings > General, and the wiki says the change needs a manual restart. Under Docker you change the host side of the port mapping instead.

Native build or Docker image on a dedicated server?

Both come from the same releases. Our view: on a machine of your own the native build is the shorter path, because Kavita can bind itself to 127.0.0.1 and nginx on the host counts as localhost. Docker suits you if the box already runs other containers; then the bind lives in the port mapping and the proxy address goes in KnownProxies.

Can Kavita be used without logging in?

No. The wiki's FAQ says anonymous access is not supported and is not planned. Refresh tokens keep a session alive, and an API key can sign a user in through a URL, which is another reason to keep those keys private.

Does the built-in backup cover everything?

It covers the database, settings, locked and list-level covers, bookmarks and logs, not the books and comics themselves. It also lands on the same disks as the instance, and each zip carries the session-signing key, so copy the zips off the machine and keep them private.

What is Kavita's licence?

GPL-3.0, per the LICENSE file in the Kareadita/Kavita repository. Our general reading, not legal advice: you may run, study and modify it, and serving it to your own readers over the web is use rather than distribution. If you distribute the program or a modified build, you pass the source on under the same licence.

Is Kavita stable enough to rely on?

The README calls it beta software until the 1.0.0 release and warns that data loss is possible as the platform changes. Treat the off-machine backups as part of the install, and read the release notes before each update.

Put your library on its own machine

Pick a cartridge for a household library or a build with drive bays for a large one; every line on the range shows its disks and cities.

See the machines

Related on Server Room

Other use cases