Layer docker-compose.gpu.yml to mount /dev/dri/{card0,renderD128}
into pp-app, add it to render (992) + video (44) groups, and set
PHOTOPRISM_FFMPEG_ENCODER=vaapi. Hosts without a VA-API device just
skip the overlay (`-f docker-compose.yml -f docker-compose.gpu.yml`
becomes opt-in per deploy).
Drops video transcode + thumbnail generation from CPU to the iGPU
where present — large win for HEVC libraries. README documents the
flag; default behavior on the base compose is unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141 lines
6.1 KiB
Markdown
141 lines
6.1 KiB
Markdown
# mule-image
|
|
|
|
Self-hosted photo management built on top of [PhotoPrism][pp]. A SvelteKit
|
|
frontend ([`web/`](web/)) plus a small Go service ([`sidecar/`](sidecar/))
|
|
fill in the keyboard-driven UI and the file/folder/mark endpoints
|
|
PhotoPrism's REST API does not expose. PhotoPrism itself handles
|
|
indexing, originals, thumbnails, and the database; we never re-implement
|
|
those.
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
┌──────────────────┐ /api/v1/* ┌──────────────┐
|
|
│ SvelteKit web/ │ ───────────────▶ │ photoprism │ ──▶ mariadb
|
|
│ (Vite : 5173) │ /api/sidecar/* │ :2342 │
|
|
│ │ ─────────┐ └──────────────┘
|
|
└──────────────────┘ ▼
|
|
┌──────────────┐
|
|
│ sidecar │ ──▶ mariadb (mule_sidecar.*)
|
|
│ :8000 │ ──▶ originals FS (rename / folders / dups)
|
|
└──────────────┘
|
|
```
|
|
|
|
Three compose services — `mariadb`, `photoprism`, `sidecar` — plus the
|
|
SvelteKit `web/` app served separately. PhotoPrism's port `2342` is
|
|
**bound to `127.0.0.1` only**; it isn't a user-facing surface. The
|
|
SvelteKit app is.
|
|
|
|
What the sidecar adds on top of PhotoPrism (full list in
|
|
[`sidecar/README.md`](sidecar/README.md)):
|
|
|
|
- Per-photo marks (rating + color) persisted to `mule_sidecar.marks`
|
|
- File rename + folder create/rename/delete with PhotoPrism reindex
|
|
- Heap (album) → folder conversion
|
|
- Perceptual-hash duplicate scan + archive
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# edit .env: set PHOTO_DIRS to the host path holding your library
|
|
# rotate PP_ADMIN_PASSWORD, PP_DB_PASSWORD, PP_DB_ROOT_PASSWORD
|
|
# before any non-local deployment.
|
|
|
|
podman-compose --env-file .env \
|
|
-f docker-compose.yml \
|
|
-f docker-compose.podman.yml \
|
|
up -d
|
|
```
|
|
|
|
Then serve the frontend. For local use the simplest path is the Vite
|
|
dev server:
|
|
|
|
```bash
|
|
cd web
|
|
npm install
|
|
npm run dev
|
|
# open http://localhost:5173
|
|
```
|
|
|
|
For a static deployment, `npm run build` produces a bundle under
|
|
`web/build/` that any static file host (nginx, Caddy, GitHub Pages-style)
|
|
can serve. Reverse-proxy `/api/v1/*` to `http://127.0.0.1:2342` and
|
|
`/api/sidecar/*` to `http://127.0.0.1:8000`.
|
|
|
|
PhotoPrism's own UI is still reachable from the host at
|
|
`http://127.0.0.1:2342` if you need admin features (user management,
|
|
settings) — set up an SSH tunnel from your laptop if the server is
|
|
remote.
|
|
|
|
## Configuration
|
|
|
|
All knobs live in [`.env.example`](.env.example). The required ones:
|
|
|
|
| Variable | Notes |
|
|
|----------------------|-----------------------------------------------------------------------------------------------|
|
|
| `PHOTO_DIRS` | Host path mounted at `/photoprism/originals`. The library. |
|
|
| `PP_ADMIN_PASSWORD` | First-boot admin password. Rotate. |
|
|
| `PP_DB_PASSWORD` | MariaDB password for the `photoprism` user. Rotate. |
|
|
| `PP_DB_ROOT_PASSWORD`| MariaDB root password. Rotate. |
|
|
| `PP_UID` / `PP_GID` | Host UID/GID that owns `PHOTO_DIRS`. PhotoPrism + sidecar drop to this user inside. |
|
|
| `PP_PORT` | Loopback host port for PhotoPrism (default `2342`). |
|
|
| `PP_ORIGINALS_MODE` | `rw` (default) or `ro` — see [Read-only libraries](#read-only-libraries). |
|
|
| `SIDECAR_PORT` | Loopback host port for the sidecar (default `8000`). |
|
|
|
|
Sidecar-specific env (DB DSN, `USER_BASEPATHS`, etc.) is documented in
|
|
[`sidecar/README.md`](sidecar/README.md).
|
|
|
|
## Read-only libraries
|
|
|
|
The default originals mount is `:rw` because file operations (rename,
|
|
folder mutations, duplicate archive, heap convert) need to mutate the
|
|
filesystem. To run against a read-only archive, set
|
|
`PP_ORIGINALS_MODE=ro` in `.env`. Browsing, marks, ratings, and color
|
|
labels still work; the following sidecar endpoints return an OS error:
|
|
|
|
- `POST /api/sidecar/files/:uid/rename`
|
|
- `POST /api/sidecar/folders` / `:rel/rename` / `DELETE /:rel`
|
|
- `POST /api/sidecar/albums/:uid/convert`
|
|
- `POST /api/sidecar/duplicates/archive`
|
|
|
|
PhotoPrism's `PHOTOPRISM_READONLY` is controlled separately by
|
|
`PP_READONLY` and gates its own backwrite / import paths.
|
|
|
|
## Dev iteration loop
|
|
|
|
For fast iteration on the sidecar without rebuilding its image on every
|
|
change, run it as a host process — bring up just `mariadb` and
|
|
`photoprism` from compose, then build and run the Go binary locally.
|
|
Full instructions in [`sidecar/README.md`](sidecar/README.md#dev-iteration-loop-host-build).
|
|
|
|
## Layout
|
|
|
|
```text
|
|
.
|
|
├── docker-compose.yml base stack: mariadb + photoprism + sidecar
|
|
├── docker-compose.podman.yml rootless-podman overlay (keep-id mapping)
|
|
├── docker-compose.gpu.yml opt-in VA-API GPU passthrough overlay
|
|
├── .env.example required env vars (copy to .env)
|
|
├── mariadb/init/ first-boot SQL: creates mule_sidecar DB + user
|
|
├── pp/ PhotoPrism bind-mounted state (storage, import)
|
|
├── sidecar/ Go service — see sidecar/README.md
|
|
└── web/ SvelteKit frontend
|
|
```
|
|
|
|
## GPU video acceleration (optional)
|
|
|
|
Hosts with a VA-API-capable GPU (Intel iGPU, AMD APU, etc.) can layer
|
|
[`docker-compose.gpu.yml`](docker-compose.gpu.yml) to hand `/dev/dri/*`
|
|
to PhotoPrism and switch ffmpeg to hardware encode/decode — a large
|
|
perf win for video thumbnails and HEVC→H.264 transcodes:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
|
|
```
|
|
|
|
Set `PP_FFMPEG_ENCODER=vaapi` in `.env` (default for the overlay). Verify
|
|
with `docker exec pp-app photoprism show config | grep -i ffmpeg`.
|
|
|
|
[pp]: https://photoprism.app/
|