Applications Azure

Bar Assistant on Ubuntu 24.04 on Azure User Guide

| Product: Bar Assistant on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Bar Assistant on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Bar Assistant is an open source, all in one solution for organising cocktail recipes and tracking a home bar. You build a catalogue of ingredients and the bottles you own, and it works out which cocktails you can make, lets you scale, cost and tag recipes, keep tasting notes and shopping lists, and publish a shareable menu. It pairs a Laravel REST API with the Salt Rim browser client for searching, filtering and editing your collection, and uses Meilisearch so lookups across recipes and ingredients are instant.

The cloudimg image ships the free and open source, MIT licensed Bar Assistant server, the MIT licensed Salt Rim web client and the MIT licensed Meilisearch engine, run the officially supported way as the upstream containers pinned by image digest. All three images are captured into the VM, so your instance starts in seconds. The image is secure by default: nothing ships with a known secret. A unique Laravel application key, a unique Meilisearch master key and a per instance admin account with a random password are generated for each VM on first boot, before the app is reachable; the search engine refuses any request without a key; and public self registration is disabled by default (the register endpoint returns 403 and the Register button is hidden) so anonymous visitors cannot create accounts, leaving the per instance admin as the only account. Backed by 24/7 cloudimg support.

Bar Assistant, Salt Rim and Meilisearch are trademarks of their respective owners. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by any of them. It ships the free and open source MIT licensed self hosted software, unmodified.

The docker, bar-assistant, nginx, firstboot and postboot services all active, and the three compose containers (bar-assistant server, Meilisearch and Salt Rim) running and healthy

What is included:

  • Bar Assistant server v5 (the MIT licensed Laravel API), pinned by image digest
  • Salt Rim web client v4 (the MIT licensed Vue browser client), pinned by image digest
  • Meilisearch v1.15 (the MIT licensed search engine) running in production mode, so every request requires a key
  • A SQLite application database, created empty on first boot and stored on a persistent volume
  • Docker Engine with the API, web client and search engine published to the loopback interface only, fronted by nginx on port 80 at / (web client), /bar (API) and /search (search)
  • bar-assistant.service, bar-assistant-firstboot.service, bar-assistant-postboot.service and nginx.service as systemd units, enabled and active on boot
  • A unique Laravel application key, a unique Meilisearch master key and a per instance admin account with a random password generated per VM on first boot, never baked into the image
  • Public self registration disabled by default (the register endpoint returns 403 and the Register button is hidden), so only the per instance admin can sign in until you choose to open registration
  • No default login, no shipped secret and an empty database on first boot
  • Ubuntu 24.04 LTS base with latest security patches applied at build time
  • Azure Linux Agent for seamless cloud integration and SSH key injection
  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region
  • Subscription to the Bar Assistant listing on Azure Marketplace

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a sensible starting point for a household or an enthusiast. For larger collections or many concurrent users use Standard_D2s_v5 or larger. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web client from the networks that use it.

Step 1: Deploy from the Azure Portal

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Bar Assistant 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 HTTP (80). Then Review + create and Create.

Step 2: Deploy from the Azure CLI

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

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

Step 4: Confirm the services are running

The stack runs as three containers (the Bar Assistant server, Meilisearch and the Salt Rim web client) under one bar-assistant.service, fronted by nginx. Confirm the services are active and see the containers. nginx listens on :80; the API, search engine and web client are each published to 127.0.0.1 only:

sudo systemctl is-active docker bar-assistant nginx
sudo docker compose -f /etc/barassistant/compose.yaml ps

You will see the services report active and the three containers running. The API (127.0.0.1:8082), Meilisearch (127.0.0.1:8081) and the Salt Rim client (127.0.0.1:8083) are bound only to the loopback interface; nginx on :80 is the single public front door and routes / to the web client, /bar to the API and /search to Meilisearch.

Step 5: Read the per instance credentials

A unique Laravel application key, a unique Meilisearch master key and a per instance admin account with a random password were generated for this VM on the first boot, before the app was reachable, and written to a root only file. Read them:

sudo cat /root/bar-assistant-credentials.txt

The file (mode 0600 root:root) holds ADMIN_EMAIL and ADMIN_PASSWORD (the account you sign in to the web client with), plus WEB_URL, API_URL, the APP_KEY and the MEILI_MASTER_KEY. None of these ship in the image; every value is unique to this VM, so no two instances share a credential and there is no default login to change.

