-
-
Notifications
You must be signed in to change notification settings - Fork 367
Expand file tree
/
Copy pathdocker-compose.yaml
More file actions
561 lines (481 loc) · 18.8 KB
/
docker-compose.yaml
File metadata and controls
561 lines (481 loc) · 18.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
# Docker Compose configuration for Lychee application with FrankenPHP backend
# Version: 2026-01-10
# You can set up secrets files for sensitive data like database passwords.
# Create a 'secrets' directory and add files 'db_password' and 'db_master_password'
# with appropriate permissions (readable only by the owner).
# Then uncomment the 'secrets' section below.
# secrets:
# db_password:
# file: ./secrets/db_password
# db_master_password:
# file: ./secrets/db_master_password
# app_key:
# file: ./secrets/app_key
##########################################################################################
# Common settings for Lychee services
##########################################################################################
x-base-lychee-setup: &base-lychee-setup
# There are two main images: `latest` and `edge`.
# `latest` is mapped to the last published version
# `edge` is mapped to the last build on master branch (may be unstable)
#
# There are also other images available which uses nginx as a base instead of FrankenPHP:
# - ghcr.io/lycheeorg/lychee:latest-legacy
# - ghcr.io/lycheeorg/lychee:edge-legacy
image: ghcr.io/lycheeorg/lychee:latest
# The following lines are for development purposes only.
# image: lychee-frankenphp:latest
# image: lychee-legacy:latest
# build:
# context: ./app
# dockerfile: Dockerfile
# args:
# NODE_ENV: "${NODE_ENV:-production}"
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
# Resource limits
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
# To configure Lychee, you can do it via:
# - environment variables (see the environment section below)
# - .env file (recommended for sensitive data)
# - mapping .env file to /app/.env (not necessary anymore if you use env_file)
env_file:
- path: ./.env
# If you use docker secrets, uncomment the following lines and
# create the secrets files as described at the top of this file.
# secrets:
# - db_password
# - app_key
volumes:
# Mount local directories for persistent storage
# Uploads : where your photos are going to be stored
- ./lychee/uploads:/app/public/uploads
# Logs: to see what went wrong (or right)
- ./lychee/logs:/app/storage/logs
# Temporary files: where your uploads are stored temporarily
# while waiting for jobs to process them.
- ./lychee/tmp:/app/storage/tmp
networks:
- lychee
x-common-env: &common-env
# User and Group IDs for the www-data user inside the container
# Note that this will impact your permissions on mounted volumes.
# By default Lychee does not run as root inside the container.
#
# Ensure that the PUID and PGID match the owner of the mounted volumes
# to avoid permission issues.
#
# You can also set it to 33 (www-data) if your files are owned by www-data.
PUID: "${PUID:-1000}"
PGID: "${PGID:-1000}"
# Or you can activate the following to run as root inside the container. (not recommended)
# RUN_AS_ROOT: "yes"
# Application Key
# You can either set it here directly (not recommended for security reasons)
# Or load it from .env file
# or use Docker secrets as shown above.
APP_KEY: "${APP_KEY:-}"
# APP_KEY_FILE: "/run/secrets/app_key"
# Application
APP_NAME: "${APP_NAME:-Lychee}"
APP_ENV: "${APP_ENV:-production}"
APP_DEBUG: "${APP_DEBUG:-false}"
APP_TIMEZONE: "${TIMEZONE:-UTC}"
APP_URL: "${APP_URL:-http://localhost:8000}"
APP_FORCE_HTTPS: "${APP_FORCE_HTTPS:-false}"
APP_MAINTENANCE_DRIVER: "${APP_MAINTENANCE_DRIVER:-file}"
# enable or disable debug bar. By default it is disabled.
# Do note that this disable CSP!!
# DEBUGBAR_ENABLED: "${DEBUGBAR_ENABLED:-false}"
# enable or disable log viewer. By default it is enabled.
# Unfortunately, log viewer is not available in production due to an upstream bug. :(
# you will need to set APP_ENV=local to enable it.
LOG_VIEWER_ENABLED: "${LOG_VIEWER_ENABLED:-true}"
# Sometimes 404 errors are very noisy in the logs.
# You can disable logging them by setting this to false.
LOG_404_ERRORS: "${LOG_404_ERRORS:-true}"
# enable or disable clockwork. By default it is disabled (and not provided on non-dev build).
CLOCKWORK_ENABLE: "${CLOCKWORK_ENABLE:-false}"
# enable or disable latency debug: adds a specific amount of time in milliseconds to wait before processing requests.
# Always disabled on production environment.
# APP_DEBUG_LATENCY: 0
# All API requests to have the header "content-type: application/json"
# or "content-type: multipart/form-data" depending on the type.
#
# If you want to disable this requirement, set this to false.
#
# This requirement prevents the use of the API from the API documentation page.
# REQUIRE_CONTENT_TYPE_ENABLED: "${REQUIRE_CONTENT_TYPE_ENABLED:-true}"
# enable s3 bucket (required in addition to needing AWS_ACCESS_KEY_ID)
# S3_ENABLED: true
# If you spread old links of to your albums in your Lychee instance starting with
# https://lychee.text/#albumID/PhotoId
# Set this value to true to enable redirection.
# LEGACY_V4_REDIRECT: "${LEGACY_V4_REDIRECT:-false}"
##############################################################################
# IMPORTANT: To migrate from Lychee v3 you *MUST* use the same MySQL/MariaDB #
# server as v3. #
##############################################################################
# Table prefix (e.g. lychee_) of a Lychee v3 instance for migration
# DB_OLD_LYCHEE_PREFIX:
# DB_CONNECTION can be sqlite, mysql or pgsql. For sqlite the other entries are
# not required, but an existing sqlite3 database may be specified if desired.
# In this case, please use an absolute path. DB_DATABASE may be omitted but should
# *not* be left blank.
#
# Note that if DB_PASSWORD includes special characters, it must be enclosed in quotes.
# e.g. DB_PASSWORD: "lychee!@#$%^&"
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}"
# Use secrets for sensitive data - see Docker secrets or vault integration
# DB_PASSWORD should come from .env file only
DB_PASSWORD: "${DB_PASSWORD:-password}"
#
# Or you can uncomment the following line to use DB_PASSWORD_FILE from secrets
# DB_PASSWORD_FILE: "/run/secrets/db_password"
# Session configuration
SESSION_DRIVER: "${SESSION_DRIVER:-file}"
SESSION_LIFETIME: "${SESSION_LIFETIME:-120}"
# SESSION_DRIVER: "${SESSION_DRIVER:-database}"
# SESSION_LIFETIME: "${SESSION_LIFETIME:-120}"
# SESSION_ENCRYPT: "${SESSION_ENCRYPT:-false}"
# SESSION_PATH: "${SESSION_PATH:-/}"
# SESSION_DOMAIN: "${SESSION_DOMAIN:-null}"
# Cache
CACHE_STORE: "${CACHE_STORE:-file}"
CACHE_PREFIX: "${CACHE_PREFIX:-lychee_cache}"
# REDIS_HOST: "lychee_cache"
# REDIS_PASSWORD: "null"
# REDIS_PORT: "6379"
# REDIS_URL=redis://<username>:<password>@<host>:<port>
# If you use Redis as cache driver, we strongly recommend
# to disable it for your Log Viewer.
# Should redis crash, you will no longer be able to access your logs.
LOG_VIEWER_CACHE_DRIVER: "file"
# When booting the application, if you have a lot of photos,
# Lychee will check the permissions of all files and folders.
# This may take a while (even hours depending on the number of photos...)
# If you are sure that your permissions are correct, you can skip these checks
# by setting the following to "yes".
# SKIP_PERMISSIONS_CHECKS: "yes"
# Queue
# The default value for QUEUE_CONNECTION is 'sync', this means that jobs are
# executed immediately (synchronously) when dispatched.
#
# For improved reactivity of Lychee we recommend to use a worker.
# You can use either 'database' or 'redis' as queue driver (but in the later you need to enable redis).
# QUEUE_CONNECTION: "${QUEUE_CONNECTION:-database}"
# Logging Stuff.
# LOG_CHANNEL: "${LOG_CHANNEL:-stack}"
# LOG_STACK: "${LOG_STACK:-single}"
# LOG_DEPRECATIONS_CHANNEL: "${LOG_DEPRECATIONS_CHANNEL:-null}"
# LOG_LEVEL: "${LOG_LEVEL:-debug}"
# LOG_STDOUT: "${LOG_STDOUT:-true}"
# SECURITY_HEADER_HSTS_ENABLE:false
# SECURITY_HEADER_CSP_CONNECT_SRC:
# SECURITY_HEADER_SCRIPT_SRC_ALLOW:
# SECURITY_HEADER_CSP_CHILD_SRC:
# SECURITY_HEADER_CSP_FONT_SRC:
# SECURITY_HEADER_CSP_FORM_ACTION:
# SECURITY_HEADER_CSP_FRAME_ANCESTORS:
# SECURITY_HEADER_CSP_FRAME_SRC:
# SECURITY_HEADER_CSP_IMG_SRC:
# SECURITY_HEADER_CSP_MEDIA_SRC:
# SESSION_SECURE_COOKIE:false
# MAIL_DRIVER:smtp
# MAIL_HOST:
# MAIL_PORT:
# MAIL_USERNAME:
# MAIL_PASSWORD:
# MAIL_ENCRYPTION:
# MAIL_FROM_NAME:
# MAIL_FROM_ADDRESS:
# TRUSTED_PROXIES=null
# Disable Basic Auth. This means that the only way to authenticate is via the API token or Oauth.
# This should only be toggled AFTER having set up the admin account and bound the Oauth client.
# DISABLE_BASIC_AUTH=false
# Disable WebAuthn. This means that the only way to authenticate is via the API token, Basic Auth or Oauth.
# DISABLE_WEBAUTHN=false
###################################################################
# LDAP Authentication (enterprise directory integration) #
###################################################################
# Enable LDAP authentication alongside or instead of basic auth
# LDAP_ENABLED=false
# LDAP Server connection settings
# LDAP_HOST=ldap.example.com
# LDAP_PORT=389
# For LDAPS (LDAP over SSL), use port 636
# LDAP_PORT=636
# Base DN for LDAP searches (e.g., dc=example,dc=com or dc=corp,dc=example,dc=com)
# LDAP_BASE_DN=dc=example,dc=com
# Service account credentials for LDAP bind
# This account needs read-only access to user and group attributes
# LDAP_BIND_DN=cn=lychee-service,ou=services,dc=example,dc=com
# LDAP_BIND_PASSWORD=securepassword
# LDAP user search filter (%s is replaced with username)
# For OpenLDAP:
# LDAP_USER_FILTER=(&(objectClass=person)(uid=%s))
# For Active Directory:
# LDAP_USER_FILTER=(&(objectClass=user)(sAMAccountName=%s))
# LDAP attribute mapping (maps LDAP attributes to Lychee user fields)
# OpenLDAP defaults:
# LDAP_ATTR_USERNAME=uid
# LDAP_ATTR_EMAIL=mail
# LDAP_ATTR_DISPLAY_NAME=displayName
# Active Directory alternatives:
# LDAP_ATTR_USERNAME=sAMAccountName
# LDAP_ATTR_EMAIL=userPrincipalName
# LDAP_ATTR_DISPLAY_NAME=displayName
# Admin role mapping via LDAP group
# Users in this group will have may_administrate=true
# LDAP_ADMIN_GROUP_DN=cn=lychee-admins,ou=groups,dc=example,dc=com
# Auto-provision users on first LDAP login
# If false, users must be pre-created in Lychee before they can log in via LDAP
# LDAP_AUTO_PROVISION=true
# TLS/SSL settings for secure LDAP connections
# LDAP_USE_TLS=true
# LDAP_TLS_VERIFY_PEER=true
# Connection timeout in seconds
# LDAP_CONNECTION_TIMEOUT=5
# Oauth token data
# XXX_REDIRECT_URI should be left as default unless you know exactly what you do.
# AMAZON_SIGNIN_CLIENT_ID=
# AMAZON_SIGNIN_SECRET=
# AMAZON_SIGNIN_REDIRECT_URI=/auth/amazon/redirect
# https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple
# Note: the client secret used for "Sign In with Apple" is a JWT token that can have a maximum lifetime of 6 months.
# The article above explains how to generate the client secret on demand and you'll need to update this every 6 months.
# To generate the client secret for each request, see Generating A Client Secret For Sign In With Apple On Each Request.
# https://bannister.me/blog/generating-a-client-secret-for-sign-in-with-apple-on-each-request
# APPLE_CLIENT_ID=
# APPLE_CLIENT_SECRET=
# APPLE_REDIRECT_URI=/auth/apple/redirect
# FACEBOOK_CLIENT_ID=
# FACEBOOK_CLIENT_SECRET=
# FACEBOOK_REDIRECT_URI=/auth/facebook/redirect
# GITHUB_CLIENT_ID=
# GITHUB_CLIENT_SECRET=
# GITHUB_REDIRECT_URI=/auth/github/redirect
# GOOGLE_CLIENT_ID=
# GOOGLE_CLIENT_SECRET=
# GOOGLE_REDIRECT_URI=/auth/google/redirect
# MASTODON_DOMAIN=https://mastodon.social
# MASTODON_ID=
# MASTODON_SECRET=
# MASTODON_REDIRECT_URI=/auth/mastodon/redirect
# MICROSOFT_CLIENT_ID=
# MICROSOFT_CLIENT_SECRET=
# MICROSOFT_REDIRECT_URI=/auth/microsoft/redirect
# MICROSOFT_TENANT_ID=
# NEXTCLOUD_CLIENT_ID=
# NEXTCLOUD_CLIENT_SECRET=
# NEXTCLOUD_REDIRECT_URI=/auth/nextcloud/redirect
# NEXTCLOUD_BASE_URI=
# KEYCLOAK_CLIENT_ID=
# KEYCLOAK_CLIENT_SECRET=
# KEYCLOAK_REDIRECT_URI=/auth/keycloak/redirect
# KEYCLOAK_BASE_URL=
# KEYCLOAK_REALM=
# AUTHENTIK_BASE_URL=
# AUTHENTIK_CLIENT_ID=
# AUTHENTIK_CLIENT_SECRET=
# AUTHENTIK_REDIRECT_URI=/auth/authentik/redirect
# AUTHELIA_BASE_URL=
# AUTHELIA_CLIENT_ID=
# AUTHELIA_CLIENT_SECRET=
# AUTHELIA_REDIRECT_URI=/auth/authelia/redirect
# AWS support data
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# AWS_DEFAULT_REGION=
# AWS_BUCKET=
# AWS_URL=
# AWS_ENDPOINT=
# AWS_IMAGE_VISIBILITY=
# AWS_USE_PATH_STYLE_ENDPOINT=
# DISABLE_IMPORT_FROM_SERVER=false
###################################################################
# Payment integration (requires SE) #
###################################################################
# Enable test mode (Sandbox mode) for payment gateways.
# In test mode, no real money transactions are done.
# We set it to true by default for safety. Make sure to set it to false
# when you go live.
# OMNIPAY_TEST_MODE=true
# Configuration values for Mollie integration
# MOLLIE_API_KEY=
# MOLLIE_PROFILE_ID=
# Configuration values for Stripe integration (NOT WORKING YET, MAYBE LATER)
# STRIPE_API_KEY=
# STRIPE_PUBLISHABLE_KEY=
# Configuration values for PayPal integration
# PAYPAL_CLIENT_ID=
# PAYPAL_SECRET=
services:
##########################################################################################
# Lychee API Service and frontend.
##########################################################################################
lychee_api:
<<: *base-lychee-setup
# Set up a container name for easier identification
container_name: lychee-api
expose:
- "${APP_PORT:-8000}"
ports:
- "${APP_PORT:-8000}:8000"
environment:
<<: *common-env
# Performance tuning for FRANKENPHP
# For the legacy setup using the -legacy tags, these values are not used.
# Increase PHP max execution time (in seconds) for long running operations like imports.
# We recommend you leave those as is and use database/redis queue with a worker for long operations.
# PHP_MAX_EXECUTION_TIME: 3000
# LYCHEE_MAX_EXECUTION_TIME: 30
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
##########################################################################################
# Queue Worker Service (disabled by default)
##########################################################################################
#
# Uncomment to enable horizontal scaling of background job processing
# THIS IS PRETTY MUCH THE SAME CONFIGURATION AS lychee_api WITH A SINGLE MINOR MODIFICATIONS
lychee_worker:
<<: *base-lychee-setup
container_name: lychee-worker
environment:
<<: *common-env
##########################################################################################
# Enable WORKER MODE
##########################################################################################
#
# THIS VALUE HERE IS THE MOST IMPORTANT ONE.
# IF LYCHEE_MODE IS NOT SET TO WORKER, THE CONTAINER WILL BE A DUPLICATE OF lychee_api.
# Set LYCHEE_MODE=worker to enable queue worker mode
LYCHEE_MODE: worker
depends_on:
lychee_db:
condition: service_healthy
lychee_api:
condition: service_healthy
# Worker health check
# Verifies queue:work process is running
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_cache:
image: redis:alpine
hostname: lychee_cache
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
read_only: true
tmpfs:
- /tmp:noexec,nosuid,nodev,size=50m
healthcheck:
test: ["CMD-SHELL", "redis-cli ping || exit 1"]
# Removed port exposure - only accessible within Docker network
# ports:
# - ${REDIS_PORT:-6379}:${REDIS_PORT:-6379}
user: 999:999 # redis user in Alpine
env_file:
- path: ./.env
required: false
environment:
- TZ=${TIMEZONE:-UTC}
networks:
- lychee
volumes:
- cache:/data:rw
restart: on-failure:5
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
env_file:
- path: ./.env
required: false
# secrets:
# - db_master_password
# - db_password
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:-rootpassword}
# - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_master_password
- MYSQL_DATABASE=${DB_DATABASE:-lychee}
- MYSQL_USER=${DB_USERNAME:-lychee}
- MYSQL_PASSWORD=${DB_PASSWORD:-password}
# - MYSQL_PASSWORD_FILE=/run/secrets/db_password
expose:
- 3306
# Removed host port binding - only accessible within Docker network
# For debugging, temporarily uncomment:
# ports:
# - 127.0.0.1:33061: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
networks:
lychee:
volumes:
mysql:
name: lychee_prod_mysql
driver: local
cache:
name: lychee_prod_redis
driver: local