From 4e439f3f0a3f33cb79fe39b1dd40cba5171a2e8e Mon Sep 17 00:00:00 2001 From: ralksta Date: Sat, 14 Feb 2026 10:34:54 +0100 Subject: [PATCH] docs: rewrite README with full feature list, expand Docker section, use port 7211 --- Dockerfile | 6 +- README.md | 191 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 161 insertions(+), 36 deletions(-) diff --git a/Dockerfile b/Dockerfile index b735b47..6015440 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,12 +30,12 @@ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static USER nextjs -EXPOSE 3000 +EXPOSE 7211 -ENV PORT=3000 +ENV PORT=7211 ENV HOSTNAME="0.0.0.0" HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ - CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1 + CMD wget --no-verbose --tries=1 --spider http://localhost:7211/api/health || exit 1 CMD ["node", "server.js"] diff --git a/README.md b/README.md index 4b358a1..9f55003 100644 --- a/README.md +++ b/README.md @@ -6,25 +6,43 @@ Immich Folio acts as a **secure reverse proxy** between your visitors and your p ## Features -- **Portfolio-style navigation** — horizontal nav bar with all your collections -- **Split hero homepage** — configurable hero image with navigation links -- **Subpage grouping** — organize albums under named collections (e.g. `/japan/tokyo-2023`) -- **Masonry photo grid** — responsive layout with lightbox viewer -- **EXIF metadata** — camera, lens, and settings displayed on demand -- **Aggressive caching** — configurable TTL for fast repeat loads +### Gallery & Layout -## Security +- **Split hero homepage** — full-height hero with site title, subtitle, and navigation links on the left; hero image on the right +- **Hero image carousel** — single image or crossfade carousel of multiple Immich assets +- **Masonry photo grid** — responsive layout with natural aspect ratios and configurable columns, gap, and aspect ratio +- **Uniform grid mode** — switch to a fixed-aspect uniform grid per-subpage or globally +- **Per-subpage grid overrides** — each subpage can define its own columns, gap, aspect ratio, and layout mode +- **Fullscreen lightbox** — keyboard and swipe navigation, EXIF panel, adjacent image preloading +- **EXIF metadata on hover** — camera body, lens, focal length, aperture, shutter speed, ISO shown directly on the grid +- **ThumbHash placeholders** — instant blurred previews while full images load -Immich Folio adds a full security layer between the public internet and your Immich instance: +### Content & Organization + +- **Subpage grouping** — organize albums into named collections (e.g. `/japan/tokyo-2023`) +- **Auto-generated slugs** — URL slugs derived from album names automatically +- **YAML gallery config** — all gallery structure defined in a single `content/gallery.yaml` file +- **Markdown about page** — `content/about.md` with frontmatter for portrait, name, location, and gear list +- **Dynamic OG images** — auto-generated social preview images per album + +### Security | Concern | Protection | -|---------|-----------| +|---------|-----------| | **Server exposure** | Immich URL and port are never sent to the browser — all requests are proxied server-side | | **API key** | Stored only in `.env.local`, never included in client-side code or responses | | **Asset IDs** | Immich UUIDs are encrypted (AES-256) into opaque tokens — visitors cannot guess or enumerate asset IDs | -| **Album scope** | Only albums explicitly listed in `LIGHTBOX_ALBUMS` are accessible — everything else is blocked | +| **Album scope** | Only albums explicitly listed in `gallery.yaml` are accessible — everything else is blocked | +| **Password protection** | Individual subpages can require a password before content is revealed | +| **Rate limiting** | Per-IP sliding-window rate limiter on the image proxy (configurable RPM) | | **No direct access** | Visitors interact only with the Next.js app; they have zero knowledge of your Immich server's existence | +### Infrastructure + +- **Health check endpoint** — `GET /api/health` for uptime monitoring and container orchestration +- **In-memory caching** — configurable TTL for Immich API responses +- **Standalone Docker image** — multi-stage build, runs as non-root, ~150 MB + ## Quick Start ```bash @@ -35,7 +53,10 @@ npm install # Configure cp .env.local.example .env.local -# Edit .env.local with your Immich server details +# Edit .env.local with your Immich server URL and API key + +cp content/gallery.yaml.example content/gallery.yaml +# Edit gallery.yaml with your album UUIDs # Run npm run dev @@ -43,43 +64,147 @@ npm run dev ## Configuration -All configuration is done via environment variables in `.env.local`: +### Environment Variables (`.env.local`) ```env # Required IMMICH_API_URL=http://your-immich-server:2283 IMMICH_API_KEY=your-api-key -# Albums to publish (comma-separated UUIDs, optional labels) -LIGHTBOX_ALBUMS=Wedding:uuid-1, Vacation:uuid-2 - -# Group albums into subpages (one per line, wrap in quotes) -LIGHTBOX_SUBPAGES=" -Japan > uuid-tokyo, uuid-kyoto -Italy > uuid-rome, uuid-florence -" - # Optional -SITE_TITLE=My Portfolio -SITE_SUBTITLE=Photography -HERO_IMAGE=asset-uuid-for-homepage -CACHE_TTL=300 +SITE_TITLE=My Photography # default: "Gallery" +SITE_SUBTITLE=A visual journal # default: empty +CACHE_TTL=300 # seconds, default: 300 +RATE_LIMIT_RPM=120 # requests/min/IP, default: 120 +``` + +### Gallery Config (`content/gallery.yaml`) + +```yaml +# Hero image(s) — single UUID or list for carousel +hero: 00000000-0000-0000-0000-000000000000 +# hero: +# - uuid-1 +# - uuid-2 + +# Standalone albums on the homepage +albums: + - 11111111-1111-1111-1111-111111111111 + - 22222222-2222-2222-2222-222222222222 + +# EXIF on hover (default: true) +# exifOnHover: false + +# Global grid layout +# grid: +# columns: 3 +# gap: 12 +# aspectRatio: "1" +# layout: masonry # "masonry" or "uniform" + +# Subpages — group albums into collections +subpages: + - name: Japan + grid: + columns: 4 + layout: uniform + aspectRatio: "3/2" + albums: + - uuid-tokyo + - uuid-kyoto + + - name: Wedding – Smith + password: clientpass123 + albums: + - uuid-wedding +``` + +See `content/gallery.yaml.example` for the full reference. + +### About Page (`content/about.md`) + +```markdown +--- +portrait: asset-uuid +name: Your Name +location: City, Country +gear: + - Camera Body + - Favorite Lens +--- + +Your bio text here. +``` + +## Docker + +### Docker Compose (recommended) + +```yaml +services: + lightbox: + build: . + container_name: immich-folio + restart: unless-stopped + ports: + - "7211:7211" + env_file: + - .env.local + volumes: + - ./content:/app/content:ro +``` + +Run with: + +```bash +docker compose up -d +``` + +The gallery will be available at `http://localhost:7211`. + +### Standalone Docker + +```bash +# Build +docker build -t immich-folio . + +# Run +docker run -d \ + --name immich-folio \ + --restart unless-stopped \ + -p 7211:7211 \ + --env-file .env.local \ + -v ./content:/app/content:ro \ + immich-folio +``` + +> **Note:** The `content/` volume mount lets you update `gallery.yaml` and `about.md` without rebuilding the image. + +### Health Check + +The container includes a built-in health check at `/api/health`: + +```bash +curl http://localhost:7211/api/health +``` + +### Reverse Proxy + +Put Immich Folio behind nginx / Caddy / Traefik with TLS. Example Caddy config: + +``` +photos.example.com { + reverse_proxy localhost:7211 +} ``` ## Tech Stack -- **Next.js 16** (App Router) +- **Next.js 16** (App Router, standalone output) - **React 19** - **TypeScript** - **Vanilla CSS** (no framework) -## Docker - -```bash -docker build -t immich-folio . -docker run -p 3000:3000 --env-file .env.local immich-folio -``` - ## License Private — all rights reserved.