Jesse A. Green / notebook

copyparty Admin Guide

Generated June 2026 from 9001/copyparty at 6e75faa

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the administrators, operators, and developers who deploy, secure, tune, and extend copyparty. It covers the architecture, the complete configuration model, security hardening, operational procedures, and the internals needed to understand — or reproduce — the project. End-user features (the browser UI, uploading, media playback) live in the User Guide; this guide links there where appropriate.

copyparty is version 1.20.16 ("sftp is fine too"), a portable file server written in Python with accelerated resumable uploads, deduplication, WebDAV/SFTP/FTP/TFTP/SMB protocols, zeroconf discovery, a media indexer, video thumbnails, audio transcoding, and write-only folders. Its single mandatory dependency is jinja2; everything else is optional and feature-gated.


1. Executive Summary

Aspect Detail
What it is A single-process, multi-protocol file server runnable from one .py file
Language Python (2.7 and 3.3+), no compiled components required
Mandatory deps jinja2 only (bundled in sfx/exe)
Default HTTP port 3923 (HTTP and HTTPS on the same port)
Config model Global options + per-volume "volflags"; CLI args and/or YAML-ish config files
Auth model Accounts + per-folder permissions; optional IdP / header / IP-range auth
Storage Plain filesystem volumes; optional SQLite index per volume (.hist/up2k.db)
Deployment Standalone, systemd, OpenRC, Docker/Podman, NixOS, behind a reverse proxy
License MIT (with optional GPL tooling kept strictly out-of-process)

Design philosophy — "inverse unix philosophy": do all the things and do an okay job. The priorities are: run anywhere, support every browser and Python version, minimize mandatory dependencies, and require no build step (the JS and Python are editable in place).

Note

Becoming rich is explicitly not a project goal. This shapes the architecture: simplicity, portability, and plaintext auditability are valued over polish or enterprise integration.


2. Architecture

2.1 High-level component map

                          ┌──────────────────────────────────────────┐
                          │              SvcHub (svchub.py)            │
                          │  orchestrator: config, logging, lifecycle, │
                          │  signal handling, service startup/reload   │
                          └───────────────┬────────────────────────────┘
                                          │ owns / starts
        ┌──────────────┬──────────────┬───┴────────┬──────────────┬───────────────┐
        ▼              ▼              ▼            ▼              ▼               ▼
   ┌─────────┐   ┌──────────┐   ┌─────────┐  ┌──────────┐  ┌──────────┐   ┌────────────┐
   │ AuthSrv │   │ HttpSrv  │   │  Up2k   │  │ ThumbSrv │  │  Ftpd /  │   │ MDNS/SSDPd │
   │ authsrv │   │ httpsrv  │   │ up2k.py │  │ th_srv   │  │ Sftpd /  │   │ zeroconf   │
   │  .py    │   │  .py     │   │         │  │          │  │ Tftpd /  │   │            │
   │ VFS +   │   │ per-conn │   │ upload  │  │ image/   │  │ SMB      │   │ LAN announce│
   │ accounts│   │ HttpConn │   │ engine, │  │ video/   │  │ servers  │   │            │
   │ + vols  │   │ +HttpCli │   │ dedup,  │  │ audio    │  │          │   │            │
   └─────────┘   └────┬─────┘   │ index   │  │ thumbs   │  └──────────┘   └────────────┘
                      │         └────┬────┘  └──────────┘
                      ▼              ▼
                 ┌─────────┐   ┌──────────┐
                 │  U2idx  │   │   MTag   │
                 │ u2idx.py│   │ mtag.py  │
                 │ search  │   │ metadata │
                 └─────────┘   └──────────┘

   TcpSrv (tcpsrv.py) — owns sockets / interface detection / port binding
   BrokerMp / BrokerThr — message bus between processes (multiprocessing) or threads

2.2 Core components

Component Module Responsibility
SvcHub svchub.py Master orchestrator. Sets up DB, logging, signal handlers; starts/stops/reloads FTP/SFTP/TFTP/HTTP servers; owns the broker.
AuthSrv authsrv.py Parses accounts, groups, and volumes; builds the VFS (virtual filesystem) tree; resolves per-request permissions; loads IdP/session databases.
VFS authsrv.py The virtual filesystem — maps URL paths to real folders, applies volflags, computes access (can_access, get_perms), supports shadowing and bubbling flags.
HttpSrv httpsrv.py Accepts HTTP(S) connections, manages worker threads, dispatches each to an HttpConn.
HttpConn httpconn.py One TCP connection; handles TLS handshake, reverse-proxy detection, and hands requests to HttpCli.
HttpCli httpcli.py The request handler — an ~80-method class implementing every HTTP verb, the HTTP API, uploads, downloads, listings, search, and the web UI.
Up2k up2k.py The resumable-upload engine: chunked hashing, dedup (symlink/hardlink/reflink), the SQLite index, file-search backend, lifetime/self-destruct.
U2idx u2idx.py Query engine over the up2k index — powers search and file-search.
MTag mtag.py Media-tag extraction via Mutagen or FFprobe, plus external parser plugins (mtp).
ThumbSrv / ThumbCli th_srv.py / th_cli.py On-demand thumbnail and audio-transcode generation (Pillow / pyvips / FFmpeg), with a disk cache.
TcpSrv tcpsrv.py Socket creation, NIC/interface detection, port binding, network monitoring.
BrokerMp / BrokerThr broker_mp.py / broker_thr.py Inter-node message bus. BrokerMp spans real OS processes (multiprocessing); BrokerThr is the single-process threaded fallback.

