Self-hosted personal photo gallery — FastAPI + React, single image.
875
Self-hosted personal photo gallery. FastAPI + SQLite on the backend, React +
graphql-request on the frontend, packaged as a single container serving
both /api/* (FastAPI) and /* (the built SPA) on port 8000.
Source: https://gitlab.com/toopy/gallery-me
GALLERY_ACCOUNT_EMAIL.gallery.zip of the filtered set./me).docker run -d \
--name gallery-me \
-p 8000:8000 \
-v $(pwd)/data:/data \
-e SECRET_KEY="$(openssl rand -hex 32)" \
-e MAGIC_LINK_BASE_URL=http://localhost:8000 \
-e SMTP_HOST=smtp.example.com \
-e SMTP_PORT=587 \
-e [email protected] \
-e SMTP_PASSWORD=app-password \
-e [email protected] \
-e EMAIL_CONSOLE=false \
-e [email protected] \
toopy/gallery-me:latest
Open http://localhost:8000/, enter the same email, click the link the
backend emails you, and you're in. Alembic migrations run on container start
against the SQLite file under /data, so the first run just works.
For a docker-compose setup with sensible defaults (incl. a local SMTP
catcher), see the
stack in the repo.
| Path | Purpose |
|---|---|
/data | Image bytes + SQLite database + variant cache. Persist this one. |
The image runs as uid 0 in this entrypoint; if you bind-mount ./data
make sure it's writable.
The container reads pydantic-settings (env vars, case-insensitive). Required
vars have no sensible default and the app refuses to boot without them.
| Variable | Default | Purpose |
|---|---|---|
SECRET_KEY | (dev placeholder — change!) | Session signing key. Use openssl rand -hex 32. |
COOKIE_SECURE | false | Set true when serving behind HTTPS. |
CORS_ORIGINS | http://localhost:5173,… | Comma-separated CORS allow-list (only matters cross-origin). |
| Variable | Default | Purpose |
|---|---|---|
SMTP_HOST | localhost | Outbound SMTP host. |
SMTP_PORT | 1025 | Outbound SMTP port. |
SMTP_USER / SMTP_PASSWORD | (empty) | Auth credentials. |
SMTP_FROM | [email protected] | From address used for magic-link emails. |
EMAIL_CONSOLE | true | Dev fallback: also print the magic link to stdout. Set false in prod. |
MAGIC_LINK_BASE_URL | http://localhost:8080 | Origin used in the email link — must reach the running container. |
MAGIC_LINK_TTL_SECONDS | 900 | TTL of the magic link. |
GALLERY_ACCOUNT_EMAIL | (empty) | If set, only this address can request a magic link. Everyone else is silently dropped. |
| Variable | Default | Purpose |
|---|---|---|
DATABASE_URL | sqlite+aiosqlite:////data/gallery_me.sqlite3 | DB connection string. |
GALLERY_DATA_DIR | /data | Root for images / archives / cache. |
GALLERY_CACHE_MAX_BYTES | 2147483648 (2 GiB) | LRU eviction cap for the variant cache. |
GALLERY_ALLOWED_WIDTHS | 160,320,480,800,1200,1600,2400 | Whitelisted resize widths. |
GALLERY_ALLOWED_FORMATS | jpeg,png,webp | Whitelisted explicit transcode targets. |
GALLERY_MAX_UPLOAD_BYTES | 52428800 (50 MiB) | Per-file upload cap. |
GALLERY_UNDO_BUFFER_SIZE | 100 | Per-user cap on rotate/resize undo entries. |
| Variable | Default | Purpose |
|---|---|---|
INFOMANIAK_API_KEY | (empty) | Env-level fallback. Per-user keys on /me take precedence. |
INFOMANIAK_PRODUCT_ID | (empty) | Env-level fallback. |
INFOMANIAK_CHAT_MODEL | google/gemma-4-31B-it | Default vision model identifier. |
INFOMANIAK_MAX_TAGS_PER_IMAGE | 8 | Cap on the tag list per image. |
INFOMANIAK_MAX_IMAGE_EDGE_PX | 1024 | Pillow downsample target before sending to the model. |
INFOMANIAK_TIMEOUT_SECONDS | 30 | Per-request httpx timeout. |
With both INFOMANIAK_API_KEY and INFOMANIAK_PRODUCT_ID empty the in-process
tagging runtime loads NoOpChatClient — the rest of the app boots and works
fine, only tag suggestion is disabled.
| Tag | Built from |
|---|---|
toopy/gallery-me:latest | main branch pipelines. |
toopy/gallery-me:<short-sha> | Feature-branch pipelines (8-char commit SHA). |
The GitLab pipeline that publishes this image lives at
/.gitlab-ci.yml
(publish:backend job).
Source: https://gitlab.com/toopy/gallery-me. Issues and merge requests welcome.
Content type
Image
Digest
sha256:ca38d7eea…
Size
86.5 MB
Last updated
5 months ago
docker pull toopy/gallery-me