Kitsu on Ubuntu 24.04 on Azure User Guide
Overview
Kitsu, by CGWire, is the popular open source collaborative production tracking platform for animation, VFX and games studios. It gives a studio one place to run a production: break a project down into episodes, sequences, shots and assets, define the task pipeline and assign the work, track the status of every task on a board, review and annotate media, and follow progress and workload across the whole team.
This image runs Kitsu bare metal behind nginx. The Zou API server (the Kitsu backend) runs under gunicorn on the loopback interface, a second gunicorn process serves the Socket.IO events stream for real-time updates, and an RQ worker processes background preview and playlist encoding jobs with FFmpeg. PostgreSQL provides the database and Redis provides the key-value store and job broker, both on the same VM and bound to the loopback interface only. nginx serves the Kitsu single-page web application and reverse-proxies the API and the events stream, so the whole platform is reachable on port 80.
The Kitsu administrator account, the PostgreSQL password and the Flask token-signing secret are generated on the first boot of every deployed VM. Two VMs launched from the same image never share a credential and never share a token-signing secret. The initial administrator email and password and the PostgreSQL password are written to /root/kitsu-credentials.txt with mode 0600 so that only the root user can read them. No studio users, no production content and no shared secret ship in the image.
What is included:
- Kitsu 1.0.56 (the pre-built Vue web application) served by nginx on
:80 - Zou 1.0.64 (the Kitsu API) under gunicorn on loopback
:5000, with the Socket.IO events stream on:5001 - An RQ background worker (
zou-jobs) with FFmpeg for preview and playlist encoding - PostgreSQL and Redis, bound to loopback only
- Per-VM administrator, database and token-signing credentials generated at first boot, in a root-only file
- Six systemd units enabled and active
- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2ms (2 vCPU / 8 GiB RAM) is the recommended starting point for a multi-user studio, because preview and movie encoding are processor and memory heavy; the image also runs comfortably on Standard_B2s (4 GiB) for small teams and evaluation. NSG inbound: allow 22/tcp from your management network and 80/tcp (plus 443/tcp once you enable HTTPS) from the networks your team will reach Kitsu on.
Step 1: Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Kitsu by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create and Create. First boot initialisation takes approximately one to two minutes after the VM starts.
Step 2: Deploy from the Azure CLI
Replace the resource group, image reference, VNet and subnet with your own:
az vm create \
--resource-group <your-rg> \
--name kitsu \
--image <marketplace-image-urn> \
--size Standard_B2ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name kitsu --port 80 --priority 1010
Step 3: Connect and Retrieve Initial Credentials
Connect over SSH with the key pair you supplied at deploy time:
ssh azureuser@<vm-public-ip>
The per-VM administrator and PostgreSQL passwords are written to a root-only file. Read it with sudo, and confirm the versions you are running:
/opt/zou/zouenv/bin/pip show zou | awk -F': ' '/^Version/{print "Zou " $2}'
cat /opt/kitsu/dist/.version.txt | sed 's/^/Kitsu SPA /'
sudo cat /root/kitsu-credentials.txt
The file lists the Kitsu administrator email and password, the database name, user and password, and the URL to reach the web interface. Keep these somewhere safe.

Step 4: Confirm the Services Are Running
The image runs six systemd units. Confirm they are all active, that the datastores are bound to loopback only, and that the web application and API answer:
systemctl is-active postgresql redis-server nginx zou zou-events zou-jobs
ss -tln | grep -E '127.0.0.1:5000|127.0.0.1:5001|127.0.0.1:5432|127.0.0.1:6379|:80 '
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/api/status
All six units report active, PostgreSQL (5432), Redis (6379) and the Zou API/events (5000/5001) listen on 127.0.0.1 only, nginx listens on :80, and both the web application and the API return 200.

Step 5: First Login to the Kitsu Web Interface
Open a web browser and navigate to http://<vm-public-ip>/. Kitsu presents its sign-in page. Enter the administrator email (<KITSU_ADMIN_EMAIL>) and the password from /root/kitsu-credentials.txt, then select Log in.

For a production deployment, change the administrator password that was generated on first boot from the user menu once you have signed in.
Step 6: Track a Production - Assets, Shots and Tasks
Kitsu organises work by production. Create one from the Productions page (the Add a production button), giving it a name and a type such as a short, a feature or a TV show. Each production carries its own resolution, frame rate and pipeline.

Inside a production you break the work down into assets (characters, props, environments) and shots (grouped into sequences), then assign task types such as Modeling, Shading, Rigging, Layout and Animation. Kitsu shows a breakdown grid per entity type, with a colour-coded status cell for every task, so a producer can see at a glance where the production stands and an artist can see exactly what to do next.


