HortusFox on Ubuntu 24.04 on Azure User Guide
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.serviceandmariadb.serviceas systemd units, enabled and active- 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 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 + create → Create.
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.

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.

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

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.

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.

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.

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.

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.