Applications Azure

KitchenOwl on Ubuntu 24.04 on Azure User Guide

| Product: KitchenOwl on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of KitchenOwl on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. KitchenOwl is an open source app for managing a household's food. Several people share the same shopping list and items check off in real time as anyone shops, so the list stays current whoever is at the store. You keep a collection of recipes, add their ingredients to the list in one tap, and plan meals across the week on a calendar. It also tracks grocery expenses so a household can split the cost. A clean Flutter web app fronts everything and the same account works from the mobile apps.

The cloudimg image ships the free and open source, AGPL-3.0 licensed KitchenOwl, run the officially supported way as the upstream all in one container pinned by image digest and captured into the VM, so your instance starts in seconds. Because KitchenOwl's upstream token signing secret is a well known fixed value, nothing here ships with a known secret: a unique JWT signing secret is generated for each VM on first boot, before the app is reachable, and a per instance admin account with a random password is seeded once the app is healthy. Open self sign up is disabled and onboarding closes as soon as the administrator exists. Backed by 24/7 cloudimg support.

KitchenOwl is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the KitchenOwl project. It ships the free and open source AGPL-3.0 licensed self hosted software, unmodified.

The docker, kitchenowl-firstboot, kitchenowl, kitchenowl-postboot and nginx services all active, and the kitchenowl compose container running and healthy

What is included:

  • KitchenOwl v0.7.9 (the AGPL-3.0 licensed all in one container: Flask/uWSGI API plus the built Flutter web app), pinned by image digest
  • A SQLite application database, created empty on first boot and stored on a persistent Docker volume at /data
  • Docker Engine with the app published to the loopback interface only, fronted by nginx on port 80 with WebSocket upgrade for realtime shopping list sync
  • kitchenowl.service, kitchenowl-firstboot.service, kitchenowl-postboot.service and nginx.service as systemd units, enabled and active on boot
  • A unique JWT signing secret and a per instance admin account with a random password generated per VM on first boot, never baked into the image
  • No default login, no shipped secret, open self sign up disabled and an empty database on first boot
  • Ubuntu 24.04 LTS base with latest security patches applied at build time
  • Azure Linux Agent for seamless cloud integration and SSH key injection
  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region
  • Subscription to the KitchenOwl listing on Azure Marketplace

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a sensible starting point for a household. For larger households or many concurrent users use Standard_D2s_v5 or larger. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web app from the networks that use it.

Step 1: Deploy from the Azure Portal

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for KitchenOwl 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.

Step 2: Deploy from the Azure CLI

RG="kitchenowl-prod"; LOCATION="eastus"; VM_NAME="kitchenowl-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/kitchenowl-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name ko-vnet --address-prefix 10.100.0.0/16 --subnet-name ko-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name ko-nsg
az network nsg rule create -g "$RG" --nsg-name ko-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name ko-nsg --name allow-http --priority 110 \
  --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name ko-vnet --subnet ko-subnet --nsg ko-nsg --public-ip-sku Standard

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

Step 4: Confirm the services are running

The app runs as one all in one container under kitchenowl.service, fronted by nginx. The container is published to 127.0.0.1:8080 only; nginx on :80 is the single public front door. Confirm the services are active and see the container:

sudo systemctl is-active docker kitchenowl nginx
sudo docker compose -f /etc/kitchenowl/compose.yaml ps

You will see the services report active and the container running. KitchenOwl is bound only to the loopback interface; nginx on :80 proxies / to it and passes through WebSocket upgrades so the shopping list syncs in real time.

Step 5: Read the per instance credentials

A unique JWT signing secret was generated for this VM on the first boot, before the app was reachable, and a per instance admin account with a random password was seeded once the app was healthy and written to a root only file. Read it:

sudo cat /root/kitchenowl-credentials.txt

The file (mode 0600 root:root) holds ADMIN_USERNAME and ADMIN_PASSWORD (the account you sign in to the web app with) and WEB_URL. None of these ship in the image; every value is unique to this VM, so no two instances share a credential and there is no default login to change.

The kitchenowl-credentials.txt file at mode 0600 root root with the per VM admin username and password and the web URL, the password redacted, and a note that they are generated uniquely on first boot

Step 6: Verify the security model

The web app and the health endpoint are reachable without authentication, but every protected API endpoint requires a bearer token, and open self sign up is disabled. Confirm that the web app loads, that an unauthenticated request to a protected endpoint is rejected with 401, and that the per instance admin credential authenticates a real call:

ADMIN_USERNAME=$(sudo grep '^ADMIN_USERNAME=' /root/kitchenowl-credentials.txt | cut -d= -f2-)
ADMIN_PASSWORD=$(sudo grep '^ADMIN_PASSWORD=' /root/kitchenowl-credentials.txt | cut -d= -f2-)
HEALTH=/api/health/8M4F88S8ooi4sMbLBfkkV7ctWwgibW6V
curl -s -o /dev/null -w 'web UI       (no auth):   %{http_code}\n' http://localhost/
curl -s -o /dev/null -w 'health       (no auth):   %{http_code}\n' "http://localhost$HEALTH"
curl -s -o /dev/null -w 'GET /api/user (no token): %{http_code}\n' -H 'Accept: application/json' http://localhost/api/user
TOKEN=$(curl -s -X POST http://localhost/api/auth \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -d "{\"username\":\"$ADMIN_USERNAME\",\"password\":\"$ADMIN_PASSWORD\",\"device\":\"guide\"}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
curl -s -o /dev/null -w 'GET /api/user (token):    %{http_code}\n' \
  -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' http://localhost/api/user

The web app returns 200, the health endpoint returns 200, the protected user endpoint is rejected with 401 for no token, and the same call with the per instance admin token returns 200. This is the security model: the API is gated by a bearer token you obtain by signing in, and there is no open registration.

curl showing the web app returning HTTP 200, the health endpoint returning 200, and the protected user endpoint returning 401 without a token and 200 with the per instance admin token

The same round trip is bundled as a single script on the image, which the build and smoke tests run to prove the credential works end to end. It signs in, creates a household, adds a shopping list item and reads it back:

sudo /usr/local/sbin/kitchenowl-roundtrip.sh

The bundled round trip script reporting OK: the web app and health endpoint are live, no and wrong tokens are rejected, and the per instance admin credential creates a household and shopping list item and reads it back

Step 7: Open the web app and sign in

Browse to http://<vm-ip>/ to reach the KitchenOwl web app. Sign in with the ADMIN_USERNAME and ADMIN_PASSWORD from Step 5.

The KitchenOwl sign in page with a Welcome back heading and Username and Password fields and a Login button

Step 8: Use the shared shopping list

After signing in, open a household to reach its shopping list. Add items by typing in the search box and tapping to add, and check them off as you shop. Every member of the household sees the same list and it syncs in real time, so whoever is at the store always has the current list. Items can be grouped by category and sorted alphabetically or by how often you buy them.

The KitchenOwl shopping list for the cloudimg Demo Household showing eight items as cards, Bananas, Cheddar cheese, Coffee beans, Eggs, Milk, Olive oil, Sourdough bread and Tomatoes, with a search box and the Shopping list, Recipes, Meal planner and Balances navigation

Step 9: Keep a recipe collection

Open Recipes to store your household's recipes with their ingredients, steps, cook time and yield. From a recipe you can add all of its ingredients to the shopping list in one tap, and you can import recipes from a URL. Use the search box to find a recipe instantly.

The KitchenOwl recipes page for the cloudimg Demo Household showing a Weekend Pancakes recipe in the list, with a search box and an add button

Step 10: Plan meals for the week

Open Meal planner to plan which recipes you will cook on which days. Add a recipe to a day and KitchenOwl can add its missing ingredients to the shopping list for you, so the weekly shop follows the plan. The planner starts empty and prompts you to pick from your recipes.

The KitchenOwl meal planner for the cloudimg Demo Household showing the Your planned meals heading, an empty state message and a Discover recipes button

Step 11: Add household members

Open self sign up is disabled on this image, so new members are added by the administrator rather than by anyone who reaches the URL. Sign in as the admin, open Settings, and create accounts for your household members, or generate an invite. To enable open registration instead (anyone can create their own account), edit /etc/kitchenowl/compose.yaml, set OPEN_REGISTRATION to "true", and restart the app:

sudo systemctl restart kitchenowl

Step 12: Call the API from your own machine

Every feature of the web app is backed by the REST API, which you can call directly. Obtain a token by signing in, then call a protected endpoint with the VM address:

TOKEN=$(curl -s -X POST http://<vm-ip>/api/auth \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -d '{"username":"<ADMIN_USERNAME>","password":"<ADMIN_PASSWORD>","device":"cli"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
curl -s -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' \
  "http://<vm-ip>/api/household"

The login returns a short lived access token (15 minutes) plus a refresh token; a long lived token for automation can be minted with POST /api/auth/llt. The API is documented at http://<vm-ip>/api/openapi.

Step 13: Server components

Component Version / Detail
Application KitchenOwl v0.7.9 all in one (Flask/uWSGI API + Flutter web UI), pinned by image digest
Front door nginx on :80 proxying / to the app with WebSocket upgrade
Application database SQLite at /data/database.db (created empty on first boot, on a persistent volume)
Orchestration Docker Compose under kitchenowl.service
JWT signing secret per instance, generated first boot into /etc/kitchenowl/kitchenowl.env
Admin account per instance random password, seeded first boot into /root/kitchenowl-credentials.txt
Registration open self sign up disabled (OPEN_REGISTRATION=false)
Operating system Ubuntu 24.04 LTS (patched at build)
License AGPL-3.0 (KitchenOwl)

Step 14: Managing the service

sudo systemctl status kitchenowl --no-pager | head -12
sudo docker compose -f /etc/kitchenowl/compose.yaml logs --tail 40 kitchenowl

Restart the app with sudo systemctl restart kitchenowl, follow the logs live with sudo docker compose -f /etc/kitchenowl/compose.yaml logs -f kitchenowl, and view configuration in /etc/kitchenowl/kitchenowl.env and /etc/kitchenowl/compose.yaml. After changing the environment file, restart the service to apply it.

Step 15: Use your own domain and HTTPS (production)

The image serves the web app over plain HTTP on port 80, which is convenient behind a load balancer or private network. For production you should terminate TLS in front of the VM so credentials travel encrypted:

  • Front the VM with Azure Application Gateway, a load balancer with a managed certificate, or a CDN, and forward to nginx on port 80.
  • Or install your own certificate: add a TLS server block to /etc/nginx/sites-available/kitchenowl referencing your certificate and key, open 443/tcp on the NSG, then sudo systemctl reload nginx.
  • If you serve the app from a custom domain, set FRONT_URL in /etc/kitchenowl/kitchenowl.env to that URL and restart the app so realtime sync uses the right origin. The app reads its URL at first boot from the resolved public address, so use a stable public IP or set the address before first boot.

Step 16: Security recommendations

  • Restrict the NSG. Allow TCP 80 (and 22 for admin) only from the networks that use the app.
  • Terminate TLS in front of the app (Step 15) so the admin password and tokens are encrypted in transit.
  • Rotate the seeded admin password. Sign in and change it in Settings.
  • Keep registration closed. Open self sign up is disabled by default; leave it that way and add members as the administrator unless you specifically want open registration.
  • Keep the app private. KitchenOwl is bound to loopback and fronted by nginx; keep it that way and never expose the container port directly.
  • Keep the OS patched. Unattended security upgrades remain enabled on the running VM.

Step 17: Support and Licensing

KitchenOwl is distributed under the GNU Affero General Public License v3.0 (AGPL-3.0). This cloudimg image bundles the unmodified official open source release; cloudimg provides the packaging, the nginx front door, the per instance secret and admin generation, the paired deploy guide, and 24/7 support with a guaranteed 24 hour response SLA. KitchenOwl is an independent open source project and this image is not affiliated with or endorsed by it.

Deploy on Azure

Launch KitchenOwl on Ubuntu 24.04 LTS by cloudimg from the Azure Marketplace and follow this guide to a working household grocery, recipe and meal planning app in minutes.