share: dockerize the file-share pipeline and document it

The Python half of the short-lived share links lived in the repo; the Apache
config and the cron entries that make it work were hand-placed on the host, so
the feature could not be rebuilt from a checkout. This adds the missing half.

Scripts (defaults unchanged, so existing bare-metal cron keeps working):
* scan_shares.py / revoke_shares.py take their paths from CONJURER_SHARE_*
  instead of hardcoding the Pi layout, and create their parent dirs;
* the revoke TTL is now CONJURER_SHARE_TTL_SECONDS. Its --help claimed "2min"
  while the code used a hardcoded 3600 - the help text now reports the real,
  configured value.

New share service:
* docker/Dockerfile.share - Apache + the two jobs, reusing the same scripts
  rather than forking copies;
* docker/share-vhost.conf.tpl - the previously undocumented Apache half.
  Three settings are load-bearing and commented as such: +FollowSymLinks (the
  shares ARE symlinks), -Indexes (a listing would expose every live token), and
  a deny rule for dotfiles (revoke_shares.py keeps .downloads.json - a map of
  every live token - inside the served directory);
* docker/entrypoint.share.sh - renders the vhost, seeds the index on first run,
  then runs scanner/revoker in sleep loops beside Apache (no cron, so their
  output shows up in docker logs);
* compose + env example, incl. the two volumes that MUST be shared with the
  musician (it creates the links and reads the index).

docs/deployment/FILE_SHARING.md documents the mechanism, both deployment routes
(docker and existing host Apache), the Discord command, why each Apache setting
matters, verification commands, and the known limitations - notably that a link
nobody ever downloads is never revoked, since the TTL starts at first download.

Verified: scanner and revoker exercised end-to-end against temp dirs (index
built; token recorded from a combined-format log line and the symlink unlinked).
Compose file not validated - no docker on this machine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Michal Tuszowski
2026-07-19 22:16:49 +02:00
parent dc449dd74c
commit 33ec1c0e35
9 changed files with 437 additions and 10 deletions
+36
View File
@@ -0,0 +1,36 @@
# Conjurer share service: Apache publishing short-lived symlink shares, plus
# the two periodic jobs that build the search index and revoke expired links.
#
# This is the piece that used to live only as hand-placed scripts + hand-edited
# Apache config on the host. Everything it needs is now in the image; the state
# it shares with the musician (the link dir and the index) comes in as volumes.
#
# Build from the repository root:
# docker build -f docker/Dockerfile.share -t conjurer-share .
FROM debian:bookworm-slim
# apache2 serves the links; python3 runs the scanner/revoker (both stdlib-only,
# so there is nothing to pip install).
RUN apt-get update && apt-get install -y --no-install-recommends \
apache2 python3 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Same scripts the bare-metal deployment uses - no forked copies.
COPY conjurer_musician/scan_shares.py ./scan_shares.py
COPY conjurer_musician/revoke_shares.py ./revoke_shares.py
COPY docker/share-vhost.conf.tpl ./share-vhost.conf.tpl
COPY docker/entrypoint.share.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# /mnt/shares - media library (mount read-only; symlink targets)
# /var/www/html/share - the symlinks themselves (SHARED with the musician,
# which is what creates them)
# /srv/share/db - share_scan.json (SHARED with the musician, which
# searches it)
# /var/log/apache2 - access log the revoker tails
VOLUME ["/mnt/shares", "/var/www/html/share", "/srv/share/db", "/var/log/apache2"]
EXPOSE 80
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]