Setting up Grocy with Podman and Cloudflare Tunnels


This article serves as another guide for people looking to setup Grocy. My setup works roughly as below:

grocy

What’s Grocy?

Grocy is a self-hosted grocery management app. It has a web interface (like every app should), and native android/iOS apps.

grocy

I turn to Grocy because I buy groceries opportunistically. I’m a student that cycles everwhere and it is more effective to chain tasks together and go shopping after a lab/lecture. As such, I often find myself in Aldi not knowing what I need to buy.

the bad news: it’s written in PHP

PHP is infamously problematic. It’s a very productive language at the expense of consistent syntax, or general security.

A compounding issue is that I’m running this on Arch Linux. Arch only supports “latest and greatest” software and I am certain that I’ll run into PHP regression bugs with this package manager.

I love my Arch PC and I don’t want to touch PHP with a ten-foot-pole. Instead, I’m putting Grocy inside a container. Whilst PHP can be a sprawling mess, at least it’ll be neatly packaged and reproducible.

This is where podman comes in to play.

What’s Podman?

Podman runs processes like docker but it’s arguably more secure by default.

Podman is a daemonless, open source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using containers.
Podman documentation

If you really care about security, read Docker Daemon Attack Surface.

Running Grocy in a container

Podman wants Grocy to be put inside a container. Luckily, this work has already been done for us by linuxserver.io. The instructions in this section are adopted from their docker page.

After installing podman, you should just be able to run Grocy like this:

# /home/krish/grocy/mnt on host will be /config in container 
mkdir -p /home/krish/grocy/mnt

podman run --detach \
	 --name=grocy \
	 -e PUID=1000 \
	 -e PGID=1000 \
	 -e TZ=Etc/UTC \
	 -p 9283:80 \
	 -v /home/krish/grocy/mnt:/config \
	 --restart unless-stopped  \
	 lscr.io/linuxserver/grocy:latest

Verify that this is correctly configured by visiting http://localhost:9283.

Cloudflare Tunnels?

PSA: “Cloudflare Tunnels” used to be called “Argo tunnels”. These names refer to the same service.

Like with all cloud service providers, cloudflare obfuscates their services with brand names as if to say “The Cloudflare Zero Trust Tunnel is so much more than a reverse proxy”. But yeah, it’s a reverse proxy. It effectively allows you to access your previous web server from anywhere on the internet.

The conventional way to self-host your web server would involve DNS, static IP addresses, certificates and all the rest of it. By using a proxy, we can sidestep all of this work.

Follow through cloudflare’s tutorials on setting up a Cloudflare Tunnel. It’ll direct you through a form which results in you pasting a command like this into your console:

sudo cloudflared service install <<your token here>>

At this point you should be able to access grocy online.

Making podman start on boot

Ok so sudo cloudflared service install by default enables cloudflare to run on boot, but we also need to setup grocy to run on boot.

podman generate systemd --new --name grocy  >grocy-podman.service:
mv grocy-podman.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable grocy-podman.service
# systemctl enable should print "Created symlink ... -> ..."
systemctl --user start grocy-podman.service

# allow running systemd stuff before your user has logged in
sudo loginctl enable-linger

Shortcuts I’ve taken

Our current setup has Grocy inside the container, and cloudflared outside the container. For perfect reproducibility, you’d want them both to be inside the container.

It’s probably possible to build your own container on top of linuxserver/grocy:latest, with a Dockerfile like this:

FROM lscr.io/linuxserver/grocy:latest
CMD  ./install_cloudflare
COPY /path/to/cloudflare/credentials/on/host /path/in/container

I haven’t yet had problems yet with my setup, so I’ll save myself from prematurely optimizing.