Applications Azure

Kyoo on Ubuntu 24.04 on Azure User Guide

| Product: Kyoo on Ubuntu 24.04 LTS on Azure

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.

The docker, kyoo-firstboot, kyoo and kyoo-postboot services all active, and the seven pinned upstream containers - front, auth, api, scanner, transcoder, traefik and a healthy postgres - all running under docker compose

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.service and kyoo-postboot.service as 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

  1. In the Azure Portal, search the Marketplace for Kyoo on Ubuntu 24.04 LTS by cloudimg and select Create.
  2. Choose your subscription, resource group and region.
  3. Set the VM size to Standard_B4ms or larger (see the sizing table above).
  4. Provide an administrator username and SSH public key.
  5. On the Networking tab, allow inbound HTTP (80). That single port is the whole public surface of this image.
  6. 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 kyoo credentials file and the environment file both listed with 0600 root:root permissions, demonstrating that the per VM secrets exist and are root only without ever displaying their values

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

The ss output showing that only port 80 is publicly bound, on both IPv4 and IPv6, with no database or microservice port exposed

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

The end to end proof reporting the advertised web address and the admin login, an unauthenticated request rejected with 401, the admin authenticating and gating the API, and the demo title scanned into the library and streamed back as real media bytes

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.

The Kyoo sign in page asking for a username and a password

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.

The Kyoo Browse library showing the pre loaded demo title as a poster tile, matched to its official artwork, with filters for media type, genres, studios and staff

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.

The Kyoo detail page for the demo title showing the backdrop, poster, play button, rating and runtime, and matched metadata including genre

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.

The Kyoo web player streaming the demo title, with the video rendered in the player alongside the timeline, play, volume, settings and fullscreen controls

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.