Lychee is the best-looking open-source album of the bunch: Laravel under the hood, FrankenPHP as the runtime since v7, one app container plus MariaDB. There is no heavy AI pipeline, but albums, tags, share links, permissions, watermarks and face recognition are all present — ideal for a clean family gallery.
1. Image and ports
| Item | Value |
|---|---|
| Application image | ghcr.io/lycheeorg/lychee:latest (or Docker Hub lycheeorg/lychee) |
| Face recognition (optional) | ghcr.io/lycheeorg/lychee-facial-recognition:latest |
| Database | mariadb:10 |
| Web port | 8000 |
The v7 image layout changed. Older tutorials with separate nginx and php-fpm containers are outdated — use the current official Compose file.
2. Download the official Compose file
mkdir -p /opt/lychee && cd /opt/lychee
curl -O https://raw.githubusercontent.com/LycheeOrg/Lychee/master/docker-compose.minimal.yaml
mv docker-compose.minimal.yaml docker-compose.yml
mkdir -p lychee/uploads lychee/logs lychee/tmp
3. Generate a key and configure
openssl rand -base64 32
# Output looks like Xb7...= — prefix it with base64: for APP_KEY
Edit the shared environment block at the top of docker-compose.yml:
APP_KEY: "base64:paste-the-generated-value-here"
APP_URL: "https://photos.example.com"
APP_FORCE_HTTPS: "true"
DB_PASSWORD: "replace-with-a-strong-database-password"
DB_ROOT_PASSWORD: "replace-with-a-strong-root-password"
TIMEZONE: "Asia/Shanghai"
If you do not need face recognition, delete the whole lychee_facial_recognition service and the AI_VISION_* variables — that saves around 1 GB of memory.
4. Start it
docker compose up -d
docker compose ps
docker compose logs -f lychee_api
Open http://SERVER_IP:8000. The first visit walks you through creating the administrator account. Sign in, create an album and upload photos.
5. Reverse proxy and HTTPS
server {
listen 443 ssl http2;
server_name photos.example.com;
ssl_certificate /etc/letsencrypt/live/photos.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/photos.example.com/privkey.pem;
client_max_body_size 2000M;
proxy_read_timeout 600s;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
On a panel such as aaPanel or BaoTa, just add a reverse proxy to http://127.0.0.1:8000 and enable SSL.

6. Day-to-day use
- Sharing: the Share button on an album supports public links, passwords and expiry dates — great for relatives.
- Permissions: create users in settings and assign upload or read-only roles.
- Watermarks and copyright: Settings → Image Processing supports batch watermarks.
- Face recognition: keep the facial-recognition container, enable it in settings and wait for the scan.
7. Backup and upgrades
- Back up
lychee/uploads(originals and thumbnails),lychee/logsand the MariaDB volume. - Upgrade with
docker compose pull && docker compose up -d. For major versions such as v6 → v7, read the official upgrade guide first — the image layout changed. - Keep
APP_KEY; move it with the data.
8. Troubleshooting
Large uploads fail? Raise both the proxy client_max_body_size and PHP's upload_max_filesize; the FrankenPHP image exposes these as environment variables.
Styles are missing? APP_URL does not match the real address. Set the production domain and restart.
Low memory? Disable the facial-recognition service; Lychee itself runs in around 512 MB.
9. Wrap-up
Lychee hits the sweet spot of "good enough, good-looking, easy to maintain". It does not try to own phone backup, but as a family sharing gallery its interface and sharing flow are genuinely pleasant.
Related: Piwigo tutorial · 2026 self-hosted album comparison