2.3 Protocol servers

Each non-HTTP protocol is an optional, self-contained server bound to its own port:

Protocol Module Backend library Default port
FTP / FTPS ftpd.py pyftpdlib (+ pyopenssl for TLS) 3921 / 3990
SFTP sftpd.py paramiko 3922
SMB / CIFS smbd.py impacket 3945 (→445)
TFTP tftpd.py partftpy 3969 (→69)
WebDAV within httpcli.py — (shares the HTTP port) 3923
mDNS / SSDP mdns.py / ssdp.py (multicast.py) bundled stolen/dnslib 5353 / 1900 UDP

Important

The HTTP/HTTPS API and WebDAV share port 3923. FTP, SFTP, TFTP, and SMB each require a dedicated port that cannot be shared with HTTP.

2.4 Multiprocessing model

By default copyparty runs single-process with a thread pool. Passing -j N (or -j0 for all cores) spawns multiple worker processes coordinated through BrokerMp. Multiprocessing reduces latency under heavy concurrency and accelerates directory listings when the index is enabled, but it increases filesystem/HDD load and adds inter-process overhead, so the single-process default is best for most deployments.

Caution

Several Prometheus metrics (cpp_http_conns, cpp_http_reqs, cpp_sus_reqs, cpp_active_bans, cpp_total_bans) are counted incorrectly when multiprocessing is enabled, because each process counts independently.

2.5 Bundled ("stolen") dependencies

To keep the mandatory dependency list at one (jinja2), copyparty vendors a few small libraries under copyparty/stolen/: dnslib (for mDNS), ifaddr (NIC discovery), and qrcodegen.py (QR codes). Each can be forced to use the system version via PRTY_SYS_DNSLIB, PRTY_SYS_IFADDR, PRTY_SYS_QRCG, or all at once with PRTY_SYS_ALL.


3. System Requirements

Resource Requirement
Python 2.7, or 3.3 through 3.14. CPython, PyPy, and Jython are all supported.
CPU/RAM Minimal — known to run on an SGI O2 with 64 MiB RAM. RAM scales with thumbnail engine (pyvips uses ~270 % more than Pillow but is faster).
Disk Volume storage + per-volume .hist/ (index DB, thumbnail cache, transcode cache, markdown history). Put .hist/ on an SSD for best performance.
OS Windows, Linux, macOS, FreeBSD, Android, iOS, and many exotic platforms (big-endian, IRIX, etc.).

Optional dependencies and the features they unlock

Dependency Feature
argon2-cffi Hashed passwords in config (--ah-alg argon2)
pyftpdlib FTP server (bundled in sfx)
pyftpdlib + pyopenssl FTPS (TLS)
paramiko SFTP server
partftpy>=0.4.0 TFTP server
impacket==0.13.0 SMB/CIFS server (not recommended)
mutagen or ffprobe Audio/media tag indexing
Pillow and/or pyvips and/or ffmpeg Image thumbnails
ffmpeg + ffprobe Video/audio thumbnails and transcoding
pyvips / ffmpeg / pillow-heif HEIF/HEIC thumbnails
libraw dcraw_emu or rawpy RAW-photo thumbnails
pyzmq ZeroMQ messages from event hooks
python-magic Filetype detection for nameless uploads
psutil Reaping stuck hooks/plugins on Windows

The pip extras map directly to these: pip install copyparty[all], or granular extras thumbnails, thumbnails2, audiotags, sftp, ftpd, ftps, tftpd, pwhash, zeromq.

Warning

mutagen makes copyparty's effective license GPL-adjacent and is fast but skips some tags. ffprobe is ~20× slower, catches more tags (key, resolution, framerate), avoids GPL code — but runs FFmpeg on incoming files, which is dangerous if your FFmpeg has an unpatched CVE and you allow anonymous upload.


4. Configuration Mastery

copyparty has two configuration scopes:

  • Global options — server-wide; set as CLI flags (--foo) or in the config-file [global] section.
  • Volflags — per-volume; set inline on a -v flag (:c,foo=bar) or in a volume's flags: block.

Most options work in both scopes. The authoritative, always-current list of every option is copyparty --help, every volflag is --help-flags, and accounts syntax is --help-accounts.

4.1 Volume and account syntax

-a USERNAME:PASSWORD
-v SRC:DST:PERM[,USER...]:PERM[,USER...]:c,VOLFLAG[=VALUE]
  • SRC = real filesystem path, DST = URL path, then permission groups (see User Guide §6.1), then c,-prefixed volflags.
  • Example combining everything:
    -v /mnt/ss:i:rw,u1:g:c,fk=4
    # /mnt/ss served at /i; read-write for u1; get-only for everyone else; filekey length 4
    

4.2 Config file structure

[global]
  e2dsa            # global options, one per line; value after the name
  z                # boolean flags need no value
  lo: /var/log/cpp/%Y-%m-%d.txt

