Kyoo on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Kyoo on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Kyoo is an open source media server for a personal collection of movies and TV, a self hosted alternative to the likes of Jellyfin and Plex. You point it at a folder of video files and it scans them, matches each title against online metadata providers to pull in posters, summaries, cast and episode details, and presents everything as a clean, browsable library in a web client. From there you stream to your browser with on the fly transcoding, so a file plays smoothly even when its original format or bitrate does not suit the device or the connection.
Kyoo is built as a set of cooperating services, a web front end, a library API, a filesystem scanner and matcher, a transcoder and a database, all fronted by a single reverse proxy. The cloudimg image runs them the officially supported way, as the upstream containers pinned by image digest and captured into the VM, so your instance starts in seconds without downloading anything.
The image ships the free and open source, GPL-3.0 licensed Kyoo server. Its sample configuration ships published default secrets, a database password of password, a fixed sample scanner key, and an open first user, which on a reachable server would be an obvious risk. This image never runs on any of them. On the first boot of every VM a fresh database password, a fresh scanner key and a fresh administrator account with a random password are generated, and unauthenticated visitors are locked out until they sign in. A short demo clip is pre loaded so your library shows a real, scannable, streamable item the moment the VM boots. Backed by 24/7 cloudimg support.
Kyoo is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Kyoo project, Traefik, PostgreSQL, TheMovieDB or TheTVDB. It ships the free and open source software, unmodified.

What is included:
- Kyoo v5.1.0 (the GPL-3.0 licensed media server), run as seven official upstream containers pinned by image digest
- The Kyoo web UI, library API, auth service, filesystem scanner and matcher, and CPU transcoder
- PostgreSQL 18 as the datastore and Traefik v3.6 as the single public reverse proxy on port
80 - Docker Engine, with every service except the Traefik front door reachable only on a private internal network
kyoo-firstboot.service,kyoo.serviceandkyoo-postboot.serviceas systemd units, enabled and active on boot- A per VM PostgreSQL password, a per VM scanner key and a per VM admin account, all generated on first boot and never baked into the image
- Metadata enrichment that works out of the box with no third party key to obtain
- A small pre loaded demo title so the library is populated on first launch
- Ubuntu 24.04 LTS base with the latest security patches applied at build time and unattended security upgrades enabled
Metadata without a key
Kyoo enriches your library, posters, summaries, cast, with data from TheMovieDB and, optionally, TheTVDB. Supplying your own provider key is entirely optional: the upstream image bundles a default TheMovieDB read token, so scanning and matching work with nothing more than outbound internet access. The demo title in this guide is matched to its real poster and details with no key configured. If you would rather use your own read access token, or add a TheTVDB key, Step 11 shows how.
Sizing: what this really needs
Kyoo browses and direct plays comfortably on a modest VM, but transcoding is CPU heavy. When a file's format or bitrate does not suit the client, the transcoder re encodes it in software in real time, and 1080p and above is genuinely demanding.
| Workload | Recommended size |
|---|---|
| Browsing, metadata, single direct play (no re encode) | Standard_B2s (2 vCPU) is enough for a trial |
| Real use, one or two concurrent transcodes | Standard_B4ms (4 vCPU) - the recommended size |
| Several concurrent transcodes | A non burstable D series, Standard_D4s_v5 or larger |
Two practical points:
- Prefer a non burstable size for regular use. B series VMs are credit limited, and sustained transcoding will exhaust the credits and then throttle, at which point playback stutters. B series is fine for trying the image out and for light direct play; a D series sustains heavy concurrent transcoding far better.
- The transcoder is CPU only here. A generic VM has no GPU, so all re encoding is done in software. That is why concurrency, not library size, is what drives the sizing.
Prerequisites
- An Azure subscription with permission to create VMs and edit network security groups
- The Azure CLI installed and signed in, if you are deploying from the command line
- An SSH key pair for administrative access to the VM
- A modern browser on the viewing side
Step 1: Deploy from the Azure Portal
- In the Azure Portal, search the Marketplace for Kyoo on Ubuntu 24.04 LTS by cloudimg and select Create.
- Choose your subscription, resource group and region.
- Set the VM size to Standard_B4ms or larger (see the sizing table above).
- Provide an administrator username and SSH public key.
- On the Networking tab, allow inbound HTTP (80). That single port is the whole public surface of this image.
- Review and create.
Step 2: Deploy from the Azure CLI
Run these on your own machine. Replace the resource group, name and region to suit.
az group create --name kyoo-rg --location eastus
az vm create \
--resource-group kyoo-rg \
--name kyoo-vm \
--image cloudimg:kyoo-ubuntu-24-04:default:latest \
--size Standard_B4ms \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
# open port 80, the only port this image needs:
az vm open-port --resource-group kyoo-rg --name kyoo-vm --port 80 --priority 1001
To restrict access to your own network instead of the whole internet, add --source-address-prefixes <your.public.ip>/32 to the rule. Because your library is personal, this is recommended.
Step 3: Connect to your VM
ssh azureuser@<vm-ip>
Step 4: Confirm the services are running
systemctl is-active docker.service kyoo-firstboot.service kyoo.service kyoo-postboot.service
Every line should read active. The seven containers are managed by docker compose, with PostgreSQL reporting healthy through its own compose healthcheck:
sudo docker compose -f /etc/kyoo/docker-compose.yml ps
You should see front, auth, api, scanner, transcoder, traefik and postgres all Up, with postgres marked (healthy).
Step 5: Read the per instance credentials
A random administrator password was generated for this VM alone on its first boot, and the account was registered as the first Kyoo user, which upstream grants administrator rights. It is stored in a root only file.
sudo cat /root/kyoo-credentials.txt

