Manual Installation
This guide covers installing Lychee without Docker. For most users, the Docker installation is simpler and recommended.
Server Requirements
Section titled “Server Requirements”- A web server such as Apache or nginx
- A database — using one of the following:
- MySQL (version > 5.7.8) / MariaDB (version > 10.2)
- PostgreSQL (version > 9.2)
- SQLite3
- PHP >= 8.4 with these extensions:
- bcmath, ctype, dom, exif, fileinfo, filter, gd, json, libxml, ldap (optional), mbstring, openssl, pcre, PDO, Phar, SimpleXML, tokenizer, xml, xmlwriter
- imagick (optional — better thumbnails)
- PhpRedis (optional — to use Redis)
- A database-specific PHP extension:
- SQLite3 for SQLite databases
- MySQLi (or PDO_MySQL) for MySQL / MariaDB
- PgSql (or PDO_PGSQL) for PostgreSQL
- On FreeBSD, you may also need: session, zlib
- Optional CLI tools:
- Exiftool (better EXIF metadata handling)
- FFmpeg (video thumbnails)
While Lychee works on 32-bit systems, a 64-bit OS is strongly recommended.
Installing Lychee
Section titled “Installing Lychee”From a Release
Section titled “From a Release”- Download the latest release zip from the Releases page.
- Extract it to your web directory (e.g.
/var/www/html).
From Source
Section titled “From Source”Building from source requires Composer and npm.
git clone https://www.github.com/LycheeOrg/Lychee /var/www/html/Lycheecd /var/www/html/Lycheecomposer install --no-devnpm installnpm run buildConfiguration
Section titled “Configuration”Directory Permissions
Section titled “Directory Permissions”Three OS users may be involved:
- Web user — the user running the web server daemon (e.g.
www-data,apache,nginx) - PHP user — the user running PHP-FPM/CGI (often the same as the web user)
- CLI user — your shell user, relevant if importing photos via CLI
Required permissions:
- All Lychee files must be readable by the web/PHP user.
storage/andbootstrap/cache/must be writable by the web/PHP user.public/uploadsandpublic/symmust be writable by the web/PHP user (and the CLI user if importing via CLI).public/distmust be writable if you want to customize CSS via the web frontend.
For CLI imports, the recommended approach is to add all users to a shared group, set group ownership, enable group write, and set the sgid bit on directories so new files inherit the group.
Environment File (.env)
Section titled “Environment File (.env)”The main directory should contain a .env file. Composer typically creates this from .env.example during installation. If it doesn’t exist, copy it manually:
cp .env.example .envApplication Key
Section titled “Application Key”The APP_KEY setting must be set. If Composer didn’t generate one:
php artisan key:generateSet APP_URL in .env to the external URL by which the public/ directory is accessible. This must match your web server configuration.
Additional Configuration
Section titled “Additional Configuration”The default .env provides usable settings out of the box. You may want to configure cache, database, and session settings — see the Configuration page.
Web Server Configuration
Section titled “Web Server Configuration”Configure your web server to serve the public/ directory. Do not expose the top-level Lychee directory — this would allow public access to the .env file and application code.
It is strongly recommended to serve Lychee over TLS. Consider Let’s Encrypt for certificates and Mozilla’s SSL Configuration Generator for server configuration.
Apache
Section titled “Apache”Enable mod_rewrite so the included public/.htaccess is honored. Also check the Apache upgrade instructions for required permissions in your site configuration.
If the default .htaccess does not work, try this alternative:
Options +FollowSymLinks -IndexesRewriteEngine On
RewriteCond %{HTTP:Authorization} .RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-dRewriteCond %{REQUEST_FILENAME} !-fRewriteRule ^ index.php [L]A sample nginx server block (without TLS):
server { listen 80; server_name <mydomain>.<tld>;
root /var/www/Lychee/public/; index index.php;
# If the request is not for a valid file, send to bootstrap if (!-e $request_filename) { rewrite ^/(.*)$ /index.php?/$1 last; break; }
# Serve /index.php through PHP location = /index.php { fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_param HTTP_PROXY ""; fastcgi_pass unix:/run/php/php8.4-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PHP_VALUE "post_max_size=100M max_execution_time=200 upload_max_filesize=30M memory_limit=300M"; fastcgi_param PATH /usr/local/bin:/usr/bin:/bin; include fastcgi_params; }
# Deny access to other .php files location ~ [^/]\.php(/|$) { return 403; }
error_log /var/log/nginx/lychee.error.log; access_log /var/log/nginx/lychee.access.log;}For subdirectory hosting, see the FAQ.
