Applications Azure

Suwayomi Server on Ubuntu 24.04 on Azure User Guide

| Product: Suwayomi Server 2.3.2243 on Ubuntu 24.04 LTS on Azure

Overview

Suwayomi Server is a free, open-source, Tachiyomi-compatible manga server and reader. It installs extension sources, browses and searches their catalogs, and serves a browser reading UI where you read chapters or download them for offline access — with the library, reading progress and downloads all kept on a server you own. The cloudimg image installs Suwayomi Server 2.3.2243 from the official GitHub release jar with SHA-256 verification, on a headless OpenJDK 21 runtime.

Two things about this image are worth knowing up front, because they differ from a stock Suwayomi install:

  • Suwayomi ships with authentication disabled (server.authMode = "none"), which would leave the reader open to anyone who can reach the port. This image therefore binds Suwayomi to the loopback interface only and fronts it with an nginx reverse proxy on port 80 that requires HTTP authentication on every request. A single anonymous endpoint, /healthz, is kept for load-balancer and monitoring probes.
  • No credential ships in the image. A one-shot first-boot service generates a 24-character admin password unique to this VM, writes it into the proxy's credential store and into a root-only file. Until that has happened, neither the reader nor the proxy will serve a request at all.

What is included:

  • Suwayomi Server 2.3.2243 as a single self-contained jar at /opt/suwayomi/Suwayomi-Server.jar, with the web reader UI bundled inside it
  • OpenJDK 21 JRE headless from Ubuntu 24.04 noble main
  • suwayomi.service running as the unprivileged suwayomi service user, bound to 127.0.0.1:4567
  • The server data root on a dedicated 40 GiB Azure data disk mounted at /var/lib/suwayomi — the library database, downloaded chapters, thumbnails, extension sources, the cached web UI and server.conf
  • An nginx reverse proxy on port 80 with HTTP Basic authentication and an unauthenticated /healthz endpoint
  • A per-VM admin password generated at first boot, stored in /root/suwayomi-credentials.txt (mode 0600)
  • Unattended security upgrades enabled
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key, and a VNet + subnet. Standard_B2s (2 vCPU, 4 GB RAM, 1024m JVM heap by default) is suitable for a personal or small-group library. For a large library, heavy concurrent reading, or bulk downloading, raise the VM size and the JVM heap together (Step 12).

NSG inbound rules: allow 22/tcp from your management CIDR and 80/tcp from the client CIDRs that need the reading UI. You do not need to open 4567/tcp — Suwayomi binds only to loopback and is reached exclusively through the proxy.

The reader is served over plain HTTP on port 80. Put TLS in front of it before production — an Azure Application Gateway, Azure Front Door, or your own reverse proxy with a certificate for your domain.

Step 1-3: Deploy + SSH (standard pattern)

Deploy the VM from the Azure Marketplace offer, then connect over SSH as azureuser:

ssh azureuser@<vm-ip>

Step 4: Service Status + Health

Confirm both services are active and the unauthenticated health endpoint responds:

sudo systemctl is-active suwayomi.service nginx.service
curl -s -o /dev/null -w 'healthz: HTTP %{http_code}\n' http://127.0.0.1/healthz

Both units report active and /healthz returns HTTP 200. /healthz is served directly by nginx and never proxies to Suwayomi, so it is a front-door liveness signal you can point a load balancer or monitor at without a credential.

Suwayomi Server terminal output showing suwayomi.service and nginx.service both reporting active, all three units reporting enabled, and systemctl status confirming the Java process is running

Step 5: Read the Per-VM Admin Credentials

The admin password is unique to this VM and was written to a root-only file at first boot:

sudo cat /root/suwayomi-credentials.txt

This prints SUWAYOMI_ADMIN_USER (admin), SUWAYOMI_ADMIN_PASSWORD (the per-VM password) and SUWAYOMI_URL. Keep the password safe — it is the only credential that unlocks the reader.

Suwayomi Server terminal output showing the credentials file is mode 600 owned by root, and its contents listing the reader URL, the admin username and the per VM generated password

Step 6: Authentication Round-Trip

Prove the proxy is doing its job — anonymous requests are refused, the per-VM password is accepted, and a wrong password is refused:

curl -s -o /dev/null -w 'anonymous:      HTTP %{http_code}\n' http://127.0.0.1/
curl -s -u 'admin:<SUWAYOMI_ADMIN_PASSWORD>' -o /dev/null -w 'with password:  HTTP %{http_code}\n' http://127.0.0.1/
curl -s -u 'admin:wrong-password' -o /dev/null -w 'wrong password: HTTP %{http_code}\n' http://127.0.0.1/

You get 401, 200, 401. The same applies to the GraphQL API through the proxy — /api/graphql on port 80 requires the credential too, so nothing about the server is reachable anonymously except /healthz.

Suwayomi Server terminal output proving the reverse proxy refuses an anonymous request with HTTP 401, accepts the per VM credential with HTTP 200, refuses a wrong password with HTTP 401, and serves the anonymous health endpoint with HTTP 200

Step 7: Version, Runtime, Bind Address and Data Disk

Suwayomi's own GraphQL API is reachable without a credential from the VM itself on 127.0.0.1:4567, because that interface is not exposed to the network:

curl -sS -H 'Content-Type: application/json' \
  --data '{"query":"{ aboutServer { version buildType } }"}' \
  http://127.0.0.1:4567/api/graphql; echo
java -version 2>&1 | head -1
ss -tlnH | grep 4567
findmnt /var/lib/suwayomi

aboutServer reports v2.3.2243 / Stable. The socket line is the important one for security: it reads [::ffff:127.0.0.1]:4567, an IPv4-mapped loopback socket, confirming the server is not listening on any routable interface. findmnt confirms the data root is the dedicated Azure data disk and not the OS disk.

Suwayomi Server terminal output showing the GraphQL aboutServer query returning version v2.3.2243 Stable, the OpenJDK 21 runtime version, the loopback only listening socket on port 4567, and the dedicated 40 GiB data disk mounted at the data root

Step 8: Sign In to the Reading UI

Browse to http://<vm-ip>/. Your browser prompts for credentials — enter admin and the password from Step 5. The Library view loads; on a fresh VM it is empty, because no library data ships in the image.

The left-hand rail is the whole application: Library (your saved titles), Updates, History, Browse (sources and extensions), Downloads, Settings and About.

The Suwayomi Server library view in a browser, showing the left navigation rail with Library, Updates, History, Browse, Downloads, Settings and About, and a title in the library grid displaying its cover art

Step 9: Add an Extension Source

Suwayomi reads catalogs through Tachiyomi-compatible extensions, and extensions come from repositories you choose and add yourself. No repository is pre-configured in this image.

In the UI go to Browse. The Source tab lists the sources currently available — on a fresh VM that is just Local source, the built-in source that serves comics you place on the VM yourself (Step 10). The Extension tab is where installed extensions appear once you have added a repository under Settings → Browse → Extension repositories.

Choose your repositories deliberately: you are responsible for the sources you add and the content you access through them. cloudimg does not bundle, endorse or host any catalog.

The Suwayomi Server Browse view in a browser, showing the Source, Extension and Migrate tabs with the built in Local source listed and a Latest button to browse it

Step 10: Serve Your Own Comics with the Local Source

The Local source reads directly from the data disk, so you can host your own scans or legally-obtained archives with no extension at all. The layout is one directory per title, one directory (or one CBZ file) per chapter:

/var/lib/suwayomi/local/
└── My Comic/
    ├── cover.jpg
    ├── details.json
    └── Chapter 1/
        ├── 001.jpg
        ├── 002.jpg
        └── 003.jpg

Create the directory, copy your page images in, then restart the server so it re-indexes:

sudo install -d -o suwayomi -g suwayomi -m 0755 "/var/lib/suwayomi/local/My Comic/Chapter 1"
sudo systemctl restart suwayomi.service
for i in $(seq 1 60); do curl -sf -o /dev/null http://127.0.0.1:4567/ && break; sleep 2; done
curl -s -u 'admin:<SUWAYOMI_ADMIN_PASSWORD>' -o /dev/null -w 'reader after restart: HTTP %{http_code}\n' http://127.0.0.1/

The reader returns HTTP 200 again after the restart. In the UI, Browse → Local source → Latest now lists your title; open it and tap the heart to add it to your Library.

Step 11: Read a Chapter

Open a title from the Library to reach its detail view — cover, metadata, description, and the chapter list. Optional details.json fields (title, author, artist, description, genre, status) are shown here for local titles.

The Suwayomi Server title detail view in a browser, showing the cover art, author and artist metadata, the source name, an In Library button, the description and a chapter list with one chapter

Click a chapter to open the reader. Pages render full width with a page counter, and the reading mode (paged, continuous vertical, right-to-left) is configurable per title and globally under Settings → Reader. Reading progress is stored server-side, so you resume in the same place from any browser.

The Suwayomi Server reader in a browser with a comic page fully rendered, showing the page artwork and the page position indicator reading 1 of 3

Step 12: JVM Heap and VM Sizing

The service runs with a 1024 MB maximum heap, which suits a personal library on Standard_B2s. Check the current setting:

systemctl cat suwayomi.service | grep -E 'ExecStart|Xmx'

To raise it, move to a larger VM size first, then add a systemd drop-in. Because the heap flags are part of ExecStart, the override must clear and restate the whole line — create /etc/systemd/system/suwayomi.service.d/10-heap.conf:

[Service]
ExecStart=
ExecStart=/usr/bin/java -Djava.awt.headless=true -Xms512m -Xmx3072m -Dsuwayomi.tachidesk.config.server.rootDir=/var/lib/suwayomi -jar /opt/suwayomi/Suwayomi-Server.jar

Then sudo systemctl daemon-reload && sudo systemctl restart suwayomi.service. Never set a maximum heap larger than about 75% of the VM's RAM — the image deliberately ships no swap (Azure manages swap on the ephemeral resource disk, and a swap file baked into an image fails Azure certification), so an oversized heap will be killed by the OOM reaper rather than paged.

Step 13: Server Settings and Backups

Everything Suwayomi exposes is under Settings: reader defaults, library categories and update behaviour, download locations, extension repositories, backups, and the server settings that mirror server.conf.

Two settings deserve care on this image, because changing them removes the protection the image adds:

  • Do not change the server IP or port away from 127.0.0.1:4567. The proxy expects the server there, and exposing it directly would publish an unauthenticated reader.
  • Suwayomi's own authentication is deliberately off. The nginx layer is what authenticates you. Turning on Suwayomi's built-in auth as well is supported but gives you two credentials to manage.

Suwayomi writes automatic backups into the data root. List them, and inspect what the data disk is holding:

sudo ls -la /var/lib/suwayomi/backups
sudo du -sh /var/lib/suwayomi 2>/dev/null
df -h /var/lib/suwayomi | tail -1

Because the library, downloads and backups all live on the dedicated data disk, you can snapshot that disk in Azure for a point-in-time copy of the whole library, and grow it without touching the OS disk.

Step 14: Change the Reader Password

The reader credential is an nginx htpasswd entry, so rotate it with htpasswd, replacing <new-password> with your own:

sudo htpasswd -bB /etc/nginx/.suwayomi_htpasswd admin '<new-password>'
sudo chown root:www-data /etc/nginx/.suwayomi_htpasswd
sudo chmod 0640 /etc/nginx/.suwayomi_htpasswd
sudo nginx -t && sudo systemctl reload nginx.service

-B stores the password bcrypt-hashed. To keep the password out of your shell history, drop the -b flag and the argument (sudo htpasswd -B /etc/nginx/.suwayomi_htpasswd admin) and htpasswd will prompt for it instead. Update /root/suwayomi-credentials.txt yourself if you want that file to stay accurate — nothing reads it at runtime, it is a record for you.

Step 15: Patching, Logs and Troubleshooting

Unattended security upgrades are enabled, so the OS keeps patching itself:

systemctl is-enabled unattended-upgrades.service
cat /etc/apt/apt.conf.d/20auto-upgrades

Server logs go to the journal, and Suwayomi also writes its own log files onto the data disk:

sudo journalctl -u suwayomi.service -n 20 --no-pager
sudo ls -la /var/lib/suwayomi/logs

Common checks:

  • Browser prompts repeatedly / 401 loop — the password is wrong. Re-read it with sudo cat /root/suwayomi-credentials.txt, or set a new one (Step 14).
  • HTTP 502 from the proxy — Suwayomi is not up. sudo systemctl status suwayomi.service and sudo journalctl -u suwayomi.service -n 50. A JVM start takes a few seconds; a heap set larger than the VM's RAM (Step 12) will fail here.
  • HTTP 500 on the reader but /healthz returns 200 — the proxy's credential file is missing. That is the fail-closed state; restore it with Step 14.
  • A new title does not appear — restart the server so the Local source re-indexes (Step 10), and check the directory is owned by suwayomi. A chapter directory with no page images in it is indexed as an empty chapter.
  • ERROR CEFManager -- Failed to set up CEF / CefException: CEF is disabled in the journal at every start — this is expected and harmless. CEF is Suwayomi's optional embedded Chromium WebView, used only for sources that need to solve an in-browser challenge. This image sets server.kcefEnabled = false because CEF downloads a full Chromium runtime at first use, which a headless server does not need and which would add a large unpatched attack surface to the image. Suwayomi logs the refusal at ERROR level; nothing is broken. If you specifically need a source that requires a browser challenge, enable kcefEnabled under Settings and accept that download, or configure FlareSolverr instead.
  • Suwayomi rewrites server.conf — this is normal. On its first start it normalises the file into its own flat server.<key> = <value> reference form, keeping your values. Edit it in that form, or use the UI.

Security

The Suwayomi server binds only to 127.0.0.1:4567 and is never exposed to the network; nginx on port 80 is the sole front door and requires HTTP authentication for every path except /healthz. The admin password is generated uniquely on each VM's first boot and stored in /root/suwayomi-credentials.txt (mode 0600, root only) — no shared or default credential exists in the image, and the server ships with no in-app account at all. The service runs as the unprivileged suwayomi user under systemd hardening (NoNewPrivileges, ProtectSystem=full, PrivateTmp, and write access confined to the data root). Restrict port 80 with your NSG to the client CIDRs that need the reader, keep port 4567 closed, and terminate TLS in front of the VM before production. The library and downloads live on a dedicated data disk you can encrypt with Azure disk encryption and snapshot independently.

You are responsible for the extension repositories you add and the content you access through them. cloudimg bundles no catalog and no repository.

Support

24/7 technical support from cloudimg by email and live chat, covering deployment and VM sizing, reverse-proxy and authentication setup, extension-source configuration, data-disk management and backups, and JVM administration. Email support@cloudimg.co.uk.