The file records:
| Key | Meaning |
|---|---|
ADMIN_USERNAME |
The administrator login, admin |
ADMIN_PASSWORD |
The per instance administrator password |
WEB_URL |
The address to open in your browser |
The file is 0600 root:root, so only root can read it:
sudo stat -c '%a %U:%G' /root/kyoo-credentials.txt
The per VM database password and scanner key live, also 0600 root:root, in the environment file. The values are never displayed; you can confirm the file exists with the right permissions:
sudo stat -c '%a %U:%G' /etc/kyoo/.env
Step 6: Verify the security model
Every service other than the Traefik front door runs on a private internal network with no public port. Only port 80 is bound to the outside world:
ss -tln

You will see 0.0.0.0:80 and [::]:80 and nothing else public. PostgreSQL (5432), the auth service (4568) and the API (5000/3567) are all reachable only inside the docker network.
The library API refuses unauthenticated access. An anonymous request for the video list is rejected, and so is a request carrying an invalid token:
curl -s -o /dev/null -w 'no token: HTTP %{http_code}\n' http://127.0.0.1/api/videos
curl -s -o /dev/null -w 'invalid token: HTTP %{http_code}\n' \
-H 'Authorization: Bearer definitely-wrong-token' http://127.0.0.1/api/videos
The first returns 401 (no credentials) and the second returns 403 (the token is rejected). Guest access is disabled by default, so a visitor must sign in before browsing or playing anything.
Step 7: Run the end to end self test
The image ships a self test that exercises the whole path with the real per VM administrator account: it signs in, confirms the API is reachable only with a valid token, triggers a library scan, finds the pre loaded demo title, and streams real bytes back from it.
sudo /usr/local/sbin/kyoo-roundtrip.sh

It prints a single OK round-trip: line reporting the streamed byte count. That a title you just scanned both appears in the library and returns real media bytes is proof the scanner, database, API and transcoder are all working together.
Step 8: Open Kyoo and sign in
Open http://<vm-ip>/ in your browser and you are shown the Kyoo sign in page.

Sign in with ADMIN_USERNAME and ADMIN_PASSWORD from the credentials file in Step 5. Then select Browse from the top navigation to open your library.
Step 9: Browse your library
The Browse view is your library. On a fresh VM it already contains the pre loaded demo title, scanned and matched to its real poster and details with no metadata key configured.

Selecting a title opens its detail page, with the backdrop, poster, synopsis, rating, runtime, genres and cast that the scanner pulled from the metadata providers.

Step 10: Play a title
Press Play on the detail page and the title streams to your browser. The transcoder re encodes on the fly where needed, so playback starts without you preparing the file in any way.

Step 11: Add your own media
The demo title lives under /var/lib/kyoo/media on the VM. Add your own films and series to that folder, then rescan. From your own machine, copy the files onto the VM and move them into the library folder:
scp "My Film (2021).mkv" azureuser@<vm-ip>:/tmp/
ssh azureuser@<vm-ip> 'sudo mv "/tmp/My Film (2021).mkv" /var/lib/kyoo/media/ && sudo chmod -R a+rX /var/lib/kyoo/media'
Name files so the scanner can match them, Title (Year).ext for films works well. You can delete the demo clip once you have your own media in place. Trigger a rescan from the web UI under Admin, or the scanner will pick up new files on its next pass.
To use your own TheMovieDB read access token, or to add a TheTVDB key, edit the environment file and restart Kyoo:
sudo sed -i 's#^THEMOVIEDB_API_ACCESS_TOKEN=.*#THEMOVIEDB_API_ACCESS_TOKEN=<your-token>#' /etc/kyoo/.env
sudo systemctl restart kyoo.service
Step 12: Managing the service
Check the status of the stack:
sudo systemctl status kyoo.service --no-pager
Restart the whole stack:
sudo systemctl restart kyoo.service
View the logs of an individual service, for example the scanner:
sudo docker compose -f /etc/kyoo/docker-compose.yml logs --tail 40 scanner
Step 13: Use your own domain and HTTPS (production)
For anything beyond a trial, put a real hostname and a certificate in front of Traefik. Because Kyoo speaks only HTTP on port 80 to the outside, the simplest robust approach is to run a certificate terminating reverse proxy, or a cloud load balancer, in front of the VM and forward to port 80. Serving over HTTPS is the right choice for any deployment reachable from the internet, and some browser playback features expect a secure context.
Step 14: Security recommendations
- Restrict the source addresses on the network security group rule to your own network wherever you can. Your library is personal.
- Treat the admin password as privileged. The first user is an administrator and can manage the library, users and scans.
- Keep new users in check. Self registered users are unverified and powerless until an administrator verifies them; leave that default in place unless you intend to open the server up.
- Put HTTPS in front of it for any internet facing deployment, as in Step 13.
- Keep the OS patched. Unattended security upgrades are enabled on this image by default.
Step 15: Support and Licensing
Kyoo is free and open source software under the GPL-3.0 licence. The image also includes Traefik (MIT) as the reverse proxy and PostgreSQL (PostgreSQL licence) as the database, both used unmodified as their official upstream containers.
This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Kyoo project, Traefik, PostgreSQL, TheMovieDB or TheTVDB. Those names are used only to identify the software included.
For help with the image, contact cloudimg support, which is available 24/7. For questions about Kyoo itself, see the upstream project at github.com/zoriya/Kyoo.