Applications Azure

Yuvomi on Ubuntu 24.04 on Azure User Guide

| Product: Yuvomi on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Yuvomi on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Yuvomi is an open source, self-hosted family planner that brings a whole household's day to day organisation into one private web app. It combines shared tasks and chores, a family calendar, shopping and pantry lists, meal planning and recipes, budgets and contacts, with an account for each family member so everyone sees what they need and jobs can be assigned and tracked. Everything lives on your own server rather than a third party cloud, so household routines, schedules and finances stay under your control.

The cloudimg image ships the free and open source, MIT licensed Yuvomi application, run the officially supported way as a single container built from the pinned upstream source and backed by an embedded SQLite database, so there is no external database to provision and your instance starts in seconds. Upstream Yuvomi lets the first visitor to a new instance run the setup wizard and become the admin, which is a real risk for a VM with a public IP; this image closes that window completely. On first boot, before the public port is ever opened, the instance generates a per-VM session signing secret, a per-VM database encryption key and claims the admin account itself with a per-VM random password, written to a root-only file. The database is encrypted at rest with a key unique to this VM. Backed by 24/7 cloudimg support.

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

The docker, yuvomi-firstboot, yuvomi, yuvomi-postboot and nginx services all active, and the Yuvomi container healthy and published only to 127.0.0.1:3000, with host nginx the single public listener terminating TLS on port 443

What is included:

  • Yuvomi v1.87.0 (the MIT licensed Node.js family planner), built from the pinned upstream source tag
  • Embedded SQLite database, created empty on first boot, encrypted at rest with a per-VM key and stored on a persistent path
  • Docker Engine running the application container, published to loopback only
  • Host nginx as the single public listener terminating TLS on port 443, with a per-VM self-signed certificate and a redirect from port 80
  • yuvomi.service, yuvomi-firstboot.service and yuvomi-postboot.service as systemd units, enabled and active on boot
  • A per-VM session signing secret, a per-VM database encryption key and a per-VM admin account password, generated on first boot and never baked into the image
  • The admin account claimed during bootstrap while port 443 is still closed, so a passer-by can never run the setup wizard
  • No open self-registration: further members are added invite-only by the admin from Settings
  • No default login, no shipped secret, no bundled third-party API key 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 Yuvomi listing on Azure Marketplace

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a comfortable starting point for a person, a household or a small family; the application idles at around 150 MB of memory. For a large household or many concurrent users use Standard_D2s_v5 or larger. NSG inbound: allow 22/tcp from your management network and 443/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 Yuvomi 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 HTTPS (443). Then Review + create and Create.

Step 2: Deploy from the Azure CLI

RG="yuvomi-prod"; LOCATION="eastus"; VM_NAME="yuvomi-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/yuvomi/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name yuvomi-vnet --address-prefix 10.100.0.0/16 --subnet-name yuvomi-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name yuvomi-nsg
az network nsg rule create -g "$RG" --nsg-name yuvomi-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 yuvomi-nsg --name allow-https --priority 110 \
  --destination-port-ranges 443 --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 yuvomi-vnet --subnet yuvomi-subnet --nsg yuvomi-nsg --public-ip-sku Standard

Replace <sub-id> and <version> with your subscription id and the image version shown on the listing, and <your-mgmt-cidr> with the network you administer from.

Step 3: First boot and per-instance credentials

On the first boot of each VM, Yuvomi generates its own per-instance secrets and claims its own admin account before the web port is opened. Nothing is baked into the image. Give the instance a minute after first boot, then SSH in and read the credentials file (it is 0600 root:root):

sudo cat /root/yuvomi-credentials.txt

The per instance credentials file, showing the Yuvomi admin login generated randomly for this VM (masked here) and the resolved web URL, with the credentials file confirmed as 0600 root:root

The file contains everything unique to this instance:

  • YUVOMI_USERNAME / YUVOMI_PASSWORD — the admin login you use in the web UI. The admin has full access, including member management.
  • YUVOMI_URL — the web address of this instance, resolved from its public IP on first boot.

The session signing secret and the database encryption key are held in /opt/yuvomi/.env (also 0600 root:root) and never leave the VM. Confirm the services and container are healthy:

sudo systemctl is-active docker yuvomi-firstboot yuvomi yuvomi-postboot nginx
active
active
active
active
active
sudo docker compose -f /opt/yuvomi/docker-compose.yml ps --format 'table {{.Service}}\t{{.Status}}\t{{.Ports}}'
SERVICE   STATUS                   PORTS
yuvomi    Up 8 minutes (healthy)   127.0.0.1:3000->3000/tcp

The application container publishes to loopback only; host nginx on port 443 is the single public door and terminates TLS.

Step 4: The security model

Upstream Yuvomi guides the first person who opens a new instance through the setup wizard that creates the admin account. On a VM with a public IP that is a real risk, so cloudimg removes it in two independent ways.

