Deployment guide

HortusFox

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. It 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 of it sits behind an admin dashboard and a REST API.

The SecureAnyCloud image delivers HortusFox fully installed and configured on Ubuntu 24.04. It is 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, and default plant attributes and calendar classes are seeded. An initial workspace and admin account are created, and one starter location is added. You land directly on a working sign-in with nothing to install.

What you get:

  • 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) and 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
  • A 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 SecureAnyCloud support

Prerequisites

You need:

  • An active Azure subscription
  • An SSH key pair
  • A VNet and subnet in the target region
  • Standard_B2s (2 vCPU / 4 GiB RAM) as a good starting size. Scale up for larger collections or more collaborators.
  • NSG inbound rules that allow 22/tcp from your management network, plus 443/tcp (HTTPS) and 80/tcp (which redirects to HTTPS) from your users

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal and choose Create a resource. Search the Marketplace for HortusFox 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 HTTPS (443).

Click 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:hortusfox-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name hortusfox \
  --image sac1647283583153:hortusfox-ubuntu-24-04: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 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. The interface answers HTTP 200 over HTTPS, and the plain HTTP port redirects to it.

MariaDB listens only on the loopback interface (127.0.0.1:3306), never on the public network. Run the check:

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'

Expect three lines of active, then app https -> 200 and http redirect -> 301. MariaDB is 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. These are a fresh administrator password, a fresh MariaDB password and a fresh cronjob token. The service also generates a per-VM self-signed TLS certificate. No shared or default credentials ship in the image.

Read the credentials file:

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
  • The database credentials

HortusFox signs in by email.

You can prove the login round trip from the VM's own shell. The script reads the per-VM credentials and posts a real admin sign-in. A signed-in session reaches the dashboard, which carries a Logout control. The script also 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.

The image ships a per-VM self-signed certificate, so 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 you sign in, the dashboard greets you and summarises your plants, locations, tasks and users at a glance.

Step 7 - Add locations and plants

HortusFox organises everything by location, such as a greenhouse, a room, a bed or a windowsill. The image ships with one starter location named Greenhouse, so you can add plants immediately. Create more locations 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 recurring care work such as watering, feeding and repotting. It has To-Do and Done lists that you can filter.

Step 8 - Plan care with the calendar

The Calendar view records important dates and reminders across a date range that you choose. Seasonal care, fertilising windows and repotting dates all sit in one place.

Other built-in modules are:

  • Inventory for pots, soil and supplies
  • Search across your collection
  • History, a timeline for each plant
  • Chat, for teams that share a workspace

Step 9 - Confirm the stack

Check the PHP, MariaDB and application settings:

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

Expect PHP 8.3.x and MariaDB 11.4.x. The application is 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. The per-VM secrets and TLS certificate are therefore in place before the first page is served.

The service writes the credentials file at mode 0600 (root only) and drops a sentinel so that it runs exactly once. Inspect the unit:

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

Administration

Do day-to-day administration from the web Admin dashboard (the gear icon in the top bar). You can manage users, locations, workspace settings, themes, backups and the environment.

HortusFox also ships a command-line tool (php asatru <command>) for maintenance and deployment. It is enabled only when APP_DEBUG=true, which this image deliberately sets to false for a production posture. Use the Admin dashboard for routine tasks.

Invite users from Admin > Users. Each user can sign in by email and change their password from their profile. Once SMTP is configured under Admin > Settings, users can also reset a forgotten password by email.

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 and open 443/tcp in the NSG. Then replace the self-signed certificate with a trusted one from Let's Encrypt. Replace the example domain with your own:

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 that you browse to. 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 live on the VM's disk. The tree includes uploaded plant photos under /var/www/hortusfox/public/img. Snapshot the disk in Azure for a point-in-time backup.

Alternatively, dump the database. 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

SecureAnyCloud provides 24/7 support for this image. Contact us by email or 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.

Deploy on Azure

Launch HortusFox 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