Applications Azure

Jotty on Ubuntu 24.04 on Azure User Guide

| Product: Jotty on Ubuntu 24.04 LTS on Azure

Overview

Jotty is a fast, private, self-hosted place for your notes, checklists and kanban boards. You write in Markdown, organise with categories and tags, search across everything, and keep it all on infrastructure you control. The cloudimg image runs the official Jotty container image ghcr.io/fccview/jotty:1.26.0 (managed by Docker with a restart policy), bound to the loopback port 127.0.0.1:3000 behind an nginx reverse proxy on port 80. Jotty's store is entirely file-based — notes and checklists are plain Markdown and JSON files, with no SQL database, no Redis and no external services — and it lives on a dedicated Azure data disk mounted at /var/lib/jotty.

Upstream Jotty ships un-bootstrapped: the very first visitor to a fresh instance is sent to /auth/setup to self-register as the administrator. On a public cloud VM that is a takeover risk, so this image closes it: a per-VM administrator account is seeded automatically on the first boot of every VM, which means /auth/setup is already satisfied and simply redirects to the sign-in page. You retrieve the generated password from a root-only file and sign in. Backed by 24/7 cloudimg support.

What is included:

  • Jotty 1.26.0 running as the official container image, managed by Docker
  • Docker Engine and nginx preinstalled and enabled
  • The Jotty web UI on :80, fronted by nginx with the WebSocket upgrade the editor uses
  • A unique administrator account seeded on first boot and recorded in a root-only file (username admin)
  • First-visitor /auth/setup self-registration closed — it redirects to the sign-in page
  • A dedicated Azure data disk at /var/lib/jotty holding all notes, checklists and app state
  • The app bound to loopback only; nginx is the sole public surface, with server_tokens off, an $http_host allowlist and config paths returning 404
  • docker.service + jotty.service + nginx.service as systemd units, enabled and active
  • An unauthenticated /api/health endpoint for Azure Load Balancer health probes
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point for personal or small-team use; size up for many active users or very large note collections. NSG inbound: allow 22/tcp from your management network and 80/tcp. Jotty serves plain HTTP on port 80; for production, terminate TLS in front of it with your own domain (see Maintenance).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Jotty 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). Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name jotty \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --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 jotty --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active docker.service jotty.service nginx.service

All three report active. Docker runs the Jotty container (bound to the loopback port 127.0.0.1:3000), and nginx fronts it on port 80. Jotty's notes, checklists and state live on the dedicated Azure data disk mounted at /var/lib/jotty.

docker.service, jotty.service and nginx.service active, the Jotty container running, and the pinned upstream image recorded in /opt/jotty/VERSION

Step 5 - Retrieve your administrator credential

The administrator account is seeded uniquely on the first boot of your VM. The generated password is written to a root-only file (the file holds only the plaintext password; the store itself keeps just a SHA-256 hash):

sudo cat /root/jotty-credentials.txt

You will see the sign-in URL, the username (admin) and the per-VM password. Keep this password safe — it is the administrator for your Jotty instance.

The root-only per-VM credentials file with the sign-in URL, admin username and generated password, and the seeded admin record in the flat-file store with the password hash (both masked here)

Step 6 - Verify the app is serving

Jotty exposes an unauthenticated health endpoint, and the image ships a self-test that proves the per-VM admin gate end to end:

curl -s http://127.0.0.1:3000/api/health; echo
sudo /usr/local/sbin/jotty-selftest

The health endpoint returns {"status":"healthy",...}, and the self-test confirms the app is serving, the per-VM password matches the seeded admin, common and blank default passwords are rejected, and first-admin self-registration is guarded.

The /api/health endpoint returning healthy and the jotty-selftest proving the per-VM admin gate: app serving, setup guarded, defaults dead

Step 7 - Review the security posture

The image is locked down by default. The app port is loopback-only (nginx is the sole public surface), first-visitor /auth/setup self-registration is closed, and nginx refuses unknown Host headers and config paths:

curl -s -o /dev/null -w 'setup -> HTTP %{http_code} %{redirect_url}\n' http://127.0.0.1:3000/auth/setup
ss -lnt | grep -E ':3000|:80 '
curl -s -o /dev/null -w 'evil-host -> %{http_code}\n' -H 'Host: evil.example.com' http://127.0.0.1/auth/login
curl -s -o /dev/null -w '/users.json -> %{http_code}\n' -H 'Host: 127.0.0.1' http://127.0.0.1/users.json

/auth/setup returns a 307 redirect to /auth/login (self-registration guarded), port 3000 listens on 127.0.0.1 only, an unknown Host header gets a bare 404, and the config path returns 404.

Secure by default: /auth/setup redirects to the login page, the app port is loopback only and refused on the routable address, and nginx returns 404 for unknown hosts and config paths

Step 8 - Sign in to Jotty

In your browser, go to http://<vm-public-ip>/. You are taken straight to the Welcome back sign-in screen (not a setup form — the admin is already seeded). Sign in as admin with the password from Step 5.

The Jotty sign-in page in the browser

Step 9 - Create your first note

Once signed in, click New Note, give it a title and click Create. Jotty opens the Markdown editor where you can write the note body; your note appears in the notes list immediately and opens with its content rendered.

The Jotty notes view listing a note created after sign-in

The Jotty Markdown editor showing the note title and its rendered body text

Jotty also gives you task checklists and kanban boards alongside notes, so you can track to-dos in the same private workspace.

The Jotty Checklists view, signed in as the administrator

Add more users from Settings once signed in as the administrator — there is no open self-service registration, so new accounts are created only by an administrator.

Maintenance

Secure with HTTPS. For production, put your own domain in front of the VM and terminate TLS. Point a DNS record at the VM's public IP, then install a certificate (for example with Certbot) and add a TLS server block to nginx that proxies to http://127.0.0.1:3000, mirroring the shipped port-80 vhost. The nginx server_name allowlist already includes your VM's addresses; add your domain name to the server_name line so it is served.

Back up your notes. Everything Jotty stores is under /var/lib/jotty/data as plain Markdown and JSON. Snapshot the data disk from the Azure portal, or copy the directory:

sudo tar czf /var/tmp/jotty-data-backup.tgz -C /var/lib/jotty data

Grow the data disk. The notes store grows on the dedicated Azure data disk. Expand the disk in the Azure portal, then grow the filesystem online with sudo growpart + sudo resize2fs on the data-disk partition.

Update Jotty. New releases ship as new image tags. Pull the new tag, update the jotty.service unit to reference it, and restart:

sudo docker pull ghcr.io/fccview/jotty:<new-version>
sudo sed -i 's#ghcr.io/fccview/jotty:1.26.0#ghcr.io/fccview/jotty:<new-version>#' /etc/systemd/system/jotty.service
sudo systemctl daemon-reload && sudo systemctl restart jotty

Review the upstream release notes before upgrading, as some releases run a data migration — back up first.

Support

This image is maintained by cloudimg with 24/7 support. If you need help deploying or operating Jotty on Azure, contact cloudimg support through the Azure Marketplace listing.

Jotty is an open source project (AGPL-3.0). This image packages unmodified upstream Jotty with cloudimg configuration and automation, and is not affiliated with or endorsed by the Jotty project.