Deployment guide

Gorse

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. It also provides 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.

This SecureAnyCloud 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. It is 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, with 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 way.

A gorse-firstboot.service oneshot generates a unique API key, dashboard password and admin key on each VM's first boot and writes them to a root-only file. The engine is marked 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. Every launch therefore runs current software rather than the version frozen at build time.

What you get:

  • 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, with no external database or cache
  • An 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
  • An Ubuntu 24.04 LTS base, patched at build time
  • 24/7 SecureAnyCloud support, 24h response SLA

Prerequisites

You need 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. The recommended VM size is Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and small catalogues. For production workloads with bigger datasets, use Standard_D2s_v5 or larger.

Gorse keeps its store on the OS disk, so expand the disk before loading large catalogues.

1

Deploy from the Azure Portal

Search the Marketplace for Gorse on Ubuntu 24.04 and choose your VM size.

Attach a network security group (NSG) that allows TCP 22 (SSH) from your management network. Also allow TCP 80 and 443 (the API and dashboard) from the networks and applications that need to reach it.

In production, front port 80 with TLS (see Step 8).

2

Deploy from the Azure CLI

RG="gorse-prod"; LOCATION="eastus"; VM_NAME="gorse-01" IMAGE_URN="sac1647283583153:gorse-ubuntu-24-04:default:latest" 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
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:gorse-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --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
3

Connect via SSH

ssh azureuser@<vm-ip>
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, and 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.

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. Then 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. 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.

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. It 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. The personalized recommendations then become tailored to each user's history.

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 that 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. A request to the dashboard root returns 302, which redirects 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.

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

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

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

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 certbot 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 the certificate is issued, restrict the NSG so that only 443 (and 22 from your management network) is reachable. Then 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/. They 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 and marks the engine ready. It then disables itself, so subsequent reboots are unaffected. The OS is patched at build time and ships with unattended security upgrades enabled.

Support

Every SecureAnyCloud deployment includes 24/7 support with a 24-hour response SLA. Contact sales@secureanycloud.com for help with deployment, configuration or scaling.

This is a repackaged open-source software product, with additional charges for SecureAnyCloud 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.

Deploy on Azure

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