First, yuvomi-postboot.service claims the admin account itself, over the loopback port, with a password generated for this VM. Yuvomi's own setup endpoint then returns 404 forever in production once a user exists, which is enforced by the application's code rather than by a configuration flag. Second, host nginx — the only public listener — does not start until that has happened: it is gated on a bootstrap-ready marker that post-boot creates only after the admin exists. Port 443 is therefore closed for the whole bootstrap window.

The session signing secret and the database encryption key are generated on first boot too, before the stack can start, so the upstream placeholder values (REPLACE_WITH_A_LONG_RANDOM_STRING, REPLACE_WITH_A_STRONG_ENCRYPTION_KEY) never exist on your VM. A start-up guard refuses to launch the application at all if either secret is empty, too short or still a placeholder, and the database is encrypted at rest with the per-VM key.

The security posture: the Yuvomi app listening only on 127.0.0.1:3000 with nginx the only public 443 listener, the setup wizard refused with 404 after the admin was claimed, an anonymous request to the authenticated API returning 401, and a wrong password rejected with 401

ss -tln | grep -E ':(443|3000) ' | awk '{print $1, $4}'
LISTEN 127.0.0.1:3000
LISTEN 0.0.0.0:443
LISTEN [::]:443

The setup wizard is closed and authenticated data is not readable anonymously:

curl -sk -o /dev/null -w 'setup wizard (after admin claimed) -> %{http_code}\n' -X POST https://127.0.0.1/api/v1/auth/setup -H 'Content-Type: application/json' --data '{"username":"probe","display_name":"probe","password":"probe-should-never-work"}'
curl -sk -o /dev/null -w 'authenticated API (anonymous) -> %{http_code}\n' https://127.0.0.1/api/v1/auth/me
setup wizard (after admin claimed) -> 404
authenticated API (anonymous) -> 401

The on-disk database is encrypted at rest, so its header is not the plaintext SQLite marker:

sudo head -c 16 /var/lib/yuvomi/data/yuvomi.db | grep -qa "SQLite format 3" && echo "plaintext" || echo "encrypted (no plaintext SQLite header)"
encrypted (no plaintext SQLite header)

Step 5: Verify the end-to-end round-trip

The image ships a prover that exercises the whole security model through the public front door: it confirms the app answers, that the setup wizard is closed, that a wrong password is rejected, and that the per-instance admin password logs in, issues a session, and creates and reads back a real task.

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

The credential round-trip prover reporting OK: health ok, the anonymous authenticated API returned 401, the setup wizard returned 404, a wrong password was rejected 401, login issued a session and CSRF token, the authenticated whoami carries the admin username, and a task was created and read back

Step 6: Sign in to the web app

Open https://<vm-ip>/ in your browser and sign in with the YUVOMI_USERNAME and YUVOMI_PASSWORD from the credentials file. The image uses a per-VM self-signed certificate, so your browser will show a certificate warning the first time; accept it, or install your own certificate at /etc/ssl/yuvomi/.

The Yuvomi sign-in page asking for a username and password, for the admin account created on this VM during first boot

Once signed in, the dashboard is the home view. It gathers the household's day at a glance — upcoming tasks and events, shopping lists, meals and more — with the module navigation down the side so you can open tasks, the calendar, shopping, meals, budget and contacts.

The signed-in Yuvomi dashboard showing the household overview with widgets for tasks, calendar and lists, and the module navigation for tasks, calendar, shopping, meals, budget and contacts

Choose Tasks to see and manage the household's shared to do list. Each task can be assigned to a family member, given a due date, a priority and a category, so chores and jobs are shared out and tracked rather than forgotten.

The Yuvomi Tasks view showing several household tasks with their titles, categories and due dates, proving the task database is live and read-write through the web UI

The Calendar brings the family's events together in one shared month view, so appointments, activities and reminders for everyone in the household are visible in one place.

The Yuvomi Calendar view showing a shared month grid with household events, demonstrating the family calendar module

Adding household members

There is no open self-registration on this image, so nobody can create an account on your instance. To add a family member, sign in as the admin, open Settings, and invite them there. Each person gets their own login and sees the household's shared tasks, calendar and lists according to what is shared with them.

Using your own domain

On first boot the instance sets its own address, BASE_URL, to https://<vm-ip>, and generates a self-signed certificate for that address. If you reach the VM by a DNS name rather than its IP address, point a hostname at the VM, then set BASE_URL in /opt/yuvomi/.env to that URL — for example https://yuvomi.example.com — install a certificate for that name at /etc/ssl/yuvomi/yuvomi.crt and /etc/ssl/yuvomi/yuvomi.key, and restart the service:

sudo systemctl restart yuvomi

The same applies if the VM's public IP changes, for example after a deallocate and start.

Managing the service

# view recent application logs
sudo docker compose -f /opt/yuvomi/docker-compose.yml logs --tail 50 yuvomi
# restart the stack
sudo systemctl restart yuvomi

The upstream licence text for the version shipped here is recorded on the VM at /usr/share/doc/yuvomi/, alongside a note on the pinned source it was built from.

Support

cloudimg provides 24/7 support with a guaranteed 24 hour response SLA. Contact support@cloudimg.co.uk for assistance with this image.