As artists work, they set a task's status (Todo, Work In Progress, Waiting For Approval, Retake, Done), publish previews for review, and leave comments. Supervisors review and approve from the same board.
Step 7: The REST API
Everything in the web interface is backed by a REST API under /api/, which requires authentication. You can drive it from curl: log in to obtain an access token, then pass it as a bearer token. The examples below use the administrator password from the credentials file (shown as <KITSU_ADMIN_PASSWORD>):
# Log in and capture an access token
TOKEN=$(curl -s -H 'Content-Type: application/json' \
-d '{"email":"<KITSU_ADMIN_EMAIL>","password":"<KITSU_ADMIN_PASSWORD>"}' \
http://127.0.0.1/api/auth/login | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# List productions with the token
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1/api/data/projects \
| python3 -m json.tool

The image is secure by default: the Zou project default administrator (super.user@mycgstudio.com / mysecretpassword) does not exist on your VM and is rejected, and unauthenticated API calls are refused. Only the per-VM administrator generated at first boot can sign in:
# The Zou default admin is rejected (HTTP 400)
curl -s -o /dev/null -w '%{http_code}\n' -H 'Content-Type: application/json' \
-d '{"email":"super.user@mycgstudio.com","password":"mysecretpassword"}' \
http://127.0.0.1/api/auth/login
# An unauthenticated API request is rejected (HTTP 401)
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/api/data/projects

Step 8: Add Studio Users
Kitsu has no public self-registration by design: an administrator or manager invites each user, so a freshly launched instance cannot be seized by a stranger. Add people from Studio → People in the web interface (or through the API), set each person's role and department, and assign them to the productions they work on. New users receive their own login and see only the productions they are members of.
Step 9: Real-Time Events and the Background Worker
Kitsu is collaborative in real time: when a colleague changes a task status or publishes a preview, everyone else's board updates live. That is served by the zou-events unit (a Socket.IO stream on 127.0.0.1:5001), which nginx proxies at /socket.io. Heavier work - normalising uploaded movies, generating thumbnails and building playlists - is handed to the zou-jobs RQ worker, which uses FFmpeg. Check both:
systemctl status zou-events --no-pager | head -n 5
systemctl status zou-jobs --no-pager | head -n 5
ffmpeg -version | head -n 1
Step 10: Services and Operations
The zou unit runs the API under gunicorn on 127.0.0.1:5000; nginx reverse proxies port 80 to it, and to the events stream on :5001. Configuration lives in /etc/zou/zou.env (loopback database and Redis, the token-signing secret, the preview folder). Confirm the layout and run Zou management commands as the zou user with the environment file loaded:
ls -ld /opt/zou/zouenv /opt/kitsu/dist /opt/zou/previews
sudo -u zou --preserve-env bash -c 'set -a; . /etc/zou/zou.env; set +a; /opt/zou/zouenv/bin/zou --help' | head -n 12
Step 11: Enable HTTPS with Let's Encrypt
For any production deployment, serve the site over HTTPS so sign-in and media transfers cannot be intercepted. The image ships with nginx, which certbot can configure automatically. The following assumes a DNS record pointing your fully qualified domain name at the VM's public IP address and an NSG rule allowing 443/tcp:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d kitsu.your-domain.example \
--non-interactive --agree-tos -m you@your-domain.example \
--redirect
After certbot finishes, set the public domain so Kitsu generates correct links, then restart the API:
sudo sed -i 's|^DOMAIN_NAME=.*|DOMAIN_NAME=kitsu.your-domain.example|; s|^DOMAIN_PROTOCOL=.*|DOMAIN_PROTOCOL=https|' /etc/zou/zou.env
sudo systemctl restart zou zou-events
Step 12: Backups and Maintenance
Kitsu has two things that must be backed up together: the PostgreSQL database (zoudb) and the preview store under /opt/zou/previews. A simple, coordinated backup:
sudo -u postgres pg_dump -Fc zoudb | sudo tee /var/backups/kitsu-$(date +%F).dump > /dev/null
sudo tar czf /var/backups/kitsu-previews-$(date +%F).tgz -C /opt/zou previews
sudo ls -lh /var/backups/
Ship the dump and the preview archive to Azure Blob Storage or another object store on a schedule. For kernel and package updates, Ubuntu's unattended-upgrades is enabled, so security patches apply automatically. To update Kitsu itself, follow the upgrade workflow in the official documentation at https://dev.kitsu.cloud/.
Scaling Beyond a Single VM
For larger studios, decouple Kitsu from the single-VM pattern:
- Move PostgreSQL to Azure Database for PostgreSQL and update
DB_HOSTin/etc/zou/zou.env - Move Redis to Azure Cache for Redis and point
KV_HOSTat the cache endpoint - Move the preview store to Azure Blob Storage mounted via BlobFuse, or to Azure Files
- Put the web tier behind Azure Application Gateway, add the gateway hostname to
DOMAIN_NAME, and run thezou-jobsworker on dedicated VMs
Each of these is documented in the official Kitsu documentation at https://dev.kitsu.cloud/.
Support
This image is backed by 24/7 cloudimg support. Guaranteed response within 24 hours, one hour average for critical issues. Contact support@cloudimg.co.uk for help with deployment, upgrades, studio and user configuration, TLS termination, preview/encoding tuning and database administration.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.