Artificial Intelligence (AI) Azure

Gorse Recommender Engine on Ubuntu 24.04 on Azure User Guide

| Product: Gorse on Ubuntu 24.04 LTS on Azure

Overview

Gorse is an open source recommender system engine written in Go. You feed it users, items and feedback such as clicks, stars or purchases through a REST API, and it returns personalized recommendations for each user, along with item to item and user to user neighbours, session based recommendations and popular or latest non personalized lists as a fallback. A built in web dashboard lets you inspect your data, review recommendations and watch the background training tasks.

The cloudimg image installs the official all in one gorse-in-one engine at /usr/local/bin/gorse-in-one, running as the gorse service bound to loopback 127.0.0.1:8088, behind nginx on port 80. The engine serves both the RESTful recommendation API (under /api/) and the web dashboard on the same port, backed by an embedded SQLite data and cache store on the OS disk, so there is no external database or cache to provision. nginx is ready for your TLS certificate.

Secure by default, no default login: Gorse ships with an empty API key and empty dashboard credentials, which leaves both the REST API and the dashboard open. This image never ships that. A gorse-firstboot.service oneshot generates a unique API key, dashboard password and admin key on each VM's first boot, writes them to a root only file, and marks the engine ready to start only once those secrets are in place, so every API request requires your key and the dashboard requires your login from the very first request. No two VMs share a secret and none is baked usable into the image.

Always current: on first boot the appliance downloads the newest Gorse release (falling back to the baked version if the network is unavailable), so every launch runs current software rather than the version frozen at build time.

What is included:

  • Gorse (verified at 0.5.11) as the official all in one gorse-in-one engine
  • gorse.service bound to loopback 127.0.0.1:8088, serving the REST API and dashboard
  • An embedded SQLite data and cache store on the OS disk, no external database or cache
  • nginx reverse proxy on port 80, ready for TLS
  • gorse-firstboot.service for the first boot secrets, binary refresh and info note
  • A unique per VM API key, dashboard password and admin key generated on first boot, in a root only 0600 file
  • Ubuntu 24.04 LTS base, fully patched
  • 24/7 cloudimg support, 24h response SLA

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet with a subnet. Gorse is a lightweight CPU only engine with no GPU requirement. Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and small catalogues, or a Standard_D2s_v5 or larger for production workloads with bigger datasets. Gorse keeps its store on the OS disk, so expand the disk before loading large catalogues.

Step 1: Deploy from the Azure Portal

Search the Marketplace for Gorse on Ubuntu 24.04, choose your VM size, and attach an NSG that allows TCP 22 (SSH) from your management network and TCP 80 / 443 (the API and dashboard) from the networks and applications that need to reach it. Front port 80 with TLS in production (see the HTTPS section below).

Step 2: Deploy from the Azure CLI

RG="gorse-prod"; LOCATION="eastus"; VM_NAME="gorse-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/gorse-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name gorse-vnet --address-prefix 10.90.0.0/16 --subnet-name gorse-subnet --subnet-prefix 10.90.1.0/24
az network nsg create -g "$RG" --name gorse-nsg
az network nsg rule create -g "$RG" --nsg-name gorse-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 gorse-nsg --name allow-web --priority 110 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 80 443 --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 gorse-vnet --subnet gorse-subnet --nsg gorse-nsg --public-ip-sku Standard

Step 3: Connect via SSH

ssh azureuser@<vm-ip>

Step 4: Verify the services are running

Gorse listens on loopback 127.0.0.1:8088 and nginx fronts it on port 80. The health endpoint is public; every other API endpoint requires your key.

sudo systemctl start gorse nginx 2>/dev/null || true
sudo systemctl is-active gorse nginx
ss -tln | grep -E ':80 |127.0.0.1:8088'
echo "health -> HTTP $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/api/health/ready)"

You should see both services active, the listening sockets, and HTTP 200 from the health endpoint.

Terminal showing the gorse and nginx services active, gorse bound to loopback 8088 with nginx fronting port 80, and the health endpoint returning HTTP 200

Step 5: Read your per VM secrets

Your API key, dashboard password and admin key were generated on this VM's first boot and stored in a root only file. Read them and keep them secret. Confirm that the REST API rejects an unauthenticated request and accepts your key.

sudo ls -l /root/gorse-info.txt
echo "no key   -> HTTP $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/api/users)"
KEY=$(sudo grep '^GORSE_API_KEY=' /root/gorse-info.txt | cut -d= -f2-)
echo "with key -> HTTP $(curl -s -o /dev/null -w '%{http_code}' -H "X-API-Key: $KEY" http://127.0.0.1/api/users)"

