Applications Azure

HortusFox on Ubuntu 24.04 on Azure User Guide

| Product: HortusFox on Ubuntu 24.04 LTS on Azure

Overview

HortusFox is a free, open source self hosted collaborative plant and garden management system built on PHP and the Asatru framework. It organises plants by location and gives you a plant inventory, watering and care task scheduling, a photo gallery, a journal and history view, a calendar, inventory tracking and a collaborative group chat, all behind an admin dashboard and a REST API. The cloudimg image delivers HortusFox fully installed and configured on Ubuntu 24.04 — a PHP 8.3 application served by nginx over HTTPS with php-fpm, backed by MariaDB 11.4 LTS bound to the loopback interface. The schema is migrated, default plant attributes and calendar classes are seeded, an initial workspace and admin account are created, and one starter location is added, so you land directly on a working sign-in with nothing to install. Backed by 24/7 cloudimg support.

What is included:

  • HortusFox 5.8 (MIT licensed), served from /var/www/hortusfox/public
  • nginx (TLS on :443, with :80 redirected to HTTPS) + PHP 8.3 (php8.3-fpm with OPcache) + MariaDB 11.4 LTS bound to 127.0.0.1
  • A per-VM self-signed TLS certificate generated on first boot, so the interface loads over a secure context
  • Per-VM administrator password, MariaDB password and cronjob token, all generated at first boot and written to a root-only file — no default or blank login ships in the image
  • nginx.service, php8.3-fpm.service and mariadb.service as systemd units, enabled and active
  • 24/7 cloudimg support

HortusFox sign-in page

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 good starting point; scale up for larger collections or more collaborators. NSG inbound: allow 22/tcp from your management network and 443/tcp (HTTPS) plus 80/tcp (which redirects to HTTPS) from your users.

Step 1 — Deploy from the Azure Marketplace

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

Step 2 — Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name hortusfox \
  --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 hortusfox --port 443 --priority 1010

Step 3 — Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 — Confirm the services are running

The services that back HortusFox should all report active, and the interface answers HTTP 200 over HTTPS (the plain HTTP port redirects to it). MariaDB listens only on the loopback interface (127.0.0.1:3306), never on the public network:

systemctl is-active nginx php8.3-fpm mariadb
curl -ks -o /dev/null -w 'app https    -> %{http_code}\n' https://127.0.0.1/auth
curl -s  -o /dev/null -w 'http redirect -> %{http_code}\n' http://127.0.0.1/
ss -tlnp | grep -E ':443 |:3306 ' | sed 's/  */ /g'

Expected: three lines of active, then app https -> 200 and http redirect -> 301, and MariaDB bound to 127.0.0.1:3306.

Service status and listening ports, with MariaDB bound to loopback only

Step 5 — Retrieve your administrator credentials

On the first boot of every VM, a one-shot service (hortusfox-firstboot.service) generates secrets that are unique to that VM: a fresh administrator password, a fresh MariaDB password and a fresh cronjob token. It also generates a per-VM self-signed TLS certificate. No shared or default credentials ship in the image.

sudo cat /root/hortusfox-credentials.txt

The file (mode 0600, root only) contains the administrator email (hortusfox.admin.user, the fixed value admin@hortusfox.local), the administrator password (hortusfox.admin.pass), the sign-in URL, and the database credentials. HortusFox signs in by email.

Per-VM credentials with the secrets masked

You can prove the login round-trip from the VM's own shell — this reads the per-VM credentials, posts a real admin sign-in (a signed-in session reaches the dashboard, which carries a Logout control), and confirms that a wrong password is rejected and redirected back to the sign-in page:

ADMIN_USER=$(sudo grep '^hortusfox.admin.user=' /root/hortusfox-credentials.txt | cut -d= -f2-)
ADMIN_PASS=$(sudo grep '^hortusfox.admin.pass=' /root/hortusfox-credentials.txt | cut -d= -f2-)
CJ=$(mktemp)
curl -ks -c "$CJ" https://127.0.0.1/auth >/dev/null
curl -ks -b "$CJ" -c "$CJ" -o /dev/null \
  --data-urlencode "email=$ADMIN_USER" --data-urlencode "password=$ADMIN_PASS" https://127.0.0.1/login
