Running Grocy in Podman
My SO actually asked me to setup something self-hosted! Wow. So today we are setting up grocy, and we are not using the easiest way to do it.
For some background we have given up trying to remember what we have in our chest freezer, so we’ll try Grocy for this purpose.
I’m using the project official containers, podman, macvlan and a pod in this case, and I ran into one minor issue in the process that I mean to document here. Spoiler: it’s not something wrong with Podman in this case, but my general setup.
TL;DR #
If you just use the default networking setup (like Dockers, which is
bridged with the main networking interface), don’t use the podman network create
part, and remember to expose ports as needed below.
Default port for the frontend is 8080.
# Only necessary if you have a complicated network setup!
podman network create \
-d macvlan \
-o parent=br-network \
--subnet 192.0.2.0/24 \
--gateway 192.0.2.1 \
--ip-range 192.0.2.0/24 \
examplenet
# Comment out the --network line if not using the above network!
podman pod create \
--name grocy \
--network examplenet \
--ip 192.0.2.4 \
--add-host "backend:127.0.0.1"
# Remove the --label line if you don't want auto updating containers!
podman container create \
--pod grocy \
--label io.containers.autoupdate=registry \
--name grocy_frontend \
--memory 256m \
--cpus=1 \
grocy/frontend:v3.3.2
# Update the environment variables below to suit your needs!
podman container create \
--pod grocy \
--label io.containers.autoupdate=registry \
--name grocy_backend \
--memory 512m \
--cpus=1 \
-v /app/grocy/data/:/var/www/data \
-e GROCY_CULTURE=sv_SE \
-e GROCY_MODE=production \
-e GROCY_CURRENCY=SEK \
grocy/backend:v3.3.2
# Not strictly necessary!
podman container create \
--pod grocy \
--label io.containers.autoupdate=registry \
--name grocy_caddy \
-v /app/grocy/caddy/config/:/config \
-v /app/grocy/caddy/data/:/data \
-v /app/grocy/caddy/Caddyfile:/etc/caddy/Caddyfile \
--memory 256m \
--cpus=1 \
caddy:latest
podman generate systemd --new --files --name grocy
systemctl daemon-reload
mkdir -p /app/grocy/data
mkdir -p /app/grocy/caddy/{config,data}
mkdir /app/grocy/data/viewcache
curl https://raw.githubusercontent.com/grocy/grocy/master/config-dist.php > /app/grocy/data/config.php
chown 82:82 /app/grocy/data/*
systemctl enable --now pod-grocy.service
Networking #
First up, make sure we have a macvlan network to run this in. This is the same example as in my primer article on podman.
podman network create \
-d macvlan \
-o parent=br-network \
--subnet 192.0.2.0/24 \
--gateway 192.0.2.1 \
--ip-range 192.0.2.0/24 \
examplenet
If you are not using a stupid complicated setup like I do, skip
this step. But remember to expose the necessary ports on the pod when
creating it!
File system #
I keep my container data in a dedicated file tree, per application. So I created a structure that looks something like this:
mkdir -p /app/grocy/data
mkdir -p /app/grocy/caddy/{config,data}
Pod creation #
I thought more magic would go into creating a pod, but it’s really only another container wrapping a group of other containers, which share a bunch of namespaces. I like it.
podman pod create \
--name grocy \
--network examplenet \
--ip 192.0.2.4 \
--add-host "backend:127.0.0.1"
Here was the first minor thing I ran into when starting the pod – the
front-end container expected to find it’s backend by hostname
‘backend’, but I named the backend container grocy_backend
. So
fixing this with the --add-host
call at the end.
One quirk of using pods is that you expose ports on the pod,
and not on the containers in the pod. If you need to change exposed
ports, you need to recreate it. Since I use macvlan
in my setup I
don’t need to expose any ports.
Container creation #
We will create three containers, one for the backend, one for the frontend and one for Caddy.
But why use Caddy when the frontend already runs nginx? I’m using an internal ACME server to manage my internal TLS, and Caddy is really easy to configure for this.
Frontend #
This can probably run fine with even less allocated memory.
podman container create \
--pod grocy \
--label io.containers.autoupdate=registry \
--name grocy_frontend \
--memory 256m \
--cpus=1 \
grocy/frontend:v3.3.2
Nothing exciting here.
Backend #
Nothing exciting here, except the environment variables. If you want to configure grocy more than below, this is done using environment variables as per the documentation.
As I’m not using the example docker-compose.yml
to build and run
this, we will need to manually perform a step otherwise done while
building.
podman container create \
--pod grocy \
--label io.containers.autoupdate=registry \
--name grocy_backend \
--memory 512m \
--cpus=1 \
-v /app/grocy/data/:/var/www/data \
-e GROCY_CULTURE=sv_SE \
-e GROCY_MODE=production \
-e GROCY_CURRENCY=SEK \
grocy/backend:v3.3.2
The manual steps needed:
mkdir /app/grocy/data/viewcache
curl https://raw.githubusercontent.com/grocy/grocy/master/config-dist.php > /app/grocy/data/config.php
chown 82:82 /app/grocy/data/*
Some handy links:
- For
GROCY_CULTURE
, see this link for a list of valid values - Default configuration can be found here
- Example container env file can be found here
Caddy #
This container is optional. If you don’t want it, remember to expose port 8080 on the front-end container instead.
First up, create the container.
podman container create \
--pod grocy \
--label io.containers.autoupdate=registry \
--name grocy_caddy \
-v /app/grocy/caddy/config/:/config \
-v /app/grocy/caddy/data/:/data \
-v /app/grocy/caddy/Caddyfile:/etc/caddy/Caddyfile \
--memory 256m \
--cpus=1 \
caddy:latest
Example /app/grocy/caddy/Caddyfile
:
{
email me@example.com
}
grocy.example.com
{
reverse_proxy localhost:8080
}
My setup looks more like the zigbee2mqtt example in the Caddy primer but due to reasons I’m using a simple setup here. This setup will try to fetch a valid certificate from letsencrypt, so keep this in mind if you already run a reverse proxy or such.
systemd #
This will split the pod systemd definition into different files, one per container.
podman generate systemd --new --files --name grocy
systemctl daemon-reload
That should reload systemd and create the following files:
/etc/systemd/system/container-grocy_backend.service
/etc/systemd/system/container-grocy_caddy.service
/etc/systemd/system/container-grocy_frontend.service
/etc/systemd/system/pod-grocy.service
Finally, start the pod:
systemctl enable --now pod-grocy.service
Check if it’s up:
# podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
1df2731a50f6 grocy Running 46 minutes ago 0c1d6d9f698c 4
And all containers:
# podman ps --pod
[...]
0c1d6d9f698c k8s.gcr.io/pause:3.5 48 minutes ago Up 48 minutes ago 1df2731a50f6-infra 1df2731a50f6 grocy
74748ff2525d docker.io/grocy/backend:v3.3.2 php-fpm81 47 minutes ago Up 47 minutes ago grocy_backend 1df2731a50f6 grocy
26cd5043ab44 docker.io/library/caddy:latest caddy run --confi... 47 minutes ago Up 47 minutes ago grocy_caddy 1df2731a50f6 grocy
839d7dd91776 docker.io/grocy/frontend:v3.3.2 nginx -e /proc/se... 47 minutes ago Up 47 minutes ago grocy_frontend 1df2731a50f6 grocy
Backups #
It’s enough to backup /app/grocy/data
, which should contain
database, configuration, and any uploaded media (like recipe images).
If you use Caddy like above, it might be worth backing up /app/grocy
instead.
Conclusion #
Now I have to go through that chest freezer to see what’s in it…