Platforms and Deployment Modes¶
Pantry Raider can run as a server stack, as a self-contained Raspberry Pi appliance, or as a thin Pi control surface for a stack that lives elsewhere. This page describes the three deployment modes, how to host the server stack, the AI providers you can plug in, and the Home Assistant integration.
For the physical hardware and peripherals, see Hardware.
Deployment modes¶
The mode is chosen in the setup wizard (or carried in via config.env on a
flashed device) and stored in the app's settings.json. The three modes are
defined in service/app/config.py:
- server. Pantry Raider runs on a general server (NAS, mini PC, VM, and so on). It connects to a separately running Grocy. This is the only non-Pi mode.
- pi_hosted. Everything runs on one Raspberry Pi: Pantry Raider plus
Grocy. The installer offers this as two clear choices: Pi Host Kiosk
(the full stack plus this device's own touchscreen/kiosk, and a Stream Deck
if one is attached) and Pi Host Standalone (the full stack, headless: no
kiosk or Stream Deck, which you can still add later from the web UI). Both are
the same
pi_hostedstack; the difference is only whether this Pi also drives a screen. The first-boot provisioner installs a host bridge and a port 80 to 9284 redirect so the device is reachable athttp://<hostname>.local/. - pi_remote. A thin satellite. The device drives a kiosk and/or Stream Deck pointed at an existing Pantry Raider server on the LAN. There is no local Docker, Grocy, or Mealie; the satellite runs the Pantry Raider UI on port 80 (via a Python venv, or optionally Docker) and pulls its backend config from the main server. This is what makes a low-spec board like a Pi Zero useful.
Switching a Pi Hosted appliance to satellite duty¶
A pi_hosted appliance can later become a satellite of a bigger server without
reflashing. In Settings under Advanced, "Run as a satellite" takes the
main server's URL and API key, pauses the local Grocy and Mealie containers
(their data stays on the SD card, nothing is deleted), and flips the device to
pi_remote: the kiosk and Stream Deck keep working, now backed by the main
server's inventory and settings.
The switch is reversible. On a switched device the Advanced settings section gains "Switch back to full stack", which starts the paused containers again and restores the backend settings the device had before the switch, inventory data intact. A device that was flashed as a plain Pi Remote has no local stack and is never offered the switch back.
For exactly which settings are editable, inherited from the server, or device-local in each mode, see the Settings visibility matrix.
Updates across the fleet¶
The "Install updates automatically" setting (on by default) and the update channel work a little differently in each mode:
- A
serverinstall is kept current by the bundled Watchtower container (the maintainedghcr.io/nicholas-fedor/watchtower), which checks once a day for a new Pantry Raider image and recreates the app container when one is published. It only manages Pantry Raider's own app container and leaves any Watchtower you already run alone. On a server, the channel and the switch in Settings cover the Pi Remotes connected to it and the update notice; they do not steer Watchtower. To stay on a release line, setPANTRYRAIDER_TAG(for example0.19) in.env. To stop automatic installs, rundocker compose stop watchtower. - A
pi_hostedappliance applies updates through the host-bridge over-the-air helper when the switch is on, and the in-app update control on its Settings page can check and apply on demand. - A
pi_remotesatellite inherits the switch and the channel from its main server (they are among theSATELLITE_PULL_FIELDS), so a server and its satellites converge on the same version rather than drifting apart.
Server installs need Docker 24 or newer with Compose v2. A server set up before the updater changed keeps its old compose file, and with it an updater that does not work with Docker 29, until you replace the file; the one-time step is in the README under Updating.
Hosting the server stack¶
The server and pi_hosted modes run the stack with Docker 24 or newer and
Docker Compose v2. Optional backends are gated behind compose profiles, so you
only run what you need.
Profiles:
- (default, no profile or
with-grocy): the Pantry Raider service plus Grocy. with-mealie: adds Mealie for recipes, meal plan, and shopping list.with-ollama: adds Ollama for fully local AI.
Example enabling everything:
docker compose --profile with-grocy --profile with-mealie --profile with-ollama up -d
Pinned backend versions and ports¶
The bundled backends are pinned to specific image tags (not :latest) so an
unattended pull cannot move you onto a breaking release.
| Service | Image | Tag | Port |
|---|---|---|---|
| Pantry Raider | ghcr.io/syracuse3dprintingorg/pantryraider |
${PANTRYRAIDER_TAG}, or the older ${FOODASSISTANT_TAG} (default latest) |
9284 |
| Grocy | lscr.io/linuxserver/grocy |
4.6.0 |
9383 |
| Mealie | ghcr.io/mealie-recipes/mealie |
v3.28.0 |
9285 |
| Ollama | ollama/ollama |
0.34.4 |
11434 (this device only) |
| Watchtower (server only) | ghcr.io/nicholas-fedor/watchtower |
1.22.3 |
none |
| Beszel hub and agent | henrygd/beszel, henrygd/beszel-agent |
0.20.0 (same tag for both) |
8090 |
| CUPS (server compose) | olbat/cupsd |
pinned by digest | 6631, this device only |
The bundled Ollama answers only on the device itself. Pantry Raider runs on the
same device and reaches it from there, so nothing else needs the port. To let other
computers on your network use it, including Pi Remotes that share the server's AI
settings, change its port line in the compose file
from 127.0.0.1:11434:11434 to 11434:11434; Ollama has no password of its
own, so only do that on a network you trust.
Logs¶
The app writes its own activity to the container log and to the debug
download in Settings. It does not write a line for every request: a kitchen
screen refreshes every few seconds, and on a Raspberry Pi each of those lines
would be a write to the memory card. If you want per-request lines back while
you chase something, set PR_ACCESS_LOG=1 on the container and restart it.
The container log itself is capped at three files of 10 MB, so it can never
fill a card on its own. That cap covers every bundled service (Grocy, Mealie,
Ollama, CUPS, Watchtower, Beszel) on new installs, and on servers that download
the current compose file. A Pi appliance that is already set up keeps its
current compose file, where only the Pantry Raider log is capped, until it is
reflashed.
To move a backend to a newer version, back up first, then bump the tag in your compose file and recreate just that service.
Grocy updated and inventory stopped loading¶
Symptom. The Inventory and Expiring pages show a banner starting "Grocy
is running but reported a problem with its own setup", quoting an "Invalid
setting in config.php" message about AUTH_CLASS. Refresh does not help.
Grocy's own web page shows the same message. /health reports grocy:
error with the cause in grocy_detail.
Cause. Grocy 4.7.0 moved its login handler into a new namespace. A
config.php written by an older Grocy still says
Setting('AUTH_CLASS', 'Grocy\Middleware\DefaultAuthMiddleware');, and once
the Grocy image updates (an unpinned :latest, or a bump of the pin), Grocy
refuses every request until that line changes. The stacks Pantry Raider ships
pin Grocy, so this mostly hits a Grocy you run separately.
Fix on a server or Unraid install. In Grocy's data folder (/config/data
inside the container; on Unraid, /mnt/user/appdata/<your grocy>/data), back
up config.php, then change the line to:
Setting('AUTH_CLASS', 'Grocy\Middleware\Auth\DefaultAuthMiddleware');
If Grocy signs you in through LDAP or a reverse proxy, the line names
LdapAuthMiddleware or ReverseProxyAuthMiddleware instead: keep that name
and add Auth\ in the same place. The banner's fix names the one your Grocy
uses.
Grocy picks the change up within a few seconds; press Refresh in Pantry
Raider. One-liner for a Grocy container named grocy with the standard
sign-in:
docker exec grocy sh -c 'cp -p /config/data/config.php /config/data/config.php.bak && sed -i "s/Grocy\\\\Middleware\\\\DefaultAuthMiddleware/Grocy\\\\Middleware\\\\Auth\\\\DefaultAuthMiddleware/" /config/data/config.php'
Appliances repair themselves. A Pi Hosted appliance checks the running
Grocy on every update and fixes the line (backup first), and the banner
offers a Repair inventory connection button that does the same on demand. The
compose stacks also mount a start-up script into the Grocy container
(docker/grocy-init) so a future Grocy update fixes itself when the
container starts. Both handle all three sign-in methods, and both put the
line back if you return to Grocy 4.6.
An expected warning in Grocy's log. When the Grocy container starts, its
log may open with a linuxserver warning that files in /custom-cont-init.d
are not owned by root. That is the start-up script above, and the warning is
expected: the script still runs, and Grocy works normally.
Reverse proxy and URL caveat¶
You can put Pantry Raider behind a reverse proxy (for example Pangolin) to get a
public URL. One important caveat: headless clients must use the LAN URL, not the
public proxy URL. A request without a browser session (for example a Home
Assistant REST sensor) hitting the public URL gets an HTML redirect rather than
the JSON it expects. So Home Assistant REST sensors point at the LAN address such
as http://192.168.1.50:9284, while human-facing Lovelace buttons can use the
public URL.
HTTPS¶
Pantry Raider serves plain HTTP on port 9284 and does not terminate TLS itself, so secure access is added in front of it. Pick whichever fits your setup:
- Reverse proxy (recommended). Put a proxy such as Caddy, nginx, Traefik, or
the bundled Pangolin tunnel in front of the app and let it handle TLS and
certificates. Caddy is the simplest: a one-line site block proxying to
localhost:9284gets an automatic Let's Encrypt certificate for a public hostname. Terminate TLS at the proxy and forward HTTP to Pantry Raider on the LAN. - Tunnel. The built-in remote-access tunnel (Settings, Forager) publishes the app over HTTPS without opening a port, which is the easiest way to reach it securely from outside the LAN.
- Self-signed, LAN only. For a closed network you can place any of the above proxies in front with a self-signed certificate; expect a browser warning unless you trust the certificate on each device.
Keep the LAN-URL caveat above in mind: Home Assistant REST sensors and other headless clients should still call the LAN HTTP address directly, not the HTTPS front end.
AI providers¶
AI features are optional. The vision provider is selected in the setup wizard.
The supported providers (see vision_provider in service/app/config.py):
- gemini (Google). Cloud, API key. The default provider.
- openai. Cloud, API key.
- anthropic. Cloud, API key.
- ollama. Fully local inference, no API key. Reads from an Ollama instance
(bundled via the
with-ollamaprofile on port 11434, which answers only on the device itself unless you publish the port). Local vision models are heavy, so this is best on x86-64 with plenty of RAM rather than a small SBC.
If you do not want local inference, configure any one of the cloud providers and any supported board is fine.
Home Assistant integration¶
There are two ways to use Pantry Raider with Home Assistant:
- Add-on (HA OS / Supervised). Pantry Raider installs as an add-on and lives in the HA sidebar with no separate login; HA authenticates the UI through Ingress.
- Standalone. A standalone Pantry Raider instance exposes REST endpoints that
HA can consume. The
homeassistant/directory ships REST sensors (expiring summary, inventory dashboard, pending scan count, and the Mealie shopping and meal-plan summaries), arest_commandfor posting scans, automations, and a Lovelace dashboard.
A common HA pattern is the headless barcode scanner: a USB or Bluetooth HID
scanner is captured with the keyboard_remote integration, an automation buffers
the typed digits, and a rest_command posts the completed barcode to
/pending/scan on the Pantry Raider LAN URL. keyboard_remote only works on
Home Assistant OS / Supervised. See
homeassistant/barcode-scanner.md for the
full walkthrough, and remember the LAN-URL caveat above for all REST sensors and
commands.