[accounts]
  ed: hunter2      # comments need TWO spaces before #

[groups]
  admins: ed, k

[/url/path]        # a volume
  /srv/realpath    # the folder it maps to
  accs:
    r: *
    rw: ed
  flags:
    e2ds
    fk: 4

Tip

A config file may pass additional CLI arguments through [global]. You can chain multiple -c file.conf. Set PRTY_CONFIG=foo.conf as an environment variable as an alternative to -c.

4.3 Option groups (from --help)

copyparty --help is organized into these sections — use them as a map of the configuration surface:

Group Covers
general options core behavior, ports, -c config files
qr options --qr, --qrs, --qrl, --qr-file, …
filesystem options volumes, --hist, --xdev, --xvol, dedup
share-url options --shr, --shr-adm, --shr-who, --shr-rt
upload options --u2sz, --u2ow, --unpost, lifetime, rules
network options -i, -p, --xff-hdr, --xff-src, --rproxy, --rp-loc
SSL/TLS options --cert, --certkey, --no-crt
TLS certificate generator cfssl-based CA/cert generation, --crt-*
IdP / identity provider --idp-*, --auth-ord, header auth
user-changeable passwords --chpw, --chpw-no, --chpw-db
Zeroconf / mDNS / SSDP -z, --z-on, --zsv, --name
SFTP / FTP / WebDAV / TFTP / SMB each protocol's flags
OPDS options --opds, --opds-exts
handlers / event hooks --xau, --xbu, etc.; --help-hooks
grafana/prometheus metrics --stats, --nos-*
yolo / opt-outs / safety --allow-csrf, -s/-ss/-sss, --no-*
salting options --fk-salt, --dk-salt, --ah-salt
logging options -q, -lo, --flo, --no-ansi, --log-date
admin panel / thumbnail / transcoding --no-thumb, --th-*, --ac-maxage
tailing / RSS / textfile / og / ui viewer + embed + UI tweaks
general & metadata db options -e2*, --db-*, -mte/-mtp/-mtm
debug options diagnostics
help sections --help-accounts, --help-flags, --help-hooks, …

4.4 File indexing

Indexing powers search, upload-undo, and reliable dedup. Two tables live in .hist/up2k.db: the up2k filetree (-e2d) and metadata tags (-e2t).

Flag Effect
-e2d Index files on upload
-e2ds + scan writable folders on startup
-e2dsa + scan all volumes (including read-only) on startup
-e2t Index media tags on upload
-e2ts + scan untagged files on startup
-e2tsr + delete all tags and do a full reindex
-e2v / -e2vu / -e2vp Verify integrity at startup / patch DB / panic on mismatch

The same flags work as volflags; d2d, d2ds, d2t, d2ts, d2v disable indexing per-volume.

Note

The recommended baseline for most deployments is -e2dsa -e2ts (index everything, scan media tags). Folder thumbnails are chosen during indexing, so a periodic rescan keeps them current.

4.5 Database location

By default each volume gets a .hist/ subfolder. Relocate it with:

  • --hist /path — global default location.
  • hist= volflag — per-volume override (- restores the in-volume default).
  • --dbpath / dbpath volflag — move just the SQLite DB, separate from thumbnails.
  • landmark volflag — require a known file to exist before touching the DB (guards against NFS/HDD outages causing spurious rescans).

Tip

Put .hist/ on an SSD. On Windows, --hist takes a regular path but the volflag path is cyg-style (/c/temp = C:\temp).

4.6 Deduplication

Enable with --dedup (global) or dedup (volflag). When a duplicate is uploaded, copyparty links it instead of storing a second copy:

Mode Flag Trade-off
Symlink (default) --dedup Per-copy timestamps; obviously not a regular file
Hardlink --hardlink-only / hardlinkonly Looks like a regular file; movable by other tools
Reflink (CoW) --reflink / reflink Safest; Linux 5.3+, Python 3.14+, btrfs/xfs only

Warning

Editing the contents of a deduplicated file edits all copies — most surprising with hardlinks, which look like ordinary files. When enabling dedup, also enable indexing (-e2dsa) so renames/deletes stay safe. --safe-dedup 1 speeds uploads by skipping content re-verification (safe only if no other software touches the files). --no-clone disables dedup detection entirely (useful for expensive cold storage like S3-Glacier).

4.7 Upload rules (volflags)

Volflag Effect
sz=1k-3m Allowed filesize range
df=4g Block uploads below this free disk space
vmaxb=1g / vmaxn=4k Cap total volume bytes / file count (needs e2ds)
nosub Disallow uploads into subdirectories
rotn=1000,2 Auto-bucket uploads into subfolders (1000/folder, 2 deep)
rotf=%Y/%m/%d/%H Force date-structured upload paths
lifetime=300 Self-destruct uploads after N seconds
maxn=250,3600 Per-IP: 250 files / hour
maxb=1g,300 Per-IP: 1 GiB / 5 min

Note

Per-IP transaction limits (maxn/maxb) assume -j 1. With multiprocessing the effective limit multiplies by the worker count, since each node tracks independently.

