Files
petfeed/docker/run-cron.sh
T
adminandClaude Sonnet 5 6cc697a696 chore(docker): add missing run-cron.sh NAS cron runner
Both existing crontab entries (trim-feeds, anniversaries) and backup-db.sh
referenced a run-cron.sh that was never actually created/committed - cron
has been executing it daily (04:00/08:00) with exit 127 since at least
today, silently, because no local mail delivery is configured for the
cron user's failure notifications.

Recreates it per README's documented curl pattern (bearer token via
CRON_SECRET, --resolve for the origin TLS cert quirk) and adds logging
to docker/cron.log so future failures are visible without relying on
cron's mail notification.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 19:27:00 +02:00

60 lines
1.7 KiB
Bash

#!/bin/sh
# Triggers a PawFeed cron route from the NAS crontab.
#
# Usage: run-cron.sh /api/cron/<name>
#
# Reads CRON_SECRET from docker/.env (sibling to this script) and hits the app
# via the DDNS hostname with --resolve to localhost, because the origin TLS
# cert (Nginx Proxy Manager) is only valid for pawfeed.neodk.ipv64.de — a plain
# curl against pawfeed.org fails with an SSL hostname mismatch from the NAS
# itself (Cloudflare only terminates TLS for pawfeed.org at the edge, browsers
# only). See README.md "Common Pitfalls".
#
# Every run is logged to docker/cron.log (with HTTP status + response body) so
# failures are visible even though this NAS has no local mail delivery set up
# for the cron user — a missing/renamed script or a non-2xx response would
# otherwise fail silently.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ENV_FILE="$SCRIPT_DIR/.env"
LOG_FILE="$SCRIPT_DIR/cron.log"
HOST="pawfeed.neodk.ipv64.de"
log() {
printf '%s [run-cron] %s\n' "$(date -Iseconds)" "$1" >> "$LOG_FILE"
}
ROUTE="${1:?usage: run-cron.sh /api/cron/<name>}"
if [ ! -f "$ENV_FILE" ]; then
log "ERROR: $ENV_FILE not found"
exit 1
fi
CRON_SECRET="$(grep -E '^CRON_SECRET=' "$ENV_FILE" | head -n1 | cut -d= -f2-)"
if [ -z "$CRON_SECRET" ]; then
log "ERROR: CRON_SECRET not set in $ENV_FILE"
exit 1
fi
RESPONSE_FILE="$(mktemp)"
trap 'rm -f "$RESPONSE_FILE"' EXIT
STATUS=$(curl -s -o "$RESPONSE_FILE" -w '%{http_code}' \
--resolve "$HOST:443:127.0.0.1" \
--max-time 60 \
-H "Authorization: Bearer $CRON_SECRET" \
"https://$HOST$ROUTE") || STATUS=000
BODY="$(cat "$RESPONSE_FILE" 2>/dev/null || true)"
log "$ROUTE -> HTTP $STATUS: $BODY"
case "$STATUS" in
2??) exit 0 ;;
*)
log "ERROR: $ROUTE returned HTTP $STATUS"
exit 1
;;
esac