Install with Docker

This page starts Beer Menu for the first time on a computer that already has Docker with Compose installed. You do not need a copy of the Beer Menu project: you save one short file and type a few commands in a terminal. After that, everything is done in the browser.

Start Beer Menu for the first time

  1. Make a folder for Beer Menu, with a folder named "data" inside it where Beer Menu keeps its data, and open a terminal there:
    mkdir -p ~/beer-menu/data
    cd ~/beer-menu
  2. Copy the compose file below with the Copy button, and save it in that folder as docker-compose.yaml:
    services:
      api:
        image: ghcr.io/helmnet/beer-menu-api:${BEER_MENU_VERSION:-latest}
        user: "${PUID:-65532}:${PGID:-65532}"
        volumes:
          - ${BEER_MENU_DATA:-./data}:/data
        restart: unless-stopped
    
      web:
        image: ghcr.io/helmnet/beer-menu-web:${BEER_MENU_VERSION:-latest}
        user: "${PUID:-65532}:${PGID:-65532}"
        ports:
          - "${BEER_MENU_WEB_PORT:-8080}:8080"
        restart: unless-stopped
  3. Tell Beer Menu to run as your own user, so it can write to the "data" folder. It refuses to run as root.
    (set -C && printf 'PUID=%s\nPGID=%s\n' "$(id -u)" "$(id -g)" > .env)
    chmod 600 .env
    This writes a file named .env, which Docker Compose reads every time Beer Menu starts, so you do this only once. If .env already exists, the command leaves it unchanged and reports that it cannot overwrite it. Only you can read it, because it may later hold a password.
  4. Download Beer Menu and start it:
    docker compose up -d
  5. For the admin app, open http://localhost:8080/ in a browser on the same computer.
  6. For the TV display, open http://localhost:8080/display. It shows an empty tap until you put a keg on it.

Beer Menu keeps running in the background and starts again after a restart. Keep the "data" folder safe: it holds all your beers, kegs and settings.

To use another port or change other settings, see "Environment variables" below.

Next, create your admin account: see Getting started.

Environment variables

Beer Menu runs without any of these settings; each one is optional. Use them to change the port, run a fixed release, create the first admin from a file, open the admin app from other devices over plain HTTP, or turn on Brewfather import, authenticator apps and passkeys.

How to set a variable

There are two kinds of setting.

Compose settings (PUID, PGID, BEER_MENU_DATA, BEER_MENU_WEB_PORT and BEER_MENU_VERSION) go in the .env file next to docker-compose.yaml, one NAME=value line each, for example:

BEER_MENU_WEB_PORT=8081

App settings (every other name starting with BEER_MENU_) go in an environment: block under api: in docker-compose.yaml. Add the environment: line once, then one line per setting under it, indented as shown:

  api:
    environment:
      BEER_MENU_COOKIE_SECURE: "false"

Never write a secret value in docker-compose.yaml. Put it in .env instead, and refer to it in docker-compose.yaml as ${NAME}, as the First admin example below shows.

A variable set in the terminal (export NAME=value) overrides the same name in .env, but only for that terminal, so keep your settings in .env.

After any change, run docker compose up -d; Compose restarts whatever changed. Run every docker compose command from the Beer Menu folder (cd ~/beer-menu), where docker-compose.yaml and .env are.

Run as your user: PUID and PGID

PUID and PGID are the user and group IDs Beer Menu runs as. That user must own the data folder. Neither may be 0: Beer Menu refuses to start as root. If they are not set, Beer Menu runs as 65532. The install steps above already set them to your own IDs in .env.

Data folder: BEER_MENU_DATA

BEER_MENU_DATA is the folder on this computer that holds the database and its backups. The default is ./data, the "data" folder next to docker-compose.yaml. If you choose another folder, it must exist and be owned by the PUID:PGID user before Beer Menu starts.

Web port: BEER_MENU_WEB_PORT

BEER_MENU_WEB_PORT is the port the admin app and the TV display open on. The default is 8080. Choose another if something else already uses 8080; the addresses above change with it. For example, with BEER_MENU_WEB_PORT=8081 the admin app is at http://localhost:8081/.

