Applications Azure

Tracktor on Ubuntu 24.04 on Azure User Guide

| Product: Tracktor on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Tracktor on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Tracktor is an open source, self-hosted vehicle and fleet management app. For every vehicle you own or run it keeps a full fuel log with mileage and cost, a service and maintenance history, and a store of compliance documents such as insurance and registration, each with a renewal reminder so nothing lapses. A dashboard turns that history into running totals and trends for spend, fuel consumption and upcoming renewals, so you can see the true cost of keeping each vehicle on the road.

The cloudimg image ships the free and open source, MIT licensed Tracktor application, built unmodified from the pinned upstream release and run natively on Node 22 with an embedded SQLite database, so the appliance boots and works standalone with no external database or service. Upstream Tracktor creates the first account through an open registration form, and leaves that registration endpoint reachable even after an owner exists, 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 encryption secret and claims the owner account itself with a per-VM random password, written to a root-only file, and public registration is then permanently disabled at the reverse proxy. Backed by 24/7 cloudimg support.

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

The tracktor-firstboot, tracktor, tracktor-postboot and nginx services all reporting active, with the Tracktor Node app published only to 127.0.0.1:3000 and host nginx the single public listener on port 80

What is included:

  • Tracktor v2.0.1 (the MIT licensed SvelteKit vehicle and fleet manager), built from the pinned upstream source
  • Node 22 from the official NodeSource repository, running the app as an unprivileged tracktor service account
  • An embedded SQLite database at /var/lib/tracktor/tracktor.db, created and migrated automatically on first boot, with no separate database service or host port
  • Host nginx as the single public listener on port 80, reverse proxying to the app on loopback, with header buffers sized for authenticated responses
  • tracktor-firstboot.service, tracktor.service and tracktor-postboot.service as systemd units, enabled and active on boot
  • A per-VM encryption secret and a per-VM owner account password, generated on first boot and never baked into the image
  • The owner account claimed during bootstrap while port 80 is still closed, so a passer by can never claim the instance
  • Public registration permanently disabled: /register and /api/auth/register return 404 from the public interface
  • No default login, no shipped secret, 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 Tracktor listing on Azure Marketplace

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a comfortable fit for a single Node process and an embedded SQLite database; the application idles at well under 100 MB of memory, so this size suits a person, a household or a small fleet. For 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 Tracktor 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="tracktor-prod"; LOCATION="eastus"; VM_NAME="tracktor-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/tracktor/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name tracktor-vnet --address-prefix 10.100.0.0/16 --subnet-name tracktor-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name tracktor-nsg
az network nsg rule create -g "$RG" --nsg-name tracktor-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 tracktor-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 tracktor-vnet --subnet tracktor-subnet --nsg tracktor-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, Tracktor generates its own per-instance secrets and claims its own owner 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/tracktor-credentials.txt

The per instance credentials file, showing the Tracktor owner username and a password generated randomly for this VM (masked here) and the resolved web URL, all unique to this instance

The file contains everything unique to this instance:

  • TRACKTOR_USERNAME / TRACKTOR_PASSWORD — the owner login you use in the web UI. The owner has full access to the fleet.
  • TRACKTOR_URL — the web address of this instance, resolved from its public IP on first boot.

Confirm the services are healthy:

sudo systemctl is-active tracktor-firstboot tracktor tracktor-postboot nginx
active
active
active
active

The application answers a health check on the loopback port, which is also proof the SQLite schema migrated on start up:

curl -s http://127.0.0.1/api/health
{"success":true,"data":{"timestamp":"2026-08-08T00:00:00.000Z"},"message":"Tracktor API is working"}

Step 4: The security model

Upstream Tracktor creates the first account through an open /register form. The web page closes once an owner exists, but the underlying registration API stays reachable, so on a raw deployment a passer by could still create an account. On a VM with a public IP that is a real risk, so cloudimg removes it in two independent ways.

First, tracktor-postboot.service claims the owner account itself, over the loopback port, with a password generated for this VM, before the public listener ever comes up. Second, host nginx — the only public listener — permanently returns 404 for both /register and /api/auth/register, so public registration is structurally impossible, and nginx does not start at all until the owner has been claimed: it is gated on a bootstrap-ready marker that post boot creates only after the owner exists. Port 80 is therefore closed for the whole bootstrap window.