4.8 Compression on upload

  • gz / xz volflags allow that algorithm; pk forces compression on all files (pk=xz,0 = forced xz level 0).
  • URL params ?pk, ?gz, ?xz request compression per-upload.
  • Compressed files are indexed after compression, so dedup/file-search won't match the originals.

4.9 Filesystem guards

  • --xdev / xdev — never traverse into another filesystem (skip cross-device symlinks/bind-mounts).
  • --xvol / xvol — ignore symlinks leaving the volume root (bind-mounts still allowed).

Since v1.7.0 these also block runtime access, not just indexing. Expect up to ~14 % slower listings and ~35 % slower tar downloads.

4.10 Periodic rescan

If other software modifies the filesystem, keep the index fresh:

  • --re-maxage 60 (global) or scan=60 (volflag) — rescan every N seconds.
  • Uploads pause during a rescan; rescans are deferred by --db-act (default 10 s) while writes are in progress.

4.11 Metadata configuration

  • -mte — which tags to index and display (and their order); per-volume via mte=.
  • -mth — index + make searchable but hide from default display.
  • -mtm qux=foo,bar — define/redefine a tag mapping (qux from foo or bar).
  • -mtp .bpm=~/bin/audio-bpm.py — external parser plugin to provide a tag. Plugins support audio-only (ay), non-audio (an), all (ad), extension filters (eexe), timeouts (t5), ordering (p1), and kill modes (kt/km/kn).
  • --db-xattr user.foo,user.bar — index Linux extended attributes (must also appear in -mte).

4.12 Other notable options

  • --mime gif=image/jif — override a file extension's MIME type (--mimes lists defaults).
  • cachectl / ?cache=321 — control browser Cache-Control.
  • chmod_f / chmod_d / uid / gid volflags — per-volume filesystem permissions and ownership (uid requires running as root).
  • dothidden — cosmetically hide files listed in a folder's .hidden file (not a security boundary).
  • --unlist — hide a whole volume from HTTP listings (HTTP-only; dothidden also affects ftp/sftp).

5. Network, TLS, and Reverse Proxy

5.1 Listening

  • -i sets the bind interface(s); default :: (all). -p 80,443 listens on multiple ports.
  • Listen on a unix socket for ~10 % more performance and tighter access control: -i unix:770:www:/dev/shm/party.sock.

5.2 Binding to ports 80/443

Platform Approach
Windows / macOS Just -p 80,443
Linux (recommended) A reverse proxy (also gives real HTTPS)
Linux (NAT) iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3923
Linux (capability) setcap CAP_NET_BIND_SERVICE=+eip $(realpath $(which python))

5.3 HTTPS / TLS

Both HTTP and HTTPS are accepted on the same port. copyparty has built-in TLS, but the recommended setup is to terminate TLS at a reverse proxy:

  • Reverse proxies follow TLS best practices better and support HTTP/2 and QUIC (copyparty speaks neither — though HTTP/1.1 is often faster anyway).
  • If cfssl is installed, copyparty auto-generates a self-signed CA + server cert on startup (written to --crt-dir); you must install ca.pem into clients.
  • To supply your own cert: --no-crt --cert server.pem (key+cert+chain concatenated), or --no-crt --cert server.crt --certkey server.key. All files must be PEM.

5.4 Reverse-proxy and real-IP

When behind any proxy (including Cloudflare), real-IP configuration is critical — bans, rate limits, and IP-auth all rely on the true client IP.

[global]
  xff-hdr: cf-connecting-ip   # header carrying the real IP (x-forwarded-for for most)
  # also configure --xff-src (trusted proxy IP) and --rproxy
  • --rproxy 1 if the header contains exactly one (correct) IP; a negative value picks from a multi-IP header (-1 = rightmost/nearest hop, -2 = second-nearest, …).
  • --rp-loc=/stuff for location-based proxying (slight perf cost; needs correct real-IP first).
  • --rproxy 0 only if copyparty directly faces the internet (otherwise CORS misbehaves).

Reference configs ship in contrib/ for nginx (recommended), apache, haproxy, lighttpd, caddy, and traefik.

Caution

Use traefik v3.6.7 or newer — older versions are affected by CVE-2025-66490.

Reverse-proxy performance (uds, fastest first): haproxy > caddy > traefik > nginx > apache > lighttpd. Connecting via a unix socket beats 127.0.0.1 across the board. nginx-QUIC (HTTP/3) is experimental and can make uploads much slower — prefer HTTP/1.1.

5.5 Zeroconf discovery

  • -z enables both mDNS and SSDP; --z-on / --z-off restrict to subnets.
  • mDNS gives a .local domain (e.g. partybox.local, from hostname or --name) visible to KDE/GNOME/macOS file managers.
  • SSDP makes copyparty appear in Windows Explorer; use --zsv to debug if it doesn't show.

6. Identity, Authentication, and Access Control

6.1 Built-in accounts

Accounts (-a user:pwd) with per-volume permissions are the baseline (see User Guide §6). Bruteforce protection: --ban-pw (default 24 h ban after 9 fails/hour).

6.2 Identity providers (IdP)

--idp-* options replace copyparty's passwords with an external SSO (Authelia, authentik, OAuth, LDAP, passkeys, etc.):

  • Config-defined users serve as a fallback for requests without a trusted IdP header; --auth-ord sets precedence.
  • --idp-login / --idp-logout repoint the UI buttons ({dst} expands to the current page).
  • --idp-cookie lets requests bearing the cppws cookie bypass a slow IdP.
  • Header mapping: --idp-hm-usr '^Tailscale-User-Login^[email removed]^alice' auto-auths by an upstream header.

A docker-compose example (Authelia + traefik) ships in docs/examples/docker/idp-authelia-traefik; see also docs/idp.md.

6.3 IP-based auth

  • --ipu 192.168.123.0/24=spartacus — autologin a CIDR range as a user.
  • --ipr 192.168.123.0/24,172.16.0.0/16=spartacus — restrict a user to certain CIDRs.

Caution

With IP-auth behind a reverse proxy, real-IP must be correct, and you should null-map the proxy's own IP (--ipu=172.24.27.9/32=) to avoid auto-logging-in the proxy.

6.4 User-changeable passwords

--chpw lets users change their own passwords in the control panel (default off because account-sharing is common). Stored in --chpw-db (default chpw.json); --chpw-no name1,name2 denies specific accounts. Not compatible with IdP.


7. HTTP API

Authentication order (first non-blank wins): url-param ?pw=, header PW:, basic-auth, then cookie (cppwd on HTTP, cppws on HTTPS).

7.1 Read operations (GET)

Params Result
?dl Download (force, don't render in browser)
?ls / ?ls&dots / ?ls=t / ?ls=v List as JSON / +dotfiles / plaintext / terminal
?opds List as an OPDS feed
?tree=. / ?tree List one level of subdirs / each level to URL
?tar / ?tar=gz:9 / ?tar=xz:9 / ?tar=pax Download subtree as tar (variants)
?zip / ?zip=dos / ?zip=crc Download subtree as zip (variants)
?tar&w / ?tar&j / ?tar&p Pre-generate webp / jpg thumbnails / audio waveforms
?shares / ?dls / ?ups / ?ru List shares / active downloads / your uploads / all recent uploads
?v Render markdown, or open media in the player
?txt / ?txt=iso-8859-1 Get file as plaintext (with charset)
?tail / ?tail=1024 / ?tail=-128 Stream a growing file (from byte / from end)
?th / ?th=opus / ?th=caf Thumbnail / transcode audio to opus / caf
?zls / ?zget=path List / fetch a file inside a zip at URL
?mime=foo Force a response MIME type

7.2 Write operations

Method Params / Body Result
PUT (binary) Upload into file at URL
PUT ?j / ?ck / ?ck=md5 + JSON reply / no checksum / md5
PUT ?gz / ?xz / ?apnd Compress with gzip/xz / append
mPOST f=FILE Upload FILE into folder at URL
mPOST ?replace / ?apnd / ?media Overwrite / append / return medialink
mPOST act=mkdir, name=foo Create directory
mPOST act=tput, body=TEXT Overwrite a markdown doc
POST ?copy=/foo / ?move=/foo Copy / move-rename
POST ?delete Delete URL recursively
jPOST ?delete ["/foo","/bar"] Delete multiple
jPOST ?share (payload) Create a temporary share URL
POST ?eshare=rm / ?eshare=3 Stop sharing / set 3-min expiry
uPOST msg=foo Send a message into the server log

Upload modifiers (header or url-param): want=url/want=json, rand=4, life=30, replace, and checksum selectors ck, ck=md5, ck=sha1, ck=sha256, ck=b2, ck=b2s. copyparty returns a truncated, url-safe base64 sha512 of the upload by default.

7.3 Admin / general

Params Result
?reload=cfg Reload config files and rescan volumes
?scan / ?scan=/a,/b Rescan the providing volume / specific volumes
?stack Dump all thread stacktraces (diagnostics)
?grid / ?imgs / ?thumb UI view toggles

8. Security

8.1 Hardening checklist

  • [ ] Set explicit accounts and volume permissions — never rely on the zero-arg default.
  • [ ] Behind a proxy, configure real-IP (--xff-hdr, --xff-src, --rproxy); set --rproxy 0 only if directly internet-facing.
  • [ ] Listen on a unix socket behind the proxy for tighter access control.
  • [ ] For untrusted/anonymous-upload volumes, set volflag nohtml to neutralize XSS (serves HTML/SVG as plaintext, disables markdown rendering and JS).
  • [ ] Enable a version-checker feed.
  • [ ] Consider password hashing.
  • [ ] Sandbox with prisonparty (chroot) or bubbleparty (bubblewrap), especially for SMB.

8.2 Safety profiles

Flag Bundles
-s --no-thumb, --no-mtag-ff (use mutagen), --dotpart (hide incoming uploads), --no-robots, --force-js
-ss -s + --unpost 0, --no-del, --no-mv, --hardlink, --vague-403 (404 instead of 401), -nih (hide hostname)
-sss -ss + --no-dav, --no-logues, --no-readme, disk logging, startup symlink scan

Important

Disabling thumbnails/transcoding via --no-thumb is strongly recommended when anonymous upload is enabled, because it stops copyparty from running FFmpeg/Pillow/VIPS on attacker-supplied files — a frequent CVE surface.

8.3 Gotchas and XSS vectors

  • Users without read access can still see .prologue.html / .epilogue.html / README.md / PREADME.md contents (intentional, for upload instructions).
  • Users may inject auto-running (sandboxed) <script> by uploading a README.md (block with --no-readme) or renaming a file to .epilogue.html (block with --no-logues / --no-dot-ren).
  • Markdown documents can carry HTML/<script>; the directory-listing embed is sandboxed but the markdown editor isn't 100 % safe. The nuclear option is the nohtml volflag.

8.4 Password hashing

--ah-alg argon2 hashes config/argument passwords (prints hashed versions on startup to copy back). --ah-cli enters an interactive mode that never writes plaintext to disk. Defaults take ~0.4 s and 256 MiB RAM per password. Keep --ah-salt consistent across environments (inspect with --show-ah-salt). With --usernames, hash as user:password.

8.5 CORS

By default, all requests except GET/HEAD must either omit Origin, match the server domain, or carry the PW header. Configure with --acao / --acam, or disable entirely with --allow-csrf.

8.6 Filekeys and dirkeys

  • Filekeys (fk): per-file access keys from --fk-salt + path + size + inode. fka makes weaker keys that survive edits (salt + path only).
  • Dirkeys (dk): per-directory keys from --dk-salt + path. dky skips the key check (g-users see folder contents but not subfolders); dks allows entering subfolders and zip/tar.

8.7 Malicious-repo / abuse posture

copyparty bans IPs that send 403/422/malicious requests (visible as cpp_sus_reqs / cpp_active_bans in metrics). The version-checker can panic-exit on a known vulnerability (--vc-exit). For GDPR, disable or rotate logging (-lo cpp-%Y-%m%d.txt.xz) and forget uploader IPs after a window (--forget-ip 43200).


9. Operations

9.1 Running as a service

Init system Resource
systemd contrib/systemd/copyparty.service (+ prisonparty.service for chroot, copyparty@.service, copyparty-user.service)
OpenRC (Alpine/Gentoo) contrib/openrc/copyparty
FreeBSD rc contrib/rc/copyparty
Podman + systemd contrib/podman-systemd/
NixOS services.copyparty module

copyparty understands NOTIFY_SOCKET (systemd Type=notify) and S6_NOTIFY_FD (s6/dinit ready-notification).

Open the relevant firewall ports (complete example, every feature enabled):

firewall-cmd --permanent --add-port={80,443,3921,3922,3923,3945,3990}/tcp
firewall-cmd --permanent --add-port=12000-12099/tcp   # passive FTP
firewall-cmd --permanent --add-port={69,1900,3969,5353}/udp
firewall-cmd --reload

(69 tftp, 1900 ssdp, 3921 ftp, 3922 sftp, 3923 http/https, 3945 smb, 3969 tftp, 3990 ftps, 5353 mdns, 12000+ passive-ftp)

9.2 Version-checker

Subscribe to a security-advisory feed to be warned of known vulnerabilities:

[global]
  vc-url: https://api.copyparty.eu/advisories   # or -panic / -all
  vc-age: 3        # hours between checks
  vc-exit          # panic-exit if current version is vulnerable

Without --vc-exit, a warning shows in the control panel for admin (a/A) users.

9.3 Logging

stdout by default (terminal / journalctl / docker logs):

[global]
  q                            # disable stdout logging (small perf win)
  lo: /var/log/cpp/%Y-%m-%d.txt  # daily logfiles; %Y-%m-%d rotates by date
  flo: 2                       # no colors in the logfile
  log-date: %Y-%m-%d           # show dates on stdout too

--no-ansi removes colors everywhere; --rlo controls collision behavior when a logfile name is taken.

9.4 Configuration reload

systemctl reload copyparty (or kill -s USR1) reloads accounts and volumes from config files without dropping connections; the [reload cfg] control-panel button does the same for admin users. [global] changes still require a restart. The HTTP API equivalent is GET ?reload=cfg.

Note

The SMB hot-reload does not pick up [global] (commandline) changes.

9.5 Prometheus metrics

Enable with --stats (and usually -e2dsa); scrape /.cpr/metrics (OpenMetrics 1.0.0). Only admin accounts can read it.

scrape_configs:
  - job_name: copyparty
    metrics_path: /.cpr/metrics
    basic_auth:
      password: wark
    static_configs:
      - targets: ['192.168.123.1:3923']

Key metrics: cpp_uptime_seconds, cpp_active_dl, cpp_http_conns, cpp_http_reqs, cpp_sus_reqs, cpp_active_bans/cpp_total_bans, plus per-volume cpp_vol_bytes, cpp_vol_files, cpp_dupe_bytes/cpp_dupe_files, cpp_disk_size_bytes/cpp_disk_free_bytes, and queue gauges (cpp_hashing_files, cpp_tagq_files, cpp_mtpq_files). Disable subsets with --nos-hdd / --nos-vol / --nos-vst / --nos-dup / --nos-unf.

9.6 Thumbnail pregeneration

Thumbnails are on-demand by default, cached for --th-maxage (1 week). To pre-generate on startup, set th-pregen / th_pregen to a comma-list of formats (j,jf,jf3,j3,w,wf,...,opus,mp3,flac,wav). Budget: regular thumbnails ~16 KiB, triple-size ~96 KiB each. Audio transcodes are treated as thumbnails (expiry via --ac-maxage).

9.7 Event hooks and external integration

  • --xau / --xbu (and move/delete equivalents) run a program before/after an event; see --help-hooks and bin/hooks/.
  • Hooks can instead emit ZeroMQ messages: --xau zmq:pub:tcp://*:5556 (PUB), --xau t3,zmq:push:tcp://*:5557 (PUSH), --xau t3,j,zmq:req:tcp://localhost:5555 (REQ with JSON).
  • The older mtp-based upload-event mechanism (bin/mtag/) is non-blocking, multithreaded, gives access to FFmpeg tags, and fires only on new unique files.
  • Handlers (bin/handlers/) replace 403/404 behavior.

9.8 Performance tuning

  • Disable HTTP/2 and HTTP/3 → up to 5× faster uploads.
  • -q (disable stdout logging) helps even with -lo.
  • --hist on SSD speeds listings, searches, and thumbnails.
  • --dedup avoids writing dupes; --safe-dedup 1 speeds upload verification.
  • --no-dirsz → ~30 % faster listings (shows inode size, not content total).
  • --no-hash . when indexing a network disk if you only need names/tags searchable.
  • Larger --iobuf / --s-rd-sz / --s-wr-sz (e.g. 1–4 MiB) help on NFS/SMB/S3.
  • -j0 enables real multiprocessing — helps with many connections and saturated 20 Gbps links, but usually reduces performance otherwise.
  • On musl distros, mimalloc (LD_PRELOAD) trades 2× RAM for higher throughput.
  • On Windows/macOS, --casechk=n is much faster (with the usual case-insensitive-FS caveats).

9.9 Cloud storage as a volume

There is no native S3 support. Mount cloud storage with rclone / geesefs / JuiceFS as a local folder, then point a copyparty volume at it. Tune with --iobuf / --s-rd-sz / --s-wr-sz; try the default, sparse, and nosparse volflags to find the best throughput for your stack.


10. Packaging and Distribution Internals

Artifact Notes
sfx (copyparty-sfx.py) Self-extractor; unpacks an embedded tar.gz into $TEMP. copyparty-en.py is English-only/smaller. Repackable to shrink.
exe copyparty.exe (win8+, bundles Pillow), copyparty32.exe (win7, Python 3.7.9 — LAN only, never internet).
zipapp (copyparty.pyz) Normal zipfile, runs without unpacking to disk; fewer features, can't benefit from newer jinja2.
PyPI copyparty package; console scripts copyparty, u2c, partyfuse.
PyInstaller Build scripts in scripts/pyinstaller/.
Docker scripts/docker/; image variants min/ac/im/iv/dj bundle increasing dependency sets.

The version is the single source of truth in copyparty/__version__.py (VERSION = (1, 20, 16), BUILD_DT = (2026, 5, 26)), consumed by both setuptools and hatch.

Caution

Docker images and the bootable build cannot decode HEIF/HEIC or H.265/HEVC for legal reasons (docs/bad-codecs.md) — iPhone media thumbnails will fail there. Use a native install with pyvips for those.


11. Code Quality and Conventions

Aspect Detail
Scale ~92 classes, ~825 functions across the copyparty/ package; the largest module is httpcli.py (HttpCli with ~80 methods).
Formatting black (pinned 21.12b0, targeting py27), isort (black profile).
Linting ruff (line-length 120), pylint (py3.11), bandit (skips B104/B110/B112).
Types mypy --strict over copyparty/.
Python floor py2.7 / py3.3 still targeted — hence the deliberately conservative idioms (no f-strings in core, broad compatibility shims).
No build step JS and Python are editable in place; this is a stated design constraint.

The codebase makes heavy use of small dedicated classes per concern (e.g. Garda for ban tracking, Cooldown, FHC file-handle cache, MTHash multithreaded hashing, Pebkac/WrongPostKey exception types) in util.py. Per-protocol servers subclass their library's handler (FtpHandler(FTPHandler), SFTP_Srv(paramiko.SFTPServerInterface), etc.), keeping copyparty's VFS logic centralized in AuthSrv/VFS.

Feature kill-switches (chickenbits / beefybits)

A distinctive pattern: per-feature environment variables disable a feature when it misbehaves (chickenbits) or force-enable it on broken platforms (beefybits). Examples:

Env var Effect
PRTY_NO_SQLITE Disable all DB features (indexing, dedup logic)
PRTY_NO_MP Disable multiprocessing
PRTY_NO_TLS Disable native HTTPS (terminate TLS at a proxy)
PRTY_NO_FFMPEG / PRTY_NO_FFPROBE Disable transcoding / tag-scan via FFmpeg
PRTY_NO_PIL / PRTY_NO_VIPS Disable a thumbnail engine (saves RAM/startup)
PRTY_FORCE_MP Force multiprocessing on macOS and other broken platforms
PRTY_NO_* (dependency chickenbits) One per optional dep — argon2, paramiko, partftpy, dcraw, magic, mutagen, psutil, pyftpd, rawpy, and Pillow sub-features (HEIF/AVIF/JXL/WEBP)

Run with PRTY_MODSPEC=1 to trace which module copyparty loads each dependency from.


12. Troubleshooting (Operator)

Error: OperationalError('database is locked')

Cause: The up2k.db is on a network disk (SMB/NFS) or a filesystem with broken locking (VirtualBox vboxsf, mergerfs), or the share dropped briefly. Solution: Move the DB to a local disk with --hist / hist volflag, or just the DB with --dbpath. Visit /?stack to capture live thread stacks for a bug report. Prevention: Keep .hist/ on a reliable local SSD; set a landmark volflag to gate DB access on network volumes.

Error: Everyone keeps getting thank you for playing

Cause: copyparty bans the IP it thinks is the client; behind a proxy that's often the proxy's IP, so one bad actor bans everyone. Solution: Configure real-IP (--xff-hdr, --xff-src, --rproxy); see §5.4 and docs/xff.md.

Error: copyparty sees HTTP though clients use HTTPS

Cause: The proxy isn't forwarding X-Forwarded-Proto: https (or an intermediate like Cloudflare terminates HTTPS early). Solution: Ensure the proxy chain forwards the header end to end.

Error: SMB clients see only ~400 files in large folders

Cause: An impacket limitation (impacket#1433), worked around by default. Solution: With impacket ≥0.12, disable the workaround with --smb-nwa-1 (but expect a performance hit).

Error: Thumbnails fail after sandboxing with prisonparty/bubbleparty + mimalloc

Cause: mimalloc needs /proc and /sys, which the sandbox hides. Solution: Grant the sandbox access to /proc and /sys.

Issue: Custom FFmpeg binary names (e.g. macports ffmpeg8)

Cause: copyparty looks for ffmpeg/ffprobe in $PATH. Solution: Set PRTY_FFMPEG_BIN and PRTY_FFPROBE_BIN to the correct name or full path.

Recovering from a Firefox WSOD during upload

Firefox 87 can crash the whole browser mid-upload. In the up2k tab's devtools (F12) you can recover the upload state:

var tabs = { ok:[], ng:[], bz:[], q:[] }; for (var a of up2k.ui.tab) tabs[a.in].push(a); tabs

13. Potential Improvements

These are observations for operators and contributors, drawn from the project's own notes and code shape:

  • Multiprocessing metric accuracy — connection/request/ban counters are per-process under -j, so aggregate dashboards under-report. A shared counter via the broker would fix this.
  • SMB backend maturity — the maintainer explicitly states low confidence that read-only is truly read-only and warns of possible path-traversal; it isn't fully integrated with the VFS. Treat SMB as LAN-only and sandbox it. A VFS-integrated SMB layer would close this gap.
  • HTTP/2 and QUIC — copyparty speaks neither; it relies on a reverse proxy for them, and notes HTTP/1.1 is often faster anyway. Native HTTP/2 could simplify single-binary deployments.
  • Bidirectional sync — intentionally unsupported; the documented path is to pair with Syncthing. Operators needing two-way sync must run a second tool.
  • httpcli.py size — HttpCli is a single ~80-method class handling the entire request surface. It is load-bearing and well-tested but a natural target for decomposition if contributing.

See docs/TODO.md in the repo for the maintainer's planned features and fixes, and docs/devnotes.md for build instructions (sfx repack, build-from-scratch).


14. Quick Reference

Default ports

Port Protocol
3923/tcp HTTP + HTTPS + WebDAV
3921/tcp FTP
3990/tcp FTPS
3922/tcp SFTP
3945/tcp SMB (NAT from 445)
3969/udp TFTP (NAT from 69)
5353/udp mDNS
1900/udp SSDP
12000-13000/tcp FTP passive range (--ftp-pr)

Essential commands

# minimal share of current folder
python copyparty-sfx.py

# indexed music server, read-only, with one read-write user
python copyparty-sfx.py -v /mnt/nas/music:/music:r -e2dsa -e2ts \
  -a kevin:okgo -v /mnt/nas/inc:/inc:rw,kevin --no-robots --theme 2

# run from a config file
python copyparty-sfx.py -c /etc/copyparty/copyparty.conf

# reload config without restart
systemctl reload copyparty      # or: kill -s USR1 <pid>

# see all options / volflags / accounts syntax
copyparty --help
copyparty --help-flags
copyparty --help-accounts

Key environment variables

Variable Purpose
PRTY_CONFIG Path to config file (alternative to -c)
XDG_CONFIG_HOME / APPDATA Where copyparty looks for default config
NOTIFY_SOCKET / S6_NOTIFY_FD Service readiness notification
PRTY_NO_* Feature/dependency chickenbits
PRTY_FORCE_MP / PRTY_FORCE_MAGIC Beefybits (force-enable)
PRTY_SYS_* Use system instead of vendored libraries
PRTY_FFMPEG_BIN / PRTY_FFPROBE_BIN Custom FFmpeg/FFprobe paths
PRTY_MODSPEC Debug: trace module loading

Reporting bugs

Primary: github.com/9001/copyparty (mirrors on GitLab and Codeberg). Include command-line arguments, config, and — for freezes — the thread stacks from /?stack or journalctl.