Backups
One file matters. How to copy it safely while the thing is running.
One file matters: queries.db. Everything else in the install directory can be rewritten from the wiki in two minutes.
queries.db-wal0 transactions not yet in the .db
queries.dbeverything up to the last checkpoint
cp queries.db backup.db → misses whatever is sitting in the -wal
Hot backup, container running#
SQLite’s own backup command takes a consistent snapshot while the database is being written to:
sudo docker exec elele-dns \
sqlite3 /data/queries.db ".backup '/data/backup.db'"
sudo cp /opt/elele-dns/data/backup.db ~/elele-$(date +%F).dbCold backup, container stopped#
cd /opt/elele-dns
sudo docker compose down
sudo cp data/queries.db ~/elele-$(date +%F).db
sudo docker compose up -dA clean shutdown checkpoints the WAL into the main file, so after down the single .db is complete on its own.
Restoring#
cd /opt/elele-dns
sudo docker compose down
sudo cp ~/elele-2026-08-01.db data/queries.db
sudo rm -f data/queries.db-wal data/queries.db-shm
sudo docker compose up -dDeleting the stale -wal and -shm alongside is the step people miss; leaving them next to a restored database is how you get a file that opens and then behaves strangely.
How big is it#
| History | Rows | Roughly |
|---|---|---|
| 7 days | ~250k | 60–90MB |
| 30 days | ~1M | 150–250MB |
| 90 days | ~3M | 300–500MB |
| Rollups only, per year | ~500k | 40–60MB, and it never gets pruned |
Indexes are about a fifth of that. The store is deliberately index-heavy: it is the difference between a device page rendering in 40ms and in four seconds.
What is not worth backing up#
- The vendored enrichment datasets. They are 45MB, they are re-downloadable, and they are rebuilt by
npm run datasets:fetch. .env, unless you would rather not retype three valuestwo values. It contains a password, so if you do keep a copy, keep it somewhere that deserves one.- AdGuard HomePi-hole’s own data directory, at least not for this product’s sake. Its log is the source, and everything read out of it is already in
queries.db. Back it up for AdGuardPi-hole’s sake — your filter lists and client names live thereyour groups, adlists and local DNS records live there — on whatever schedule you already use for it.