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.
48 lines
2.1 KiB
INI
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
|