Deployment guide

DumbAssets

Overview

DumbAssets is a deliberately simple, self-hosted asset tracker. It catalogues the physical things you own, such as electronics, appliances, tools and equipment, with their manufacturer, model and serial number, purchase date and price, warranties, maintenance reminders, photos and receipts, all from a small web dashboard with search and simple charts.

This SecureAnyCloud image runs DumbAssets 1.0.11 on Ubuntu 24.04 LTS as a complete, running server. Data stays in plain files on the VM with no external database, so your catalogue is a set of readable JSON files plus an uploads folder that you fully control.

DumbAssets is protected by a single site PIN, and a blank PIN disables authentication entirely. For that reason the image never ships a default PIN. Each VM generates its own random PIN on first boot, and the service refuses to start until a real PIN and a unique session secret are in place.

What you get:

  • DumbAssets 1.0.11 served behind nginx on port 80, with the Node app bound to loopback only
  • Node.js 22 LTS from NodeSource, run by an unprivileged dumbassets system account under systemd
  • The Node process bound to 127.0.0.1:3000 and never directly reachable, with nginx as the only front door
  • A PIN unique to your VM, generated on first boot; no default or blank PIN ships in the image
  • A session secret unique to your VM, replacing the insecure upstream default
  • File-based storage in a persistent data directory at /var/lib/dumbassets/data
  • One clearly labelled demo asset, so the dashboard shows real content the first time you sign in
  • dumbassets.service and nginx.service as enabled, active systemd units
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting size.

Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the web interface. DumbAssets serves plain HTTP here. For internet-facing use, terminate TLS in front of it with your own domain, using a reverse proxy or the Azure Application Gateway, so the PIN and your data are never sent in the clear.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for DumbAssets by SecureAnyCloud, and select Create.

On the Basics tab, 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).

Select Review + create, then Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:dumbassets:default:latest
az vm create \
  --resource-group <your-rg> \
  --name dumbassets \
  --image sac1647283583153:dumbassets:default:latest \
  --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 dumbassets --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemd runs DumbAssets as the unprivileged dumbassets user. nginx is the only front door: it listens on :80 and reverse-proxies to the Node process on 127.0.0.1:3000. Confirm that the services are active and that the application port is loopback-only:

systemctl is-active dumbassets nginx dumbassets-firstboot
sudo ss -tlnp | grep -E ':80 |:3000 '

Expected output: all three services report active, nginx holds 0.0.0.0:80, and the Node application is bound only to 127.0.0.1:3000.

Step 5 - Retrieve your PIN

On the first boot of every VM, dumbassets-firstboot.service generates a PIN unique to that VM and a unique session secret. It writes the PIN and the sign-in URL to a root-only file. Read it with:

sudo cat /root/dumbassets-credentials.txt

There is no default or shared PIN in the image. DumbAssets treats an empty PIN as "authentication disabled". The shipped image therefore carries an empty PIN, and the service is configured to refuse to start until first boot has written a real one. Until then, the captured image cannot be signed in to at all. Store the PIN somewhere safe.

Step 6 - Verify the app is closed to unauthenticated access

The whole application sits behind the PIN. Verify it from the VM: an unauthenticated API request is refused, the root page redirects to the login screen, a wrong PIN is rejected, and only this VM's PIN is accepted. The commands read the PIN from the root-only credentials file, so no secret is typed on the command line:

PIN=$(sudo grep '^DUMBASSETS_PIN=' /root/dumbassets-credentials.txt | cut -d= -f2-)
curl -s http://127.0.0.1/pin-length; echo
curl -s -o /dev/null -w 'unauthenticated /api/assets -> %{http_code}\n' http://127.0.0.1/api/assets
curl -s -o /dev/null -w 'unauthenticated / -> %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'wrong PIN -> %{http_code}\n' \
  -X POST -H 'Content-Type: application/json' --data '{"pin":"00000000"}' http://127.0.0.1/verify-pin
curl -s -o /dev/null -w 'this VM PIN -> %{http_code}\n' \
  -c /tmp/da.jar -X POST -H 'Content-Type: application/json' --data "{\"pin\":\"$PIN\"}" http://127.0.0.1/verify-pin

Expected output:

  • /pin-length reports a non-zero length, which means authentication is on
  • The unauthenticated API returns 401
  • The root page returns 302, a redirect to the login screen
  • A wrong PIN returns 401
  • This VM's PIN returns 302 and sets a session

Step 7 - Inspect your data files

DumbAssets stores everything in a persistent directory at /var/lib/dumbassets/data. Assets.json and SubAssets.json hold the catalogue, and Images, Receipts and Manuals hold your uploads. The image ships one clearly labelled demo asset, so the dashboard is not empty on your first sign-in:

sudo ls -l /var/lib/dumbassets/data
sudo python3 -c 'import json; d=json.load(open("/var/lib/dumbassets/data/Assets.json")); print(len(d), "asset(s):", [a["name"] for a in d])'

Expected output: the data directory listing, and one asset named Example Laptop (demo - safe to delete).

Step 8 - Check the service hardening

The Node process runs as the unprivileged dumbassets user under systemd with ProtectSystem=strict. It binds the loopback interface only, so nginx is the sole way in. It also refuses to start unless a real PIN is present, which stops the app from ever coming up open:

systemctl show dumbassets.service -p User -p ProtectSystem -p Restart
systemctl is-enabled dumbassets dumbassets-firstboot nginx
sudo ss -tlnp | grep 3000

Expected output: the service runs as dumbassets with ProtectSystem=strict, all three units are enabled, and the application listens only on 127.0.0.1:3000.

Step 9 - Sign in to the dashboard

Browse to http://<vm-public-ip>/. DumbAssets sends you to the PIN entry screen.

Enter the PIN from Step 5, one digit per box. The form submits itself when you enter the last digit. Until you enter the correct PIN, the app shows nothing.

For production, put the app behind your own hostname with TLS termination and restrict :80 to your management network in the NSG. This keeps the PIN and your data off plain HTTP.

Step 10 - Explore the asset dashboard

After you sign in, you land on the dashboard. The asset list is on the left, with a search box and an Add Asset button. An overview on the right shows warranty status and a chart of warranties expiring over time.

The demo asset appears in the list, so you can see the layout straight away.

Step 11 - Inspect an asset

Select an asset to open its detail view. It shows the manufacturer, model and serial number, purchase date and price, quantity, notes, and warranty and maintenance information.

From here you can edit the asset, attach documents, photos and receipts, and add components (sub assets) that belong to it.

Step 12 - Add your own assets

Open the demo asset and use the delete icon to remove it. Then select Add Asset to start cataloguing your own.

Give each asset a name, then fill in as much as you want: manufacturer, model and serial number, purchase date and price, tags, maintenance events, and uploaded photos, receipts and manuals. Add a warranty with an expiry date so DumbAssets can remind you before it lapses. Select Import Assets to bring in an existing inventory in bulk.

To start completely clean instead, stop the service, clear the data directory and restart:

sudo systemctl stop dumbassets
sudo rm -rf /var/lib/dumbassets/data/*
sudo systemctl start dumbassets

Maintenance

  • Configuration: the runtime environment lives in /etc/dumbassets/dumbassets.env (owned root:dumbassets, mode 0640). It holds the PIN, the session secret, the port and the base URL. Change a value there, then run sudo systemctl restart dumbassets.
  • Change the PIN: edit DUMBASSETS_PIN in /etc/dumbassets/dumbassets.env (4 or more digits) and restart the service.
  • Your data: everything is under /var/lib/dumbassets/data. Back up that directory to keep your catalogue, uploads and configuration.
  • Logs: the server logs to the journal. Run sudo journalctl -u dumbassets -f to follow it.
  • Security updates: unattended security upgrades are enabled, so the OS keeps itself patched. Reboot when a new kernel is installed.
  • TLS: for production, front port 80 with your own domain and a TLS-terminating reverse proxy or Azure Application Gateway.
  • Rotate the PIN and session secret: remove /var/lib/sac/data/dumbassets-firstboot.done and /var/lib/dumbassets/.bootstrap-ready, then reboot. First boot regenerates both.

Support

SecureAnyCloud provides 24/7/365 expert technical support for this image. Contact sales@secureanycloud.com.

DumbAssets is licensed under the GNU General Public License v3.0. This image is provided by SecureAnyCloud, and additional charges apply for build, maintenance and 24/7 support.

Deploy on Azure

Launch DumbAssets on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure