copyparty: read-only volume (no uploads); correct runbook anon-perms claim
-v /w::A granted anonymous full rwmda on the LAN (verified: anon PUT -> 201, PROPFIND -> 207). New perms ::r:ra,dank: browse/download for anonymous (required by the guarded files.franksdank.cloud chain), admin for dank, no w/m/d for anyone. Runbook corrected with the --help-accounts semantics.
This commit is contained in:
1 parent
207235420c
commit
8e1b00646f
2 files changed
+59
-19
No files matched your search
@@ -77,7 +77,12 @@ services:
|
|||||||
image: ghcr.io/9001/copyparty-ac:latest
|
image: ghcr.io/9001/copyparty-ac:latest
|
||||||
container_name: copyparty
|
container_name: copyparty
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: ["-a", "dank:${COPAY_PASS}", "-v", "/w::A"]
|
# read-only since 2026-08-31: copyparty perms are per-field "letters[,user]"
|
||||||
|
# with no user = every unauthenticated request. Anonymous gets r (browse +
|
||||||
|
# download; the guarded files.franksdank.cloud chain reaches copyparty
|
||||||
|
# unauthenticated after authentik). dank gets ra (admin panel). No w/m/d
|
||||||
|
# anywhere: uploads, moves, deletes rejected server-side. Interface: `--help-accounts` in-image.
|
||||||
|
command: ["-a", "dank:${COPAY_PASS}", "-v", "/w::r:ra,dank"]
|
||||||
ports:
|
ports:
|
||||||
- "3923:3923"
|
- "3923:3923"
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -27,11 +27,28 @@ envs are *not* consumed by this image (zero `COPAY_` references in the
|
|||||||
package). The deployed interface:
|
package). The deployed interface:
|
||||||
|
|
||||||
```
|
```
|
||||||
command: ["-a", "dank:${COPAY_PASS}", "-v", "/w::A"]
|
command: ["-a", "dank:${COPAY_PASS}", "-v", "/w::r:ra,dank"]
|
||||||
```
|
```
|
||||||
|
|
||||||
`-a` takes `USER:PASS`; `-v` takes `SRC:DST:PERMS:FLAGS` — here volume `/w`
|
`-a` takes `USER:PASS`. `-v` takes `src:dst:perm1:perm2:...` (authoritative:
|
||||||
with the `A` ("all") flag for the `dank` account, nothing for anonymous.
|
`python3 -m copyparty --help-accounts` inside the image, v1.20.21): each perm
|
||||||
|
field is `<letters>[,user[,user...]]` and a field with **no username applies to
|
||||||
|
every unauthenticated request**. Letters: `r` read (list + download), `w`
|
||||||
|
upload, `m` move, `d` delete, `a` admin (control panel, config reload), `A` =
|
||||||
|
`rwmda.` (everything). Empty `dst` mounts at the basename of `src` → URL `/w`.
|
||||||
|
|
||||||
|
**Read-only posture (2026-08-31):** `::r` = browse + download for anonymous
|
||||||
|
(required: the guarded `files.franksdank.cloud` chain delivers authentik'd
|
||||||
|
traffic to copyparty *unauthenticated*), `:ra,dank` = admin for the `dank`
|
||||||
|
account. **No `w`/`m`/`d` for anyone** — uploads, moves, and deletes are
|
||||||
|
rejected server-side over HTTP, PUT, and WebDAV alike. There is no dedicated
|
||||||
|
"reject uploads" volflag; the perms field is the documented mechanism
|
||||||
|
(`--help-flags` volflags only throttle/reshape uploads).
|
||||||
|
|
||||||
|
History: the pre-2026-08-31 flag `-v /w::A` was *not* "A for dank, nothing for
|
||||||
|
anonymous" as an earlier revision of this page claimed — the bare `A` granted
|
||||||
|
full read/write/delete to anyone reaching port 3923. Verified live the same
|
||||||
|
day: anonymous `GET /Movies/` → 200, `PROPFIND /` → 207, `PUT` → 201.
|
||||||
|
|
||||||
### Configuration File Options
|
### Configuration File Options
|
||||||
|
|
||||||
@@ -55,27 +72,27 @@ The `iv` edition is no longer available for arm32/armv6. Use `dj` for maximum co
|
|||||||
|
|
||||||
## Volumes
|
## Volumes
|
||||||
|
|
||||||
Live deployment (2026-08-29): the whole LUKS array is served at URL root `/w`
|
Live deployment: the whole LUKS array is served at URL `/w` (the ac edition
|
||||||
via the `-v /w::A` flag — account `dank` holds the `A` (all) flag, anonymous
|
takes its volume roots from argv plus `chdir: /w` in `/z/initcfg`, not from a
|
||||||
gets nothing. The compose bind mount is
|
`/data` convention). Access is **read-only since 2026-08-31** (`-v /w::r:ra,dank`
|
||||||
`/mnt/entropy:/w` (host path → container path); the ac edition serves its
|
— see [[#Command-line interface (ac edition)]] above). The compose bind mount is
|
||||||
volume roots from argv, not from a `/data` convention.
|
`/mnt/entropy:/w` (host path → container path). Note the bind itself is still
|
||||||
|
rw on disk — copyparty enforces read-only at the application layer, so local
|
||||||
|
services (Jellyfin, Calibre) keep writing into the array directly.
|
||||||
|
|
||||||
## Docker Compose
|
## Docker Compose
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
|
||||||
copyparty:
|
copyparty:
|
||||||
image: ghcr.io/9001/copyparty:latest
|
image: ghcr.io/9001/copyparty-ac:latest
|
||||||
container_name: copyparty
|
container_name: copyparty
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
command: ["-a", "dank:${COPAY_PASS}", "-v", "/w::r:ra,dank"]
|
||||||
COPAY_PASS: "${COPAY_PASS}"
|
|
||||||
COPAY_MODE: rw
|
|
||||||
ports:
|
ports:
|
||||||
- "3923:3923"
|
- "3923:3923"
|
||||||
volumes:
|
volumes:
|
||||||
- /opt/copyparty/data:/data
|
- /mnt/entropy:/w
|
||||||
|
- /opt/copyparty/cfg:/cfg
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3923/')"]
|
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3923/')"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
@@ -83,6 +100,21 @@ services:
|
|||||||
retries: 3
|
retries: 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`${COPAY_PASS}` is compose-time interpolation from `dankserver/.env` — the
|
||||||
|
password lands in the container's **argv**, visible to anyone who can run
|
||||||
|
`podman inspect copyparty` on the host.
|
||||||
|
|
||||||
|
**Applying changes:** `scripts/deploy.sh` deliberately does not touch the
|
||||||
|
dankserver compose stack (host containers are not quadlet-managed there), so
|
||||||
|
`command:` edits need a manual recreate on Dankserver:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd /home/dank/serverAppConfigs/dankserver && podman-compose up -d --force-recreate copyparty
|
||||||
|
```
|
||||||
|
|
||||||
|
Same project (`dankserver`), only copyparty is recreated; a fresh container
|
||||||
|
answers `000` for the first seconds while it mounts.
|
||||||
|
|
||||||
## Healthcheck
|
## Healthcheck
|
||||||
|
|
||||||
A simple HTTP check on port 3923 works. The root path returns HTTP 200 with the directory listing.
|
A simple HTTP check on port 3923 works. The root path returns HTTP 200 with the directory listing.
|
||||||
@@ -106,10 +138,13 @@ Upgrade to v1.20.19+ to cover all known CVEs. The dirkey fix (v1.20.17) matters
|
|||||||
- **Large transfers:** Disable TLS inside the app and let Caddy terminate TLS. This avoids double encryption overhead.
|
- **Large transfers:** Disable TLS inside the app and let Caddy terminate TLS. This avoids double encryption overhead.
|
||||||
- **Dedicated share directory:** Do not give Copyparty the whole disk. Mount only the intended share path.
|
- **Dedicated share directory:** Do not give Copyparty the whole disk. Mount only the intended share path.
|
||||||
- **Whole-disk share (live choice):** this deployment *does* serve the whole
|
- **Whole-disk share (live choice):** this deployment *does* serve the whole
|
||||||
91 T array (`-v /w::A`). Safe only because anonymous gets zero permissions —
|
91 T array from `/w`. Since 2026-08-31 the volume is application-level
|
||||||
every request authenticates against the `dank` account first, and Caddy +
|
read-only for every account, so no remote write path exists. But note:
|
||||||
Anubis + authentik sit in front (see [[Anubis]], [[Authentik]]). Strip the
|
**LAN-direct `:3923` is unauthenticated browse/download** (anonymous holds
|
||||||
`A` flag or drop the account and the array becomes world-writable again.
|
`r`) — Caddy + Anubis + authentik guard only `files.franksdank.cloud`, not
|
||||||
|
the published port. Tighten to `-v /w::r,dank` if anonymous LAN reads become
|
||||||
|
unacceptable. (Before 2026-08-31, `-v /w::A` made the array world-writable
|
||||||
|
on the LAN — see [[#Command-line interface (ac edition)]].)
|
||||||
- **Upload tokens scoped per folder:** Prevents accidental global write access.
|
- **Upload tokens scoped per folder:** Prevents accidental global write access.
|
||||||
- **CSP nonces (v1.20.17+):** Security hardening for JavaScript execution. May break third-party JS plugins (`--js-browser` / `--html-head`).
|
- **CSP nonces (v1.20.17+):** Security hardening for JavaScript execution. May break third-party JS plugins (`--js-browser` / `--html-head`).
|
||||||
- **Custom thumbnail extractors (v1.20.19+):** New `thumbex` framework. Requires configuration in `initcfg`.
|
- **Custom thumbnail extractors (v1.20.19+):** New `thumbex` framework. Requires configuration in `initcfg`.
|
||||||
|
|||||||
Reference in new issue
Block a user