Lychee Documentation

A great looking and easy-to-use photo-management-system you can run on your server, to manage and share photos.

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy Lychee on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name lychee -p 8000:8000 --restart always ghcr.io/lycheeorg/lychee:latest
Configured Services & Ports
βš™οΈ lychee_api
image: ghcr.io/lycheeorg/lychee:latest
πŸ”Œ Ports: ${APP_PORT:-8000}:8000
βš™οΈ lychee_worker
image: ghcr.io/lycheeorg/lychee:latest
βš™οΈ lychee_db
image: mariadb:10
βš™οΈ lychee_facial_recognition
image: ghcr.io/lycheeorg/lychee-facial-recognition:latest
docker-compose.yml
yaml (docker-compose.yml)
# Docker Compose configuration for Lychee application with FrankenPHP backend
# Version: 2026-01-10

x-base-lychee-setup: &base-lychee-setup
  image: ghcr.io/lycheeorg/lychee:latest
  restart: unless-stopped  # Auto-restart at container level (outer layer)

  # Security hardening
  security_opt:
    - no-new-privileges:true
    - seccomp:unconfined  # FrankenPHP may need this; consider custom seccomp profile
  cap_drop:
    - ALL
  cap_add:
    - CHOWN
    - SETGID
    - SETUID
    - DAC_OVERRIDE
    - NET_BIND_SERVICE
  read_only: false  # Laravel needs write access to storage/cache
  tmpfs:
    - /tmp:noexec,nosuid,nodev,size=100m
  volumes:
    - ./lychee/uploads:/app/public/uploads
    - ./lychee/logs:/app/storage/logs
    - ./lychee/tmp:/app/storage/tmp
  networks:
    - lychee

x-common-env: &common-env
  PUID: "${PUID:-1000}"
  PGID: "${PGID:-1000}"
  # REPLACE ME WITH YOUR VALUE GENERATED WITH `openssl rand -base64 32`
  APP_KEY: "base64:ucMiFCbfQZUFOxrQz1x9C0OBJeLCCCAieZmnEHXmyGI="
  APP_NAME: "${APP_NAME:-Lychee}"
  APP_ENV: "${APP_ENV:-production}"
  APP_TIMEZONE: "${TIMEZONE:-UTC}"
  APP_URL: "${APP_URL:-http://localhost:8000}"
  APP_FORCE_HTTPS: "${APP_FORCE_HTTPS:-false}"
  DB_CONNECTION: "${DB_CONNECTION:-mysql}"
  DB_HOST: "${DB_HOST:-lychee_db}"
  DB_PORT: "${DB_PORT:-3306}"
  DB_DATABASE: "${DB_DATABASE:-lychee}"
  DB_USERNAME: "${DB_USERNAME:-lychee}"
  DB_PASSWORD: "${DB_PASSWORD:-password}"
  SESSION_DRIVER: "${SESSION_DRIVER:-file}"
  SESSION_LIFETIME: "${SESSION_LIFETIME:-120}"
  QUEUE_CONNECTION: "${QUEUE_CONNECTION:-database}"
  AI_VISION_ENABLED: "${AI_VISION_ENABLED:-true}"
  AI_VISION_FACE_API_KEY: "${AI_VISION_API_KEY:-changeme}"
  AI_VISION_FACE_URL: "http://lychee_facial_recognition:8000"

services:
  lychee_api:
    <<: *base-lychee-setup
    container_name: lychee-api
    expose:
      - "${APP_PORT:-8000}"
    ports:
      - "${APP_PORT:-8000}:8000"
    environment:
      <<: *common-env
      # Enable WORKER MODE
    depends_on:
      lychee_db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/up"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  lychee_worker:
    <<: *base-lychee-setup
    container_name: lychee-worker
    environment:
      <<: *common-env
      # Enable WORKER MODE
      LYCHEE_MODE: worker

    depends_on:
      lychee_db:
        condition: service_healthy
      lychee_api:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "pgrep -f 'queue:work' || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s  # Give worker time to start up

  lychee_db:
      image: mariadb:10
      security_opt:
          - no-new-privileges:true
      cap_drop:
          - ALL
      cap_add:
          - SETGID
          - SETUID
          - DAC_OVERRIDE
          - CHOWN
      read_only: false  # MariaDB needs write access
      tmpfs:
          - /tmp:noexec,nosuid,nodev,size=200m
          - /var/run/mysqld:noexec,nosuid,nodev,size=10m
      environment:
          - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:-rootpassword}
          - MYSQL_DATABASE=${DB_DATABASE:-lychee}
          - MYSQL_USER=${DB_USERNAME:-lychee}
          - MYSQL_PASSWORD=${DB_PASSWORD:-password}
      expose:
          - 3306
      volumes:
          - mysql:/var/lib/mysql
      networks:
          - lychee
      restart: unless-stopped
      healthcheck:
        test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
        interval: 5s
        timeout: 3s
        retries: 10
        start_period: 10s

  lychee_facial_recognition:
    container_name: lychee-facial-recognition
    image: ghcr.io/lycheeorg/lychee-facial-recognition:latest
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    environment:
      VISION_FACE_LYCHEE_API_URL: "http://lychee_api:8000"
      VISION_FACE_API_KEY: "${AI_VISION_API_KEY:-changeme}"
      VISION_FACE_VERIFY_SSL: "${AI_VISION_VERIFY_SSL:-true}"
      VISION_FACE_PHOTOS_PATH: "/data/photos"
      VISION_FACE_STORAGE_PATH: "/data/embeddings"
      VISION_FACE_WORKERS: "${AI_VISION_WORKERS:-1}"
    volumes:
      - ./lychee/uploads:/data/photos:ro
      - ai_vision_embeddings:/data/embeddings
    networks:
      - lychee
    depends_on:
      lychee_api:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

networks:
    lychee:

volumes:
    mysql:
        name: lychee_prod_mysql
        driver: local
    ai_vision_embeddings:
        name: lychee_ai_vision_embeddings
        driver: local

Lychee Documentation

Welcome to the Lychee documentation! This folder contains comprehensive documentation about the Lychee photo management system and is primarily focused on the internal workings of Lychee.
This includes its architecture, request lifecycles, data structures, and validation systems. It is intended for developers and contributors who want to understand how Lychee operates under the hood.

Before getting started, we would like to highlight the folders of interest at the root level of the repository:

text
./
β”œβ”€β”€ app/        # Contains the core of Lychee: models, controllers, actions, and business logic
β”œβ”€β”€ database/   # Database migrations for setting up the database schema
β”œβ”€β”€ docs/       # Developer documentation (this folder) explaining Lychee's internal workings
β”‚   └── specs/  # Structured documentation following DiΓ‘taxis framework
β”œβ”€β”€ lang/       # Translation files for internationalization
β”œβ”€β”€ resources/  # Frontend assets including Vue.js components
β”œβ”€β”€ routes/     # API and web route definitions
└── tests/      # Automated test suites for ensuring code quality and functionality

The missing folders (bootstrap, composer-cache, config, docker, phpstan, public, scripts and storage) are still essential for the overall functionality of Lychee but not of primary concern for understanding the system.

Documentation Structure

Documentation is organized following the DiΓ‘taxis framework in the specs/ directory:

Getting Started

Backend Architecture

Frontend Architecture

Data Structures

Authorization and Validation

  • Policies Documentation - Authorization and access control system with regular and query policies
  • Rules Documentation - Custom validation rules with patterns, security considerations, and implementation examples

Localization and Internationalization

Contributing

Additional Resources

For more information about Lychee:


Last updated: January 21, 2026