docs: rewrite README with full feature list, expand Docker section, use port 7211
This commit is contained in:
@@ -30,12 +30,12 @@ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|||||||
|
|
||||||
USER nextjs
|
USER nextjs
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 7211
|
||||||
|
|
||||||
ENV PORT=3000
|
ENV PORT=7211
|
||||||
ENV HOSTNAME="0.0.0.0"
|
ENV HOSTNAME="0.0.0.0"
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
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"]
|
CMD ["node", "server.js"]
|
||||||
|
|||||||
191
README.md
191
README.md
@@ -6,25 +6,43 @@ Immich Folio acts as a **secure reverse proxy** between your visitors and your p
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Portfolio-style navigation** — horizontal nav bar with all your collections
|
### Gallery & Layout
|
||||||
- **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
|
|
||||||
|
|
||||||
## 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 |
|
| Concern | Protection |
|
||||||
|---------|-----------|
|
|---------|-----------|
|
||||||
| **Server exposure** | Immich URL and port are never sent to the browser — all requests are proxied server-side |
|
| **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 |
|
| **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 |
|
| **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 |
|
| **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
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -35,7 +53,10 @@ npm install
|
|||||||
|
|
||||||
# Configure
|
# Configure
|
||||||
cp .env.local.example .env.local
|
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
|
# Run
|
||||||
npm run dev
|
npm run dev
|
||||||
@@ -43,43 +64,147 @@ npm run dev
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
All configuration is done via environment variables in `.env.local`:
|
### Environment Variables (`.env.local`)
|
||||||
|
|
||||||
```env
|
```env
|
||||||
# Required
|
# Required
|
||||||
IMMICH_API_URL=http://your-immich-server:2283
|
IMMICH_API_URL=http://your-immich-server:2283
|
||||||
IMMICH_API_KEY=your-api-key
|
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
|
# Optional
|
||||||
SITE_TITLE=My Portfolio
|
SITE_TITLE=My Photography # default: "Gallery"
|
||||||
SITE_SUBTITLE=Photography
|
SITE_SUBTITLE=A visual journal # default: empty
|
||||||
HERO_IMAGE=asset-uuid-for-homepage
|
CACHE_TTL=300 # seconds, default: 300
|
||||||
CACHE_TTL=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
|
## Tech Stack
|
||||||
|
|
||||||
- **Next.js 16** (App Router)
|
- **Next.js 16** (App Router, standalone output)
|
||||||
- **React 19**
|
- **React 19**
|
||||||
- **TypeScript**
|
- **TypeScript**
|
||||||
- **Vanilla CSS** (no framework)
|
- **Vanilla CSS** (no framework)
|
||||||
|
|
||||||
## Docker
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t immich-folio .
|
|
||||||
docker run -p 3000:3000 --env-file .env.local immich-folio
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Private — all rights reserved.
|
Private — all rights reserved.
|
||||||
|
|||||||
Reference in New Issue
Block a user