Deployment guide

Bar Assistant

Overview

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. You can 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 it uses Meilisearch so that lookups across recipes and ingredients are instant.

This guide covers the deployment and configuration of Bar Assistant on Ubuntu 24.04 on Azure, using SecureAnyCloud Azure Marketplace images. The image ships the free, open-source, MIT-licensed Bar Assistant server, Salt Rim web client and Meilisearch engine. They run the officially supported way, as 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, and nothing ships with a known secret. On first boot, before the app is reachable, each VM generates a unique Laravel application key, a unique Meilisearch master key and a per-instance admin account with a random password. The search engine refuses any request without a key. Public self-registration is disabled by default (the register endpoint returns 403 and the Register button is hidden), so anonymous visitors cannot create accounts and the per-instance admin is the only account.

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

What you get:

  • 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 and 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 the latest security patches applied at build time
  • Azure Linux Agent for seamless cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with a guaranteed 24-hour response SLA

Prerequisites

  • An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
  • A subscription to the Bar Assistant listing on the 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.

Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the web client from the networks that use it.

1

Deploy from the Azure Portal

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

2

Deploy from the Azure CLI

RG="bar-assistant-prod"; LOCATION="eastus"; VM_NAME="bar-assistant-01" IMAGE_URN="sac1647283583153:bar-assistant:default:latest" 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
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:bar-assistant: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 bar-vnet --subnet bar-subnet --nsg bar-nsg --public-ip-sku Standard
3

Connect to your VM

ssh azureuser@<vm-ip>
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. nginx listens on :80. The API, search engine and web client are each published to 127.0.0.1 only. Confirm that the services are active and list the containers:

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

The services report active and the three containers report 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. It routes / to the web client, /bar to the API and /search to Meilisearch.

5

Read the per-instance credentials

On first boot, before the app was reachable, your VM generated a unique Laravel application key, a unique Meilisearch master key and a per-instance admin account with a random password. It wrote them to a root-only file. Read the file:

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

The file (mode 0600 root:root) holds ADMIN_EMAIL and ADMIN_PASSWORD (the account you use to sign in to the web client), 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.

6

Verify the security model

The web client and the public API version endpoint are reachable without authentication. 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

Expect these results:

  • The web client returns 200.
  • Meilisearch rejects the unauthenticated request with 401, because it is key-gated.
  • The registration endpoint returns 403, because public self-registration is disabled by default.
  • The protected profile endpoint rejects a request with no token with 401, and the same call with the per-instance admin token returns 200.

Together, these results show 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 that you obtain by signing in.

The same round trip is bundled as a single script on the image, which verifies that the credential works end to end:

sudo /usr/local/sbin/bar-assistant-roundtrip.sh
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. To enable registration for additional household members, see Step 11.

8

Create your first bar and import recipes

After you sign in, create a bar, which is your workspace for a collection of cocktails and ingredients. 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.

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.

10

Open a recipe

Select any cocktail to open its recipe. It shows the photo, description, glass type, method, ABV and the full ingredient list with measurements. You can scale the measurements and switch between millilitres, ounces and centilitres.

Add tasting notes, rate the cocktail, add missing ingredients to your shopping list, or edit and add your own recipes.

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

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

13

Server components

The image contains the following components:

  • 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 and /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 on first boot into /etc/barassistant/bar.env
  • Admin account: per-instance random password, seeded on first boot into /root/bar-assistant-credentials.txt
  • Operating system: Ubuntu 24.04 LTS (patched at build)
  • License: MIT (Bar Assistant, Salt Rim, Meilisearch)
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. View the configuration in /etc/barassistant/bar.env and /etc/barassistant/compose.yaml. After you change the environment file, restart the service to apply it.

15

Use your own domain and HTTPS (production)

The image serves the web client and API over plain HTTP on port 80, which suits a load balancer or private network. For production, terminate TLS in front of the VM so that 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 that references your certificate and key, open 443/tcp on the NSG, then run sudo systemctl reload nginx.
  • Point a DNS name you control at the VM public IP. The web client reads its API and search URLs at first boot from the resolved public address, so use a stable public IP or set the address before first boot when you use a custom domain.
16

Security notes

  • 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 that the admin password and tokens are encrypted in transit.
  • Rotate the seeded admin password. Sign in and change it in Settings. 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.
17

Support and Licensing

Bar Assistant, Salt Rim and Meilisearch are each distributed under the MIT License. This SecureAnyCloud image bundles the unmodified official open-source releases. SecureAnyCloud 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 SecureAnyCloud from the Azure Marketplace, and follow this guide to a working cocktail and home bar manager in minutes.

Deploy on Azure

Launch Bar Assistant 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