Files
projectsend/docker/production/compose.example.yaml
T
ignacionelson 85b1650ef0 Tell a self-hosted installation when nothing is checking its uploads
The dashboard's System card now says so when no scanner is configured
at all, not only when a configured one is failing: "Anything uploaded
here — by staff, by clients, or through an upload link — is passed on
unchecked", with a link to set it up.

Said only where somebody can act on it. Connecting a scanner is a new
capability, scanning.connect, community only — on a hosted installation
the scanner is infrastructure the platform runs, so its address is not a
tenant's to set and its absence is not a tenant's to fix. The two
policies stay on both editions, because what to do with a file nobody
could scan is a decision about somebody's own files. An edition
difference through the registry, never an edition check.

Also: PROJECTSEND_SCANNER_DEFAULT_ADDRESS, seeded into the settings on
first boot by the command that already does this for two-factor
enforcement. It is the opposite of PROJECTSEND_SCANNER_ADDRESS — a
starting value rather than a policy, so a Docker install that brings up
the optional scanner container arrives configured while the address and
the switch stay on the settings screen. Both are seeded together or
neither: an address with scanning off would look configured and check
nothing.

Nothing changes for an existing installation on upgrade: scanning stays
off, existing files are marked "never scanned", and the scanner
container is still opt-in.
2026-09-16 15:34:49 -03:00

149 lines
5.6 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
profiles:
- scanner
volumes:
storage:
db-data:
redis-data:
clamav-data: