# Lychee

Photo management web app for uploading, organizing and sharing albums.

- Replaces: [Flickr](https://openlogs.fyi/alternatives/flickr)
- Summary: Paid photo hosting services, such as Flickr.
- Stack: PHP (language), MariaDB (database)
- Deployment: docker_compose
- License: MIT (osi) [source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/LICENSE)
- Business model: unknown. The README at the pinned commit does not state a business model, so it stays unknown. ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/README.md), read 2026-10-22)
- Difficulty: hard. 4 services (1 database or broker: mariadb), 6 volume mounts, no env values to set, host access: cap_add. Heuristic score 6 of 11: hard.
- Requirements: not stated
- Repository: [LycheeOrg/Lychee](https://github.com/LycheeOrg/Lychee)

## Install

1. Docker with the Compose plugin ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/README.md))

   ```text
   A host with Docker and the Docker Compose plugin. This entry runs from a compose file.
   ```

2. Save the compose file as docker-compose.minimal.yaml ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml))

   ```yaml
   # 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
   ```

3. What the compose file check ran with ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/README.md))

   ```text
   The compose file check ran on this file alone. The folder held only this file. The README tells the reader to download the minimal docker-compose template and start it with docker compose -f docker-compose.minimal.yaml up -d.
   ```

4. Start it ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/README.md))

   ```bash
   docker compose -f docker-compose.minimal.yaml up -d
   ```

5. Open the app ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml))

   ```text
   Open http://localhost:8000. The compose file publishes host port 8000 for the lychee_api service. The README says to open this address in a browser.
   ```

Compose file check: config_ok on 2026-10-22.

## Gotchas and maintenance

### Gotchas

- Some images use the latest tag or no tag: Images without a pinned version: lychee_api: ghcr.io/lycheeorg/lychee:latest, lychee_worker: ghcr.io/lycheeorg/lychee:latest, lychee_facial_recognition: ghcr.io/lycheeorg/lychee-facial-recognition:latest. A later pull can get a different version. ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml), checked 2026-10-22)
- The compose file has placeholder values: Placeholder values: DB_PASSWORD is "password" (lychee_api), AI_VISION_FACE_API_KEY is "changeme" (lychee_api), DB_PASSWORD is "password" (lychee_worker), AI_VISION_FACE_API_KEY is "changeme" (lychee_worker), MYSQL_PASSWORD is "password" (lychee_db), VISION_FACE_API_KEY is "changeme" (lychee_facial_recognition). ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml), checked 2026-10-22)
- The compose file publishes host ports: Host ports: 8000 (lychee_api). A port without a host address listens on all host network interfaces. ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml), checked 2026-10-22)
- The compose file mounts host folders: Host paths mounted into containers: ./lychee/uploads at /app/public/uploads (lychee_api), ./lychee/logs at /app/storage/logs (lychee_api), ./lychee/tmp at /app/storage/tmp (lychee_api), ./lychee/uploads at /app/public/uploads (lychee_worker), ./lychee/logs at /app/storage/logs (lychee_worker), ./lychee/tmp at /app/storage/tmp (lychee_worker), ./lychee/uploads at /data/photos (lychee_facial_recognition). ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml), checked 2026-10-22)
- Some services get elevated host access: lychee_api adds Linux capabilities, lychee_worker adds Linux capabilities, lychee_db adds Linux capabilities. ([source](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml), checked 2026-10-22)

### Signals

Computed from a GitHub snapshot taken 2026-10-22.

- Open issues and pull requests: 18
- Stars: 4312, forks: 386
- Last push: 2026-10-22 (0 days ago)
- Latest release: v7.11.1 on 2026-10-13 (9 days ago)

## Sources

- [Repository: https://github.com/LycheeOrg/Lychee](https://github.com/LycheeOrg/Lychee)
- [License: https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/LICENSE](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/LICENSE)
- [Business model: https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/README.md](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/README.md)
- [Compose file: https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml](https://github.com/LycheeOrg/Lychee/blob/d7deef4e25d25df820950fc174b11dfdc498c130/docker-compose.minimal.yaml)

---
Canonical: https://openlogs.fyi/tools/lychee  
Last updated: 2026-10-22