The encryption secret (APP_SECRET, used by Tracktor to encrypt any notification credentials you add) is generated on first boot too, and a start up guard refuses to launch the application at all if that secret is empty, too short or a known default, so the upstream empty default never runs on your VM.

The security posture: the Tracktor app listening only on 127.0.0.1:3000 and nginx the single 0.0.0.0:80 public listener, a public registration POST refused 404, an anonymous vehicles API refused 401, and exactly one owner account present

The app is on loopback only and nginx is the single public door on port 80:

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

Public registration is closed, and vehicle data is not readable anonymously:

curl -s -o /dev/null -w 'public POST /api/auth/register -> %{http_code}\n' -X POST http://127.0.0.1/api/auth/register -H 'Content-Type: application/json' --data '{"username":"passerby","password":"nope123"}'
curl -s -o /dev/null -w 'anonymous GET /api/vehicles  -> %{http_code}\n' http://127.0.0.1/api/vehicles
public POST /api/auth/register -> 404
anonymous GET /api/vehicles  -> 401

Exactly one account exists on a fresh instance, and it is the owner you were given:

sudo sqlite3 /var/lib/tracktor/tracktor.db 'SELECT username FROM users;'
admin

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

The image ships a prover that exercises the whole security model and a real authenticated action through the public front door: it confirms the app answers, that public registration is refused, that anonymous callers are rejected, that a wrong password is rejected, and that the per-instance password logs in and then creates and reads back a vehicle and a fuel log.

sudo /usr/local/sbin/tracktor-roundtrip.sh
OK round-trip: url=http://<vm-ip>/ user=admin; health 200; anon vehicles 401; public register blocked 404; wrong password 401; login 200; created + read back vehicle and a fuel log

The Tracktor round-trip prover reporting OK: health returned 200, anonymous vehicles was refused 401, public registration was blocked 404, a wrong password was rejected 401, the per-VM owner logged in 200, and a vehicle and a fuel log were created and read back

Step 6: Sign in to the web app

Open http://<vm-ip>/ in your browser and sign in with the TRACKTOR_USERNAME and TRACKTOR_PASSWORD from the credentials file.

The Tracktor login page asking for a username and password, for the owner account created on this VM during first boot

Once signed in, the dashboard is the home view. It summarises your fleet: the vehicles you have added, recent activity, upcoming reminders and the running costs Tracktor derives from your fuel and service history.

The signed in Tracktor dashboard after first login, showing the fleet summary with a vehicle present, its recorded costs and the navigation to fuel, maintenance and compliance records

Managing vehicles and logging fuel

Choose Add Vehicle from the dashboard or the Garage, and fill in the make, model, year and registration. The Garage shows every vehicle you manage, each with its registration, fuel type and current odometer, and its own pages for fuel, maintenance, documents and reminders.

The Tracktor Garage listing two managed vehicles, a Volkswagen Golf and a Honda CB500X, each showing its registration, fuel type, year and current odometer reading

Open Fuel Logs to record a fill up with its date, odometer reading, quantity and cost. As you add entries Tracktor tracks consumption and spend over time, shown here as the fuel used, total spent and average mileage across the fleet with a per entry table, while each vehicle also holds its service history and its insurance and registration documents with renewal reminders.

The Tracktor Fuel Tracking view showing the fuel used, total spent and average mileage summary tiles, a fuel consumption trend chart and a table of the logged fuel entries with odometer, quantity and cost

Adding other people

This image is a single owner appliance: public self registration is disabled, so nobody can create an account on your instance from the web. The owner account manages the whole fleet. You can change the owner username or password at any time from the profile menu in the top right of the web UI.

Using your own domain

The instance works whether you reach it by its public IP or by a DNS name that points at it: the reverse proxy forwards the browser's Host header, so no reconfiguration is needed to use a hostname. If you terminate TLS on a reverse proxy in front of the VM, set HTTP_MODE=https in /etc/tracktor/tracktor.env so the session cookie is marked secure, then restart the service:

sudo systemctl restart tracktor

Managing the service

# view recent application logs
sudo journalctl -u tracktor.service --no-pager | tail -50
# restart the app
sudo systemctl restart tracktor

The MIT licence text and a note recording the exact upstream release shipped here are on the VM at /usr/share/doc/tracktor/.

Support

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