Version: BEER_MENU_VERSION

BEER_MENU_VERSION is the release to run, such as 1.0.0. The default is latest, the newest release. With a version set, Beer Menu changes only when you change this line. With latest, docker compose up -d keeps the release it already downloaded and does not look for a newer one. To update, set the new version, or keep latest for the newest release, then run:

docker compose pull
docker compose up -d

First admin: BEER_MENU_ADMIN_USERNAME and BEER_MENU_ADMIN_PASSWORD

BEER_MENU_ADMIN_USERNAME and BEER_MENU_ADMIN_PASSWORD create the first admin when Beer Menu starts, but only while no admin exists. Set both or neither. The username must be 1 to 64 letters, digits, dots, underscores or hyphens, and the password 12 to 256 characters. Setting only one, or a value outside those limits, stops Beer Menu at startup. If they are not set, you create the first admin in the browser instead: see Getting started.

Open .env in a text editor and add the password line. Replace CHANGE-ME with your password, keeping the single quotes so Compose reads it exactly as typed. Left unchanged, it is too short, so Beer Menu stops at startup:

BEER_MENU_ADMIN_PASSWORD='CHANGE-ME'

Then add these lines to the environment: block under api: in docker-compose.yaml:

      BEER_MENU_ADMIN_USERNAME: owner
      BEER_MENU_ADMIN_PASSWORD: ${BEER_MENU_ADMIN_PASSWORD}

Never write the password itself in docker-compose.yaml. Keep .env readable only by you (chmod 600 .env, as the install steps did). After the first start, remove both lines from docker-compose.yaml and the password line from .env, then run docker compose up -d. Until you do, the password stays in the running container, where docker inspect shows it.

Plain HTTP on your network: BEER_MENU_COOKIE_SECURE

BEER_MENU_COOKIE_SECURE is true by default: the sign-in cookie then works only over HTTPS or at http://localhost. Set it to "false" only if you open the admin app over plain HTTP by the computer's network address, such as from your phone; otherwise sign-in seems to work but the next page is not signed in. Leave it on when the app is behind HTTPS.

Over plain HTTP, your password and sign-in cookie cross your network unencrypted, so anyone on it can read them. Where you can, put Beer Menu behind HTTPS (for example a reverse proxy) instead of turning this off.

Encryption key: BEER_MENU_SECRET_KEY_FILE or BEER_MENU_SECRET_KEY

The encryption key protects the stored Brewfather API key and the secrets of authenticator apps. If it is not set, Brewfather import and authenticator apps are off.

Create the key once, in the Beer Menu folder:

(umask 077 && set -C && openssl rand -base64 32 > beer-menu-secret-key)

The umask 077 makes the file readable only by you from the moment it is created. The set -C stops the command from replacing a key that already exists.

The file must be owned by the PUID:PGID user. It is when you create it as yourself after the install steps above.

Then give the file to Beer Menu with BEER_MENU_SECRET_KEY_FILE. Add the environment: and secrets: lines under api:, and the second secrets: block at the end of docker-compose.yaml, not indented:

  api:
    environment:
      BEER_MENU_SECRET_KEY_FILE: /run/secrets/beer_menu_secret_key
    secrets:
      - beer_menu_secret_key

secrets:
  beer_menu_secret_key:
    file: ./beer-menu-secret-key

BEER_MENU_SECRET_KEY holds the key itself instead of a file. If both are set, the file wins. The file is safer, because environment values show in docker inspect.

Keep a copy of the key somewhere other than the data folder. If you lose or change it, Brewfather is disconnected (enter the Brewfather API key again) and every authenticator app's codes stop working (those admins sign in with a passkey or a recovery code, then remove the authenticator app and add it again). A restored backup needs the same key.

Passkeys: BEER_MENU_PUBLIC_URL

BEER_MENU_PUBLIC_URL is the address admins open the admin app at, exactly as the browser shows it: scheme, host name and port if any, such as https://taplist.example.org. Passkeys need it; if it is not set, passkeys are off. It must be https:// with a host name (not an IP address), or http://localhost, with an optional port and no path. A wrong value stops Beer Menu at startup.