The bar-assistant-credentials.txt file at mode 0600 root root with the per VM admin email and password, URLs, application key and Meilisearch master key, the secrets redacted, and a note that they are generated uniquely on first boot

Step 6: Verify the security model

The web client and the public API version endpoint are reachable without authentication, but every protected API endpoint requires a bearer token, and Meilisearch refuses any request without a key. Confirm that the web client loads, that an unauthenticated request to a protected endpoint is rejected with 401, and that the per instance admin credential authenticates a real call:

ADMIN_EMAIL=$(sudo grep '^ADMIN_EMAIL=' /root/bar-assistant-credentials.txt | cut -d= -f2-)
ADMIN_PASSWORD=$(sudo grep '^ADMIN_PASSWORD=' /root/bar-assistant-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'web client    (no auth):    %{http_code}\n' http://localhost/
curl -s -o /dev/null -w 'search        (no key):     %{http_code}\n' http://localhost/search/indexes
curl -s -o /dev/null -w 'register      (closed):     %{http_code}\n' -X POST -H 'Content-Type: application/json' -d '{"email":"x"}' http://localhost/bar/api/auth/register
curl -s -o /dev/null -w 'profile       (no token):   %{http_code}\n' -H 'Accept: application/json' http://localhost/bar/api/profile
TOKEN=$(curl -s -X POST http://localhost/bar/api/auth/login \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -d "{\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["token"])')
curl -s -o /dev/null -w 'profile       (with token): %{http_code}\n' \
  -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' http://localhost/bar/api/profile

The web client returns 200; Meilisearch rejects the unauthenticated request with 401 (it is key gated); the registration endpoint returns 403 because public self registration is disabled by default; the protected profile endpoint is rejected with 401 for no token, and the same call with the per instance admin token returns 200. This is the security model: the web client and the search engine are locked down, public registration is closed, and the API is gated by a bearer token you obtain by signing in.

curl showing the web client returning HTTP 200, Meilisearch rejecting an unauthenticated request with HTTP 401 as it is key gated, the registration endpoint returning 403 as public registration is closed, and the protected profile endpoint returning 401 without a token and 200 with the per instance admin token

The same round trip is bundled as a single script on the image, which the build and smoke tests run to prove the credential works end to end:

sudo /usr/local/sbin/bar-assistant-roundtrip.sh

The bundled round trip script reporting OK: the web client, search and API are live, no and wrong tokens are rejected with 401, and the per instance admin credential authenticates a real API call

Step 7: Open the web client and sign in

Browse to http://<vm-ip>/ to reach the Salt Rim web client. Sign in with the ADMIN_EMAIL and ADMIN_PASSWORD from Step 5. Public self registration is disabled by default on this appliance, so there is no Register button and anonymous visitors cannot create accounts; see Step 11 to enable registration for additional household members.

The Salt Rim sign in page for Bar Assistant, with the per instance admin email entered and the Login and Register buttons

Step 8: Create your first bar and import recipes

After signing in, create a bar (your workspace for a collection of cocktails and ingredients) and choose to import the bundled base data. Bar Assistant then loads several hundred classic cocktail recipes and their ingredients, so you have a populated library to explore immediately. The home dashboard shows your bar statistics, the latest cocktails and recommendations based on what is on your shelf.

The Bar Assistant home dashboard for a bar, showing bar statistics of 613 total cocktails and 286 total ingredients, a list of the latest cocktails, and a recommendations panel

Step 9: Browse and search your cocktails

Open Cocktails to browse the library as a grid of recipe cards with photos, ratings, ingredients and tags. Use the search box (powered by Meilisearch) to find a recipe instantly, filter by ingredient, tag or method, and sort the list. Mark what is on your Shelf and Bar Assistant highlights the cocktails you can make right now.

The Bar Assistant cocktails page showing a grid of cocktail recipe cards, each with a photo, name, star rating, ingredient list and tags, plus a search box and filter and sort controls

Step 10: Open a recipe

Select any cocktail to open its recipe: the photo, description, glass type, method, ABV and the full ingredient list with measurements, which you can scale and switch between millilitres, ounces and centilitres. Add tasting notes, rate it, add missing ingredients to your shopping list, or edit and add your own recipes.

A single cocktail recipe detail view in Bar Assistant, showing the Mosquito with its photo, description, tags, glass type, method, ABV and the scaled ingredient list with measurements

Step 11: Manage registration and users

Public self registration is disabled by default on this appliance, so no anonymous visitor can create an account: the /bar/api/auth/register endpoint returns 403 (an nginx lock added on first boot) and the Register button is hidden. To enable registration for household members, set ALLOW_REGISTRATION=true in /etc/barassistant/bar.env, remove the nginx lock, then reload and recreate the stack:

sudo sed -i 's/^ALLOW_REGISTRATION=.*/ALLOW_REGISTRATION=true/' /etc/barassistant/bar.env
sudo truncate -s 0 /etc/nginx/snippets/ba-reg-lock.conf
sudo systemctl reload nginx
sudo docker compose --env-file /etc/barassistant/bar.env -f /etc/barassistant/compose.yaml up -d

Each user manages their own profile and password in Settings; a bar owner can invite members and assign roles to share a bar even while public registration stays closed.

Step 12: Call the API from your own machine

Every feature of the web client is backed by the REST API, which you can call directly. Obtain a token by signing in, then call a protected endpoint with the VM address:

TOKEN=$(curl -s -X POST http://<vm-ip>/bar/api/auth/login \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -d '{"email":"<ADMIN_EMAIL>","password":"<ADMIN_PASSWORD>"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["token"])')
curl -s -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' -H 'Bar-Assistant-Bar-Id: 1' \
  "http://<vm-ip>/bar/api/cocktails?per_page=5"

The login returns a 14 day bearer token; protected list endpoints take a Bar-Assistant-Bar-Id header to select which bar to query. The full API is documented at http://<vm-ip>/bar/api/server/openapi.

Step 13: Server components

Component Version / Detail
API server Bar Assistant server v5 (Laravel, pinned by image digest)
Web client Salt Rim v4 (Vue, pinned by image digest)
Search engine Meilisearch v1.15 (production mode, key required)
Front door nginx on :80 routing / to the client, /bar to the API, /search to search
Application database SQLite (created empty on first boot, on a persistent volume)
Orchestration Docker Compose under bar-assistant.service
Application key per instance, generated first boot into /etc/barassistant/bar.env
Admin account per instance random password, seeded first boot into /root/bar-assistant-credentials.txt
Operating system Ubuntu 24.04 LTS (patched at build)
License MIT (Bar Assistant, Salt Rim, Meilisearch)

Step 14: Managing the service

sudo systemctl status bar-assistant --no-pager | head -12
sudo docker compose -f /etc/barassistant/compose.yaml logs --tail 40 bar-assistant

Restart the whole stack with sudo systemctl restart bar-assistant, follow the API logs live with sudo docker compose -f /etc/barassistant/compose.yaml logs -f bar-assistant, and view configuration in /etc/barassistant/bar.env and /etc/barassistant/compose.yaml. After changing the environment file, restart the service to apply it.

Step 15: Use your own domain and HTTPS (production)

The image serves the web client and API over plain HTTP on port 80, which is convenient behind a load balancer or private network. For production you should terminate TLS in front of the VM so credentials travel encrypted:

  • Front the VM with Azure Application Gateway, a load balancer with a managed certificate, or a CDN, and forward to nginx on port 80.
  • Or install your own certificate: add a TLS server block to /etc/nginx/sites-available/bar-assistant referencing your certificate and key, open 443/tcp on the NSG, then sudo systemctl reload nginx.
  • Point a DNS name you control at the VM public IP. Because the web client reads its API and search URLs at first boot from the resolved public address, use a stable public IP or set the address before first boot when using a custom domain.

Step 16: Security recommendations

  • Restrict the NSG. Allow TCP 80 (and 22 for admin) only from the networks that use the app.
  • Terminate TLS in front of the app (Step 15) so the admin password and tokens are encrypted in transit.
  • Rotate the seeded admin password. Sign in and change it in Settings, and close open registration (Step 11) once your users exist.
  • Keep the search engine and API private. Meilisearch and the API are bound to loopback and fronted by nginx; keep them that way and never expose the container ports directly.
  • Keep the OS patched. Unattended security upgrades remain enabled on the running VM.

Step 17: Support and Licensing

Bar Assistant, Salt Rim and Meilisearch are each distributed under the MIT License. This cloudimg image bundles the unmodified official open source releases; cloudimg provides the packaging, the single nginx front door, the per instance key and admin generation, the paired deploy guide, and 24/7 support with a guaranteed 24 hour response SLA. Bar Assistant is an independent open source project and this image is not affiliated with or endorsed by it.

Deploy on Azure

Launch Bar Assistant on Ubuntu 24.04 LTS by cloudimg from the Azure Marketplace and follow this guide to a working cocktail and home bar manager in minutes.