Files
serverAppConfigs/dankserver/copyparty/quadlet/copyparty.container
T
dank e82c8b2d06 fix(fleet): refuse a container start until the mount it binds has answered
Dankserver rebooted with the array's mount and the media containers racing. A
rootless quadlet cannot order itself against the system's mnt-entropy.mount, so
`RequiresMountsFor=/mnt/entropy` is inert in the user manager: podman resolved
the bind against the pre-mount directory, Jellyfin and Plex came up blind, and
Jellyfin read an empty library and began `Removing item, Type: "Season"` by the
thousand. Copyparty had no guard at all.

`scripts/wait-for-mount.sh` is the gate: it waits for every named mountpoint,
then refuses by name. `ConditionPathIsMountPoint=` is NOT the fix — measured on
the host, an unmet condition logs `skipped, unmet condition check` with
NRestarts=0 and no start attempt ever follows, which is fail-dead, not
fail-closed. Jellyfin and Plex swap the condition for the gate; Copyparty gets
one; the law is recorded in AGENTS.md and the view page.

Verified on the host: the 5.7.0 quadlet generator accepts ExecStartPre in
[Service] (exit 0, all three units generated, gate present), the gate waits for
a mount that appears mid-window and proceeds, and it refuses a plain directory
after its window naming the path.

tests/media_overlay.bats pinned the old mechanism by name; its intent — both
media servers refuse to start without the view — now rides the gate.
2026-10-31 18:17:02 -07:00

48 lines
2.1 KiB
INI

# Quadlet unit: Copyparty file server (rootless, boot-persistent).
#
# Install path on dankserver: ~/.config/containers/systemd/copyparty.container
# Unit name: copyparty.service (podman 5.x drops the container- prefix)
#
# The image's default entrypoint is /bin/ash /z/cpp.sh -c /z/initcfg; the
# Command= line below reproduces the compose-era argv exactly: the admin
# account is passed as -a <user>:<password>. ${COPAY_ACCOUNT} and
# ${COPAY_PASSWORD} are expanded by systemd at ExecStart time from the
# host-local env file /home/dank/Containers/copyparty/env (mode 0600).
# This file holds no secrets. The deployer refuses to start this unit before
# that env file exists, so a missing env file fails the unit instead of
# creating an admin account with a garbage password.
#
# /w is the entropy volume, mounted read-only: nothing writes into /mnt/entropy
# anymore; every consumer of the share is a read-only client.
[Unit]
Description=Copyparty file server container
After=network.target
[Container]
ContainerName=copyparty
# Digest-pinned: upstream stopped publishing version tags after 1.19.15, so
# the pin rides :latest@digest (the tag in the reference is cosmetic; the
# digest is the pull). Pinned 2026-10-21 at the build whose label is
# 1.20.26 - closes GHSA-3c88-p299-7hvr (1.20.25) and GHSA-hg99-jqfp-rf76
# (1.20.26); the previously running build was the rolling :latest at
# 1.20.24 (issue #73 on command-center).
Image=ghcr.io/9001/copyparty-ac:latest@sha256:7f77459160a4bf34fdca79f2965dff4f0c1d7069a3d9cdfb3632acb041dd2f6a
Network=dankserver_appnet
EnvironmentFile=/home/dank/Containers/copyparty/env
Exec=-a ${COPAY_ACCOUNT}:${COPAY_PASSWORD} -v /w::r:ra,dank
Volume=/mnt/entropy:/w:ro
Volume=/home/dank/Containers/copyparty/cfg:/cfg
PublishPort=3923:3923
[Service]
# /w is the array: serving the pre-mount directory instead of the volume shows an
# empty share and nothing complains, so the mount has to answer first.
ExecStartPre=/home/dank/serverAppConfigs/scripts/wait-for-mount.sh /mnt/entropy
EnvironmentFile=/home/dank/Containers/copyparty/env
Restart=always
RestartSec=5
[Install]
WantedBy=default.target