Is a server of your own the right home for Grocy?
Yes, if you want it reachable from everyone's phone without leaving a home computer switched on. Grocy keeps track of what is in the cupboards and when it goes off, builds the shopping list from minimum stock amounts, plans meals from your recipes, and reminds people whose turn the chores are. It is a hobby project by Bernd Bestel, and its author describes it as technically a pretty simple PHP application.
Simple is good news for you. There is no separate database program to look after: Grocy stores everything in an SQLite file. If you only ever use it on one Windows PC, the project's own Grocy Desktop app is the easier choice. A server earns its keep once several people, in different places, need the same list. Keeping household money in order too? Firefly III runs on the same kind of machine.
What you'll be running
- PHP 8.5, paired with SQLite 3.40 or later. Since Grocy 4.6.0 this is the only version the project supports, so older PHP will not do.
- PHP extensions mbstring, intl, gd, pdo_sqlite, fileinfo, ctype and zlib.
- A web server whose root points at Grocy's
publicfolder. On nginx you add onetry_filesline, shown in the install below. - A writable
datafolder, which holds your settings, the database and any files you upload. - A current browser: Firefox, Chrome or Edge, on a laptop or a phone.
The project doesn't publish a minimum for processor, memory or disk, so we won't invent one. Your real decision is the operating system. Ubuntu 26.04 LTS is the release to pick, because PHP 8.5 comes from its standard packages; earlier Ubuntu versions come with an older PHP that current Grocy no longer supports.
The server that fits
A family's Grocy is one small job, and one small job is what our compact cartridge servers are for: a whole machine of your own, cheaper than a big VPS, where nobody else's workload slows yours down. The smallest is our micro server. On every machine in the dedicated server list you log in as root, nobody meters the port, and there's no contract: you can cancel when any month ends.
Choose an x86 server and pick Ubuntu 26.04 when you order, checking it is on that server's list. Skip the ARM cartridge: Ubuntu 18.04 is the newest it can install, and that release cannot give Grocy the PHP it wants. A ready server is handed over within 30 minutes of the payment being approved; a custom build takes between 4 and 24 hours when we hold the parts. You manage the server; we keep the hardware and the network running.
Up and running in an evening
Log in over SSH and work through these in order. The first three lines put a firewall up that lets only SSH in, and they cover IPv6 too, not just IPv4: ufw has to be told about IPv6 before you add a rule, and --force stops its yes/no question from eating the next line you paste.
sudo sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw
sudo ufw allow 22/tcp
sudo ufw --force enable
sudo apt update
sudo apt install -y nginx php8.5-fpm php8.5-sqlite3 php8.5-gd php8.5-intl php8.5-mbstring unzip wget sqlite3
php -v
sudo mkdir -p /var/www/grocy
cd /var/www/grocy
sudo wget -O grocy.zip https://releases.grocy.info/latest
sudo unzip -q grocy.zip && sudo rm grocy.zip
sudo cp config-dist.php data/config.php
sudo chown -R www-data:www-data /var/www/grocy/data
sudo tee /etc/nginx/sites-available/grocy >/dev/null <<'EOF'
server {
listen 127.0.0.1:8095;
root /var/www/grocy/public;
index index.php;
location / {
try_files $uri /index.php$is_args$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/grocy /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
- Check that
php -vreports 8.5. Thefileinfo,ctypeandzlibextensions are part of the base PHP package, so they need no install of their own. - The zip unpacks into
/var/www/grocy. Your settings file isdata/config.php; open it to set your currency and language, and to hide whole areas you'll never use, such as batteries or equipment, with their feature flags. - Only the
datafolder belongs to the web server user. Everything else stays owned by root. - The block ends by saving Grocy's nginx site as
/etc/nginx/sites-available/grocy, switching it on, and reloading nginx oncenginx -tapproves the syntax.
Change admin/admin before anyone else can see it
Every new Grocy starts with the same account, user admin and password admin, and the README tells you to change it right away. That's why the nginx site you just created serves Grocy on a private address, 127.0.0.1 port 8095, that only the server itself can reach.
- On your own computer, run
ssh -N -L 8095:127.0.0.1:8095 you@your-server, signing in as yourself. While that window stays open,http://localhost:8095on your computer is Grocy on the server. - Sign in as admin/admin, open the user menu in the top right corner, and replace that password with a long, unique one.
- Add a login for each member of the household. Watch the permissions: by default (
DEFAULT_PERMISSIONSisADMIN) every new user is an administrator.
Opening it to the household over HTTPS
Once the password is yours, give Grocy a name in DNS, for example grocy.example.com. In the nginx file, swap listen 127.0.0.1:8095; for listen 80; and listen [::]:80; and add server_name grocy.example.com;. Next, ufw allow 80,443/tcp (as root) lets web traffic in; nginx runs directly on the server, so ufw would otherwise turn visitors away over both IPv4 and IPv6. Add certbot and the python3-certbot-nginx package that teaches it nginx, and sudo certbot --nginx -d grocy.example.com fetches a free Let's Encrypt certificate and switches the site to HTTPS.
HTTPS matters for more than privacy. Scanning a barcode with your phone's camera runs entirely inside the browser, offline, and browsers only allow it on a secure connection. Grocy's author still recommends a cheap USB barcode scanner for speed. When a code is new to Grocy, it can look the product up on Open Food Facts; if you'd rather nothing leaves your server, set STOCK_BARCODE_LOOKUP_PLUGIN to an empty value.
On phones, Grocy installs to the home screen as a web app; it needs a connection, as it has no offline mode. The grocy.info site names two apps as well: Grocy Mobile for iPhone, iPad and Mac, and Grocy Android. Both come from the community rather than the Grocy project.
Keeping your stock list safe
Everything that matters is in /var/www/grocy/data: config.php, the database grocy.db, and a storage folder with pictures and files you've uploaded. Don't just copy grocy.db while Grocy is in use, because you could catch it mid-write. Either stop PHP with sudo systemctl stop php8.5-fpm while you copy, or let SQLite make the copy safely while the app keeps running. The nightly job below does the second:
sudo mkdir -m 700 -p /var/backups/grocy
sudo tee /usr/local/sbin/grocy-backup >/dev/null <<'EOF'
set -e
umask 077
d=/var/backups/grocy/$(date +%F)
mkdir -p "$d"
sqlite3 /var/www/grocy/data/grocy.db ".backup '$d/grocy.db'"
tar -czf "$d/data.tgz" -C /var/www/grocy --exclude='data/grocy.db*' --exclude=data/viewcache --exclude=data/backups data
EOF
Now tell cron to run it every night at 03:20:
echo '20 3 * * * root /bin/bash /usr/local/sbin/grocy-backup > /var/backups/grocy/last-run.log 2>&1' | sudo tee /etc/cron.d/grocy-backup
Each night gets its own dated folder, readable by root only, and the last run's output is kept in last-run.log. Old folders are not deleted for you. Copy them to a computer somewhere else too: backups that sit on the server's own disk vanish with it. Inside each folder you'll find two files, since the database travels separately from the rest: grocy.db and data.tgz. When you need one back, work through these steps:
- Name the night you want in a shell variable, for example
DIR=/var/backups/grocy/2026-10-22. - Make sure both files are there and not empty:
sudo test -s "$DIR/grocy.db" && sudo test -s "$DIR/data.tgz" && echo ok. Carry on only when you see ok. - Now stop PHP, so nothing writes while you restore:
sudo systemctl stop php8.5-fpm. - Unpack the rest of the folder into place with
sudo tar -xzf "$DIR/data.tgz" -C /var/www/grocy. - If
datastill holds the live database's companion files,grocy.db-walandgrocy.db-shm, delete them; then put the saved database back:sudo cp "$DIR/grocy.db" /var/www/grocy/data/. - Return ownership to the web server with
cd /var/www/grocy && sudo chown --recursive www-data:www-data data, then bring PHP back:sudo systemctl start php8.5-fpm.
Staying current
Upgrading means unpacking each new release on top of the current files while your data folder stays put. Grocy ships update.sh for that: cd /var/www/grocy && sudo bash update.sh runs it (it needs wget and unzip). Before it downloads anything it packs the current install into a .tgz under data/backups and clears out archives older than 60 days. Be aware that it wipes everything else in that folder apart from data and itself.
Then do one thing that is our addition, not part of update.sh: run cd /var/www/grocy && sudo chown --recursive www-data:www-data data. Because the script runs with root rights, whatever it writes ends up owned by root, and Grocy could no longer save to its own folder. After that, open Grocy: the database upgrades itself when it sees a new version. Read each release's changelog first, because some carry a warning; 4.7.0, for instance, asked you to check your AUTH_CLASS setting. And look in config-dist.php for new options worth copying into your own config.php.
Questions people ask
- Is there an official Grocy Docker image?
- No. The README sends Docker users to
linuxserver/grocy, which grocy.info labels a community contribution, so LinuxServer.io maintains it, not the Grocy project. If you go that way anyway, bind its port to 127.0.0.1. A bare port mapping opens on all of the server's IPv4 and IPv6 addresses, and Docker routes IPv4 to the container before ufw ever checks it (IPv6 as well, when Docker handles IPv6 itself). Docker Engine 28 and later keep a 127.0.0.1-bound mapping private to the server, and your nginx can proxy to it. - What username and password does Grocy start with?
adminandadmin. Change that password before the site gets a public address, signing in through SSH port forwarding to the private 127.0.0.1 port, as shown above.- Which licence is Grocy released under?
- The MIT License, so you can run it, change it and share it freely. Help comes from the community on Reddit's r/grocy and the GitHub issue tracker; the author asks people not to contact him privately.
- Can Grocy run inside a folder of my existing website?
- Yes. Point
BASE_URLandBASE_PATHat the subfolder in your config file. A hostname of its own, like grocy.example.com, keeps the setup simpler. - Why does Grocy refuse to start on my older server?
- Current releases support PHP 8.5 only, together with SQLite 3.40 or later. An operating system that packages an older PHP will not run them, while Ubuntu 26.04 has it.