The info note is owned root:root with mode 0600. An unauthenticated call to /api/users returns 401, and the same call with your X-API-Key header returns 200, because the engine enforces the key on every /api/* endpoint except the public health checks.

Terminal showing the root only 0600 secrets file, the public health endpoint returning 200, and the REST API rejecting a request without a key with HTTP 401 then accepting the per VM key with HTTP 200

Step 6: Feed data and get recommendations via the REST API

Load your API key into a shell variable, then send Gorse a few users, items and feedback events. Items carry categories and a timestamp; feedback records that a user starred an item. Gorse serves the latest items straight from the store, and returns per user recommendations (falling back to the latest items until the collaborative filtering model has trained on your feedback).

KEY=$(sudo grep '^GORSE_API_KEY=' /root/gorse-info.txt | cut -d= -f2-)
H1="X-API-Key: $KEY"; H2="Content-Type: application/json"; TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
curl -s -X POST http://127.0.0.1/api/users -H "$H1" -H "$H2" \
  --data '[{"UserId":"alice","Labels":{}},{"UserId":"bob","Labels":{}}]' >/dev/null
curl -s -X POST http://127.0.0.1/api/items -H "$H1" -H "$H2" --data "[
  {\"ItemId\":\"movie_inception\",\"Categories\":[\"scifi\"],\"Timestamp\":\"$TS\",\"Labels\":{}},
  {\"ItemId\":\"movie_matrix\",\"Categories\":[\"scifi\"],\"Timestamp\":\"$TS\",\"Labels\":{}},
  {\"ItemId\":\"movie_coco\",\"Categories\":[\"animation\"],\"Timestamp\":\"$TS\",\"Labels\":{}}]" >/dev/null
curl -s -X POST http://127.0.0.1/api/feedback -H "$H1" -H "$H2" --data "[
  {\"FeedbackType\":\"star\",\"UserId\":\"alice\",\"ItemId\":\"movie_inception\",\"Timestamp\":\"$TS\"},
  {\"FeedbackType\":\"star\",\"UserId\":\"alice\",\"ItemId\":\"movie_matrix\",\"Timestamp\":\"$TS\"},
  {\"FeedbackType\":\"star\",\"UserId\":\"bob\",\"ItemId\":\"movie_inception\",\"Timestamp\":\"$TS\"}]" >/dev/null
echo "latest items:        $(curl -s -H "$H1" 'http://127.0.0.1/api/latest?n=5' | jq -r '[.[].Id] | join(", ")')"
echo "recommend for alice: $(curl -s -H "$H1" 'http://127.0.0.1/api/recommend/alice?n=5' | jq -r 'join(", ")')"

GET /api/latest returns the items you just inserted, and GET /api/recommend/alice returns a non empty list of recommended item IDs. As more feedback accumulates, Gorse's background tasks train the collaborative filtering model and the personalized recommendations become tailored to each user's history.

Terminal showing users, items and feedback fed to Gorse over the REST API, the latest items returned from the store, and a non empty personalized recommendation list for a user

Step 7: Open the web dashboard

Gorse ships a web dashboard for inspecting your data, recommendations and background tasks. It is served on the same port as the API and is protected by the per VM dashboard login. Confirm it is reachable and requires authentication.

echo "login page -> HTTP $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/login)"
echo "dashboard  -> HTTP $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/)"

The login page returns 200, and a request to the dashboard root returns 302, redirecting an unauthenticated visitor to the login form. In a browser, open http://<vm-ip>/ and sign in as admin with the GORSE_DASHBOARD_PASSWORD value from /root/gorse-info.txt.

The Gorse dashboard sign in page requiring a username and password

Once signed in, the Overview page summarises how many users, items and feedback events the recommender knows about, with recommendation performance over time.

The Gorse dashboard Overview page showing the user, item and feedback totals for the recommender

The Items page lists the catalogue the recommender serves, with each item's categories, timestamp and labels.

The Gorse dashboard Items page listing the item catalogue with categories and timestamps

The Users page lists the users known to the recommender, and each row links through to that user's personalized recommendations.

The Gorse dashboard Users page listing the users known to the recommender

Step 8: Enable HTTPS

nginx fronts the API and dashboard on port 80 and is ready for TLS. Point a DNS record at the VM, then obtain a certificate with certbot and let it configure nginx for port 443.

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

After issuance, restrict the NSG so only 443 (and 22 from your management network) is reachable, and use the API and dashboard over https://your-domain.example.com/.

Persistence, first boot and updates

The recommender's data and cache live in embedded SQLite databases on the OS disk under /var/lib/gorse/ and are captured into the image, so a VM launched from this image is ready immediately. The first boot service generates the per VM secrets, refreshes the Gorse binary to the latest release, marks the engine ready, then disables itself so subsequent reboots are unaffected. The OS ships fully patched with unattended security upgrades enabled.

Terminal showing the per VM info note with the API key, admin key and dashboard password masked, alongside the resolved dashboard and API URLs

Support

Every cloudimg deployment includes 24/7 support with a 24 hour response SLA. Contact support@cloudimg.co.uk for help with deployment, configuration or scaling.

This is a repackaged open source software product with additional charges for cloudimg support services. Gorse is licensed under the Apache License 2.0 and is a trademark of its respective owner. 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.