curl -ks -b "$CJ" -o /tmp/hf-check.html -w 'correct password -> HTTP %{http_code}\n' https://127.0.0.1/
grep -qi logout /tmp/hf-check.html && echo 'signed in (Logout present)' || echo 'not signed in'
rm -f "$CJ" /tmp/hf-check.html

Administrator account, credentials file permissions and the login round-trip proof

Step 6 — Sign in to HortusFox

Browse to https://<vm-public-ip>/auth and sign in with the administrator email and password from the credentials file. Because the image ships a per-VM self-signed certificate, your browser shows a one-time certificate warning on first visit — click through it, or install your own domain certificate into /etc/nginx/ssl/.

After signing in you land on the dashboard, which greets you and summarises your plants, locations, tasks and users at a glance.

HortusFox dashboard after signing in

Step 7 — Add locations and plants

HortusFox organises everything by location (a greenhouse, a room, a bed, a windowsill). The image ships with one starter location named Greenhouse so you can add plants immediately; create more from Admin → Locations. Choose Add Plant from the top bar to register a plant against a location, then attach photos, notes, custom attributes and a watering schedule. The Tasks view manages the recurring care work — watering, feeding, repotting — with To-Do and Done lists you can filter.

The plant care Tasks view

Step 8 — Plan care with the calendar

The Calendar view records important dates and reminders across a date range you choose, so seasonal care, fertilising windows and repotting dates are all in one place. Other built-in modules include an Inventory for pots, soil and supplies, a Search across your collection, a plant History timeline and a collaborative Chat for teams that share a workspace.

The HortusFox calendar view

Step 9 — Confirm the stack

php -v | head -1
mariadb --version
grep -E '^APP_DEBUG|^DB_HOST|^DB_DATABASE' /var/www/hortusfox/.env

Expected: PHP 8.3.x, MariaDB 11.4.x, and the application configured with APP_DEBUG=false (production posture) against the loopback database hortusfox.

PHP and MariaDB versions, endpoint health and the production configuration

First-boot service and security model

A one-shot hortusfox-firstboot.service runs After=mariadb.service and Before=nginx.service, so the per-VM secrets and TLS certificate are in place before the first page is ever served. It writes the credentials file at mode 0600 (root only) and drops a sentinel so it runs exactly once.

systemctl status hortusfox-firstboot.service --no-pager | head -6
sudo stat -c '%a %U:%G %n' /root/hortusfox-credentials.txt

Administration

Day to day administration is done from the web Admin dashboard (the gear icon in the top bar): manage users, locations, workspace settings, themes, backups and the environment. HortusFox also ships a command line tool (php asatru <command>) intended for maintenance and deployment; it is only enabled when APP_DEBUG=true, which this image deliberately sets to false for a production posture, so use the Admin dashboard for routine tasks.

Users can be invited from Admin → Users; each can sign in by email, change their password from their profile, and reset a forgotten password by email once SMTP is configured under Admin → Settings.

Enabling HTTPS with your own domain

The image already serves HTTPS with a per-VM self-signed certificate. For production, point a real domain at the VM's public IP, open 443/tcp in the NSG, then replace the self-signed certificate with a trusted one using Let's Encrypt (replace the domain):

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com

HortusFox derives its links from the host you browse to, so once you reach the VM by your domain name over HTTPS the application uses it automatically — no configuration change is needed.

Backup and maintenance

The database and the application tree (including uploaded plant photos under /var/www/hortusfox/public/img) live on the VM's disk — snapshot the disk in Azure for a point-in-time backup, or dump the database with (the database password is in the credentials file):

sudo mariadb-dump hortusfox > hortusfox-backup.sql

Keep the OS patched with sudo apt update && sudo apt upgrade (unattended security upgrades are enabled by default). The stack restarts cleanly with sudo systemctl restart nginx php8.3-fpm mariadb.

Support

This image is backed by 24/7 cloudimg support. Contact us by email and chat for help with HortusFox deployment, upgrades, adding locations and plants, task and calendar configuration, SMTP and email reminders, the REST API, performance tuning and database administration.

All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.