Suwayomi Server on Ubuntu 24.04 on Azure User Guide
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.servicerunning as the unprivilegedsuwayomiservice user, bound to127.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 andserver.conf - An nginx reverse proxy on port 80 with HTTP Basic authentication and an unauthenticated
/healthzendpoint - 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.

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.

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.

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.

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.

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.

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.

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.

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.serviceandsudo 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
/healthzreturns 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 disabledin 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 setsserver.kcefEnabled = falsebecause 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, enablekcefEnabledunder 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 flatserver.<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.