Keep the database in ./data and bind-mount it

SQLite writes three files — the database plus its -wal and -shm companions.
Putting them in one directory means a deployment mounts a single path and a
backup copies a single directory.

- FOODSTER_DB defaults to ./data/foodster.db, and openDB creates the parent
  directory on startup rather than failing on a fresh checkout
- compose bind-mounts ./data instead of using a named volume, so the file can
  be listed, copied and opened with any sqlite client without going through
  the container engine
- the image runs as UID 65534, which cannot write to a host directory owned
  by someone else, so compose now sets user: from FOODSTER_UID/FOODSTER_GID
- `make up` creates ./data first: left to the engine it appears root-owned
  and the app silently cannot write to it
This commit is contained in:
Esa Kataja
2026-09-05 18:17:14 +03:00
parent c9a63bdd9e
commit c6f44bb427
7 changed files with 45 additions and 15 deletions
+11 -1
View File
@@ -18,6 +18,7 @@ import (
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
@@ -36,7 +37,10 @@ var version = "dev"
const (
listenAddr = ":8080"
defaultTZ = "Europe/Helsinki"
defaultDB = "./foodster.db"
// Everything SQLite writes — the database plus its -wal and -shm
// companions — lives in one directory, so a deployment mounts a single
// path and a backup copies a single directory.
defaultDB = "./data/foodster.db"
// failDelay throttles password guessing.
// ponytail: a fixed sleep is enough for a LAN-only app; swap in
@@ -108,6 +112,12 @@ func run() error {
// openDB opens the SQLite file and brings its schema up to date.
func openDB(path string) (*sql.DB, error) {
if dir := filepath.Dir(path); dir != "." && dir != "" {
if err := os.MkdirAll(dir, 0o755); err != nil {
return nil, fmt.Errorf("create %s: %w", dir, err)
}
}
dsn := "file:" + path +
"?_pragma=journal_mode(WAL)" +
"&_pragma=foreign_keys(ON)" +