mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-17 09:05:08 +00:00
c15c9c48f8
Run against the dev stack with real ClamAV and queue workers, and a code review looking for ways around the scanner. Quarantine now stays quarantined until somebody releases the file. A rescan only touches files people can download, and changes nothing when the scanner cannot answer or scanning is off. Before, an old infected file rescanned while clamd restarted went through the "allow" policy and became downloadable. The daily missing-files check leaves quarantined files alone, so a storage outage no longer brings one back as a fresh upload. A file longer than clamd's StreamMaxLength is "too large" again. clamd answers and hangs up; the next write raised a warning that became an exception before the answer was read, so the file was recorded as "scanner down" and retried past the unscannable policy. The production compose example gives clamd the settings it needs. On its own defaults an encrypted zip comes back clean. The Test button now sends a password-protected zip and fails when it is called clean, and says when an address answers but is not ClamAV. Saving the settings restarts the queue workers, which kept the old values in memory. New scan runs --all, as its name says, and is refused while scans are queued. A retry scheduled for later no longer counts as a scan in progress. Also: quarantine respects client scope for listing, release and notifications; a zip built before a file was quarantined is refused; public comments and version links skip unavailable files; a client no longer sees their own quarantined or missing upload; a file whose bytes return is scanned at once; clamd listens on IPv6 too, so its container health check passes.
178 lines
6.5 KiB
YAML
178 lines
6.5 KiB
YAML
# A complete ProjectSend install using the official image.
|
|
#
|
|
# 1. Edit the passwords and APP_URL below.
|
|
# 2. docker compose -f compose.example.yaml up -d
|
|
# 3. Open APP_URL — the setup screen creates your administrator account.
|
|
#
|
|
# This is the file the Docker Hub description points at, so it is written
|
|
# for someone who has never seen the project before.
|
|
|
|
name: projectsend
|
|
|
|
services:
|
|
app:
|
|
image: projectsend/projectsend:2
|
|
restart: unless-stopped
|
|
ports:
|
|
# Put a TLS-terminating proxy in front of this in any real install.
|
|
# ProjectSend issues download links and password-reset emails using
|
|
# APP_URL, so that value — not this port — is what users must reach.
|
|
#
|
|
# Bound to the loopback address, not to every interface, because
|
|
# TRUSTED_PROXIES below is "*". That setting tells the application to
|
|
# believe the X-Forwarded-For header of whoever connects to it, which
|
|
# is correct behind a proxy and catastrophic when anybody can connect
|
|
# directly: a visitor who reaches this port themselves is then the
|
|
# "proxy", and can hand the application any client IP they like —
|
|
# which is enough to walk straight through the login lockout, every
|
|
# named rate limit, and the address recorded in the download log.
|
|
#
|
|
# Publishing on the loopback address keeps the proxy (on this host,
|
|
# or in this compose file) able to reach it while nothing off the
|
|
# machine can. If you move the proxy to another host, publish on the
|
|
# interface it comes from and narrow TRUSTED_PROXIES to that address
|
|
# or subnet at the same time — the two settings only make sense
|
|
# together.
|
|
- "127.0.0.1:8080:80"
|
|
environment:
|
|
APP_URL: https://files.example.com
|
|
APP_ENV: production
|
|
APP_DEBUG: "false"
|
|
|
|
# Generated on first boot and kept on the storage volume. Set it
|
|
# explicitly if you manage secrets elsewhere — but never change it on
|
|
# a running install: it decrypts existing data.
|
|
# APP_KEY: base64:...
|
|
|
|
DB_CONNECTION: mysql
|
|
DB_HOST: db
|
|
DB_PORT: "3306"
|
|
DB_DATABASE: projectsend
|
|
DB_USERNAME: projectsend
|
|
DB_PASSWORD: change-me-database
|
|
|
|
REDIS_HOST: redis
|
|
CACHE_STORE: redis
|
|
SESSION_DRIVER: redis
|
|
QUEUE_CONNECTION: redis
|
|
|
|
# Uncomment together with the clamav service at the bottom of this
|
|
# file. It is written into the settings once, on first boot, so the
|
|
# site arrives configured — and it stays yours afterwards: the
|
|
# address and the switch are both on System → Settings → Virus
|
|
# scanning, and this line is ignored on every later boot.
|
|
# PROJECTSEND_SCANNER_DEFAULT_ADDRESS: tcp://clamav:3310
|
|
|
|
# Mail is easier to configure from System → Settings → Email once you
|
|
# are logged in — it has a "send test" button. These are the fallback
|
|
# until then.
|
|
MAIL_MAILER: smtp
|
|
MAIL_HOST: smtp.example.com
|
|
MAIL_PORT: "587"
|
|
MAIL_USERNAME: ""
|
|
MAIL_PASSWORD: ""
|
|
MAIL_FROM_ADDRESS: files@example.com
|
|
|
|
# Required whenever anything sits between your visitors and this
|
|
# container — which includes the reverse proxy you should be running.
|
|
# Without it every visitor appears to come from the proxy: the login
|
|
# rate limiter treats all of your users as one attacker, and the
|
|
# download log records the proxy's address.
|
|
#
|
|
# "*" means "trust whoever connects to me", which is only safe when
|
|
# nothing but the proxy can — which is what the loopback binding
|
|
# above is for. Change one and you have to change the other.
|
|
TRUSTED_PROXIES: "*"
|
|
|
|
# Optional: uncomment these — with a password of your own — to create
|
|
# the first administrator unattended and skip the setup screen. Left
|
|
# commented, the setup screen creates it instead. Ignored once any
|
|
# user exists.
|
|
# ADMIN_NAME: Administrator
|
|
# ADMIN_EMAIL: admin@example.com
|
|
# ADMIN_PASSWORD: change-me-admin
|
|
volumes:
|
|
# Every uploaded file lives here, along with the generated APP_KEY.
|
|
# This is the volume to back up; losing it loses the data.
|
|
- storage:/var/www/html/storage
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
|
|
db:
|
|
image: mysql:8.4
|
|
restart: unless-stopped
|
|
environment:
|
|
MYSQL_DATABASE: projectsend
|
|
MYSQL_USER: projectsend
|
|
MYSQL_PASSWORD: change-me-database
|
|
MYSQL_ROOT_PASSWORD: change-me-root
|
|
volumes:
|
|
- db-data:/var/lib/mysql
|
|
healthcheck:
|
|
# The app waits for this before migrating, so a slow first start is
|
|
# normal rather than a failure.
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 20
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
restart: unless-stopped
|
|
volumes:
|
|
- redis-data:/data
|
|
|
|
# Virus scanning, off unless you ask for it:
|
|
# docker compose --profile scanner up -d
|
|
# then point Settings → Virus scanning at tcp://clamav:3310.
|
|
#
|
|
# Budget about 1-1.5 GB of memory: the virus definitions are held in
|
|
# memory. The first start downloads them and does not answer until it
|
|
# has, which the Test button on that screen reports plainly.
|
|
clamav:
|
|
image: clamav/clamav:stable
|
|
restart: unless-stopped
|
|
# Deliberately no ports. clamd has no authentication and no
|
|
# encryption, so anything that can reach it can use it, and files
|
|
# cross that connection in the clear.
|
|
volumes:
|
|
- clamav-data:/var/lib/clamav
|
|
# ClamAV's own defaults are not enough: left on them, clamd answers
|
|
# "OK" for an archive it cannot open, and every password-protected zip
|
|
# would be recorded as clean. The settings it needs are at the bottom
|
|
# of this file.
|
|
configs:
|
|
- source: clamd-conf
|
|
target: /etc/clamav/clamd.conf
|
|
profiles:
|
|
- scanner
|
|
|
|
volumes:
|
|
storage:
|
|
db-data:
|
|
redis-data:
|
|
clamav-data:
|
|
|
|
configs:
|
|
clamd-conf:
|
|
content: |
|
|
LogTime yes
|
|
Foreground yes
|
|
TCPSocket 3310
|
|
|
|
# The largest stream clamd accepts. Keep it at or above "Largest file
|
|
# to scan" on the settings screen, or larger files are not scanned.
|
|
StreamMaxLength 512M
|
|
MaxFileSize 512M
|
|
MaxScanSize 1024M
|
|
MaxRecursion 16
|
|
MaxFiles 10000
|
|
|
|
# Report what could not be opened instead of calling it clean. These
|
|
# four are the reason this file exists.
|
|
AlertExceedsMax yes
|
|
AlertEncrypted yes
|
|
AlertEncryptedArchive yes
|
|
AlertEncryptedDoc yes
|