Let the data folders be set per install, database separately
DATA_DIR takes the files and PGDATA_DIR the database, so the database can stay on a filesystem that supports ownership when the files live on a disk that doesn't. The example .env points both at /Volumes/Data/printhive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
985b81d1de
commit
6c10cf6b37
4 changed files with 44 additions and 12 deletions
|
|
@ -2,5 +2,13 @@
|
||||||
DATABASE_URL=postgres://USER@localhost:5432/stl_library
|
DATABASE_URL=postgres://USER@localhost:5432/stl_library
|
||||||
PORT=3000
|
PORT=3000
|
||||||
|
|
||||||
|
# Docker only: where data lives on the host. Both default to ./data beside
|
||||||
|
# docker-compose.yml. DATA_DIR takes the model files, thumbnails and previews.
|
||||||
|
DATA_DIR=/Volumes/Data/printhive
|
||||||
|
# The database is set separately, because Postgres needs a filesystem with real
|
||||||
|
# ownership and permissions — leave it on local disk if DATA_DIR is exFAT, FAT
|
||||||
|
# or a network share.
|
||||||
|
PGDATA_DIR=/Volumes/Data/printhive/pgdata
|
||||||
|
|
||||||
# Thingiverse import — get a free app token at https://www.thingiverse.com/developers
|
# Thingiverse import — get a free app token at https://www.thingiverse.com/developers
|
||||||
THINGIVERSE_TOKEN=
|
THINGIVERSE_TOKEN=
|
||||||
|
|
|
||||||
19
README.md
19
README.md
|
|
@ -59,17 +59,22 @@ Run the unit tests with `npm test`.
|
||||||
|
|
||||||
### Where your data lives
|
### Where your data lives
|
||||||
|
|
||||||
With Docker, everything sits in folders next to `docker-compose.yml` (set `DATA_DIR` to put them elsewhere):
|
With Docker, everything sits in folders on the host — `./data` beside `docker-compose.yml` unless `.env` says
|
||||||
|
otherwise (`DATA_DIR` for the files, `PGDATA_DIR` for the database):
|
||||||
|
|
||||||
| Folder | Holds |
|
| Folder | Holds |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `data/pgdata` | The database: models, tags, collections, watches, spools, printers, settings (tokens and printer access codes live here) |
|
| `$PGDATA_DIR` | The database: models, tags, collections, watches, spools, printers, settings (tokens and printer access codes live here) |
|
||||||
| `data/uploads` | Your model files, as uploaded or downloaded |
|
| `$DATA_DIR/uploads` | Your model files, as uploaded or downloaded |
|
||||||
| `data/thumbnails` | Generated pictures, including plate images |
|
| `$DATA_DIR/thumbnails` | Generated pictures, including plate images |
|
||||||
| `data/glb` | Converted 3D previews for the viewer |
|
| `$DATA_DIR/glb` | Converted 3D previews for the viewer |
|
||||||
| `data/extracted` | Files unpacked from archives — a cache |
|
| `$DATA_DIR/extracted` | Files unpacked from archives — a cache |
|
||||||
|
|
||||||
A backup needs `data/pgdata` (or a `pg_dump`) and `data/uploads`; the other three rebuild themselves. Everything else in
|
The database is set apart from the rest because Postgres needs a filesystem with real ownership and permissions —
|
||||||
|
ext4, xfs, APFS and the like. exFAT, FAT and most network shares won't do, so keep `PGDATA_DIR` on local disk if the
|
||||||
|
files live on one of those.
|
||||||
|
|
||||||
|
A backup needs the database (or a `pg_dump`) and `uploads`; the other three rebuild themselves. Everything else in
|
||||||
the container is replaced on each update, so nothing outside these folders is kept.
|
the container is replaced on each update, so nothing outside these folders is kept.
|
||||||
|
|
||||||
Upgrading from a version that used Docker named volumes: stop the stack, run `tools/volumes-to-folders.sh` to copy the
|
Upgrading from a version that used Docker named volumes: stop the stack, run `tools/volumes-to-folders.sh` to copy the
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,11 @@ services:
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-printhive}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-printhive}
|
||||||
POSTGRES_DB: printhive
|
POSTGRES_DB: printhive
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_DIR:-./data}/pgdata:/var/lib/postgresql/data
|
# Set separately from DATA_DIR: Postgres needs a filesystem with real
|
||||||
|
# ownership and permissions (ext4, xfs, APFS...), which exFAT, FAT and
|
||||||
|
# most network shares don't provide. Keep it on local disk if the files
|
||||||
|
# live somewhere like that.
|
||||||
|
- ${PGDATA_DIR:-./data/pgdata}:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U printhive -d printhive"]
|
test: ["CMD-SHELL", "pg_isready -U printhive -d printhive"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
|
|
@ -33,7 +37,7 @@ services:
|
||||||
MAKERWORLD_TOKEN: ${MAKERWORLD_TOKEN:-}
|
MAKERWORLD_TOKEN: ${MAKERWORLD_TOKEN:-}
|
||||||
PRINTABLES_TOKEN: ${PRINTABLES_TOKEN:-}
|
PRINTABLES_TOKEN: ${PRINTABLES_TOKEN:-}
|
||||||
volumes:
|
volumes:
|
||||||
# Folders on the host, under ./data (set DATA_DIR to put them elsewhere).
|
# Folders on the host: ./data unless DATA_DIR says otherwise.
|
||||||
# uploads and pgdata hold everything that matters; the other two rebuild.
|
# uploads and pgdata hold everything that matters; the other two rebuild.
|
||||||
- ${DATA_DIR:-./data}/uploads:/app/uploads
|
- ${DATA_DIR:-./data}/uploads:/app/uploads
|
||||||
- ${DATA_DIR:-./data}/thumbnails:/app/thumbnails
|
- ${DATA_DIR:-./data}/thumbnails:/app/thumbnails
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,23 @@
|
||||||
# again with nothing lost.
|
# again with nothing lost.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Same settings Compose uses, so the copy lands where the stack will look.
|
||||||
|
if [ -f .env ]; then
|
||||||
|
DATA_DIR="${DATA_DIR:-$(grep -E '^DATA_DIR=' .env | tail -1 | cut -d= -f2-)}"
|
||||||
|
PGDATA_DIR="${PGDATA_DIR:-$(grep -E '^PGDATA_DIR=' .env | tail -1 | cut -d= -f2-)}"
|
||||||
|
fi
|
||||||
DATA_DIR="${DATA_DIR:-./data}"
|
DATA_DIR="${DATA_DIR:-./data}"
|
||||||
|
PGDATA_DIR="${PGDATA_DIR:-./data/pgdata}"
|
||||||
VOLUMES=(pgdata uploads thumbnails glb extracted)
|
VOLUMES=(pgdata uploads thumbnails glb extracted)
|
||||||
|
|
||||||
|
# Where each volume's contents should end up.
|
||||||
|
target_for() {
|
||||||
|
case "$1" in
|
||||||
|
pgdata) echo "$PGDATA_DIR" ;;
|
||||||
|
*) echo "$DATA_DIR/$1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
# Compose names volumes "<project>_<name>", the project being this folder's name
|
# Compose names volumes "<project>_<name>", the project being this folder's name
|
||||||
# unless it's set elsewhere.
|
# unless it's set elsewhere.
|
||||||
PROJECT="${COMPOSE_PROJECT_NAME:-$(basename "$(pwd)")}"
|
PROJECT="${COMPOSE_PROJECT_NAME:-$(basename "$(pwd)")}"
|
||||||
|
|
@ -21,12 +35,13 @@ if docker compose ps --status running --quiet 2>/dev/null | grep -q .; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Project: $PROJECT"
|
echo "Project: $PROJECT"
|
||||||
echo "Copying into: $DATA_DIR"
|
echo "Files: $DATA_DIR"
|
||||||
|
echo "Database: $PGDATA_DIR"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
for name in "${VOLUMES[@]}"; do
|
for name in "${VOLUMES[@]}"; do
|
||||||
volume="${PROJECT}_${name}"
|
volume="${PROJECT}_${name}"
|
||||||
target="$DATA_DIR/$name"
|
target="$(target_for "$name")"
|
||||||
|
|
||||||
if ! docker volume inspect "$volume" >/dev/null 2>&1; then
|
if ! docker volume inspect "$volume" >/dev/null 2>&1; then
|
||||||
echo "· $volume — no such volume, skipping (nothing to copy)"
|
echo "· $volume — no such volume, skipping (nothing to copy)"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue