mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-18 01:25:09 +00:00
d11bda094b
The defaults let files through when the scanner cannot answer, so an installation whose scanner died looks, from every screen anybody uses, exactly like one that is working. Three places now say otherwise. `projectsend:status` gains a `scanning` block: whether it is on, whether it is managed, whether the scanner answers right now, the engine and how old its definitions are, what is waiting, what is quarantined, and how many files went out unscanned in the last 24 hours. Absent, null and zero stay distinct — `reachable: null` means there is nothing to reach, `false` means it should be answering and is not. The scans queue is reported beside the other two. The dashboard's System card carries the same warning for whoever is actually looking at a screen, and says nothing at all while scanning is healthy or switched off. Docker gets the scanner as an opt-in profile — `--profile scanner` — in both the development compose file and the published example, with a clamd.conf whose Alert* options are what make an encrypted archive come back as "could not scan" instead of "OK". No published ports: clamd has no authentication and the file crosses that socket in the clear. Both images also run a worker for the scans queue. The dashboard test caught a 500 before it shipped: a nullable return written as `array`.
217 lines
6.8 KiB
YAML
217 lines
6.8 KiB
YAML
name: projectsend
|
|
|
|
services:
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
volumes:
|
|
- .:/var/www/html
|
|
# Shared dev clones of the companion packages — never nested inside this
|
|
# repo. Relative to keep host and container paths symmetric with
|
|
# the ../packages symlink at this repo's own root.
|
|
- ../packages:/var/www/packages
|
|
environment:
|
|
PHP_IDE_CONFIG: serverName=projectsend
|
|
# Optional unattended first-admin creation; without these the web
|
|
# setup screen prompts on first visit.
|
|
ADMIN_NAME: ${ADMIN_NAME:-}
|
|
ADMIN_EMAIL: ${ADMIN_EMAIL:-}
|
|
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-}
|
|
# The whole default stack declares one, so it comes back after a reboot
|
|
# or a Docker restart instead of half of it coming back — the confusing
|
|
# state, where the queue runs and the site is down (#1658). The dev-only
|
|
# profile services below deliberately do not: you bring those up for a
|
|
# session, not for the life of the machine.
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
web:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/web/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
ports:
|
|
- "${APP_PORT:-8090}:80"
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ./docker/web/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- app
|
|
|
|
worker:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
command: php artisan queue:work --queue=default --tries=3 --backoff=3
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ../packages:/var/www/packages
|
|
# Required so `queue:restart` (triggered when mail provider settings
|
|
# are saved) actually brings the worker back instead of leaving the
|
|
# queue dead until someone runs `docker compose up -d` by hand.
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
# Zip builds get their own worker: BuildZipDownloadJob allows itself an
|
|
# hour, and on a shared queue one large archive holds up every
|
|
# notification email behind it.
|
|
worker-zips:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
command: php artisan queue:work --queue=zips --tries=1
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ../packages:/var/www/packages
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
# Scans get their own worker for the reason zips do: reading a 5 GB file
|
|
# to the scanner takes minutes, and on the default queue it would sit in
|
|
# front of every notification email.
|
|
worker-scans:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
command: php artisan queue:work --queue=scans --tries=1
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ../packages:/var/www/packages
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
scheduler:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
command: php artisan schedule:work
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ../packages:/var/www/packages
|
|
# Same reason the worker has one, plus a second: on a fresh clone this
|
|
# exits until `composer install` has run, and without a restart policy it
|
|
# then stays exited — scheduled work silently never happens, on the one
|
|
# setup where nobody would think to check.
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
db:
|
|
image: mysql:8.4
|
|
command: --mysql-native-password=OFF
|
|
environment:
|
|
MYSQL_DATABASE: ${DB_DATABASE:-projectsend}
|
|
MYSQL_USER: ${DB_USERNAME:-projectsend}
|
|
MYSQL_PASSWORD: ${DB_PASSWORD:-secret}
|
|
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root}
|
|
volumes:
|
|
- db-data:/var/lib/mysql
|
|
restart: unless-stopped
|
|
ports:
|
|
# Loopback only: this forward exists for host-side DB GUIs, not for
|
|
# the network. Without the prefix Docker publishes on 0.0.0.0 and
|
|
# bypasses most host firewalls — a LAN-reachable MySQL with the
|
|
# compose-file default password on any host that runs the stack.
|
|
- "127.0.0.1:${DB_PORT_FORWARD:-33061}:3306"
|
|
healthcheck:
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${DB_ROOT_PASSWORD:-root}"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 10
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
restart: unless-stopped
|
|
volumes:
|
|
- redis-data:/data
|
|
|
|
# Dev-only DB GUI (brief §12: ship Adminer as a dev-only Compose service)
|
|
adminer:
|
|
image: adminer:latest
|
|
ports:
|
|
# Loopback only — an unauthenticated DB panel must not be reachable
|
|
# from the network just because someone brought the dev profile up
|
|
# on a machine with a routable address.
|
|
- "127.0.0.1:${ADMINER_PORT:-8091}:8080"
|
|
environment:
|
|
ADMINER_DEFAULT_SERVER: db
|
|
depends_on:
|
|
- db
|
|
profiles:
|
|
- dev
|
|
|
|
# Dev-only SMTP catcher: lets email notifications be sent and inspected
|
|
# locally (web UI + HTTP API) without a real mail server.
|
|
mailpit:
|
|
image: axllent/mailpit:latest
|
|
ports:
|
|
# Loopback only, same reasoning as Adminer: captured mail is readable
|
|
# without authentication.
|
|
- "127.0.0.1:${MAILPIT_SMTP_PORT:-1025}:1025"
|
|
- "127.0.0.1:${MAILPIT_WEB_PORT:-8025}:8025"
|
|
profiles:
|
|
- dev
|
|
|
|
# The virus scanner, off unless you ask for it:
|
|
# docker compose --profile scanner up -d
|
|
# then point Settings → Virus scanning at tcp://clamav:3310.
|
|
#
|
|
# It costs about 1-1.5 GB of memory, because the virus definitions are
|
|
# held in memory, and the first start downloads them before it answers.
|
|
# That is why this is a profile rather than a service everybody runs.
|
|
clamav:
|
|
image: clamav/clamav:stable
|
|
# No ports. clamd has no authentication and no encryption of any kind,
|
|
# so anything that can reach it can use it, and file contents cross
|
|
# that connection in the clear. It is reachable from the application
|
|
# on this network and from nowhere else.
|
|
volumes:
|
|
- clamav-data:/var/lib/clamav
|
|
- ./docker/clamav/clamd.conf:/etc/clamav/clamd.conf:ro
|
|
restart: unless-stopped
|
|
profiles:
|
|
- scanner
|
|
|
|
volumes:
|
|
db-data:
|
|
redis-data:
|
|
clamav-data:
|