summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xarch-lastsync.sh27
-rwxr-xr-xarchmirror-iso.sh11
-rwxr-xr-xarchmirror-repos.sh24
-rwxr-xr-xarchmirror-sync.sh50
-rwxr-xr-xftpsync-mirror.sh10
-rwxr-xr-xgentoo-lastsync.sh27
-rwxr-xr-xgentoomirror-sync.sh50
-rwxr-xr-xhbsd-lastsync.sh27
-rwxr-xr-xhbsdmirror-sync.sh50
-rwxr-xr-xmirror-backup.sh46
-rwxr-xr-xmirror-sync.sh43
-rwxr-xr-xmirror-verify.sh94
-rwxr-xr-xmirror-watch.sh7
-rwxr-xr-xsha256.sh29
-rwxr-xr-xvoid-key-bootstrap.sh40
15 files changed, 535 insertions, 0 deletions
diff --git a/arch-lastsync.sh b/arch-lastsync.sh
new file mode 100755
index 0000000..a2c0106
--- /dev/null
+++ b/arch-lastsync.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Upstream (Arch Geo CDN points to a Tier-1 close to you)
+UPSTREAM="https://geo.mirror.pkgbuild.com/lastsync"
+
+# Your mirror (the VIP that Arch probes)
+MIRROR="https://stygian.failzero.net/mirror/archlinux/lastsync"
+
+# Log file
+LOGFILE="/var/log/mirrors/delay.log"
+mkdir -p "$(dirname "$LOGFILE")"
+
+# Fetch timestamps (seconds since epoch)
+u=$(curl -fsS "$UPSTREAM" || echo 0)
+m=$(curl -fsS "$MIRROR" || echo 0)
+
+if [[ "$u" =~ ^[0-9]+$ && "$m" =~ ^[0-9]+$ ]]; then
+ delay_min=$(( (u - m) / 60 ))
+ echo "$(date -Is) upstream=$u mirror=$m delay=${delay_min}m" >> "$LOGFILE"
+else
+ echo "$(date -Is) error fetching lastsync" >> "$LOGFILE"
+
+curl -fsS https://geo.mirror.pkgbuild.com/lastsync > "$LIVE/lastsync" \
+ || date -u +%s > "$LIVE/lastsync"
+
+fi
diff --git a/archmirror-iso.sh b/archmirror-iso.sh
new file mode 100755
index 0000000..bd0c3e5
--- /dev/null
+++ b/archmirror-iso.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+# /usr/local/sbin/archmirror-iso.sh
+set -euo pipefail
+UPSTREAM="rsync://mirror.csclub.uwaterloo.ca/archlinux/iso/"
+DST="/brimstone3/mirror-stage/arch-repos/iso"
+LOG="/var/log/mirrors/arch-iso.log"
+
+mkdir -p "$DST"
+
+rsync -rtlH --safe-links --delete-delay --delay-updates \
+ "$UPSTREAM" "$DST" | tee -a "$LOG"
diff --git a/archmirror-repos.sh b/archmirror-repos.sh
new file mode 100755
index 0000000..f15504a
--- /dev/null
+++ b/archmirror-repos.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# /usr/local/sbin/archmirror-repos.sh
+set -euo pipefail
+UPSTREAM="rsync://mirror.csclub.uwaterloo.ca/archlinux/"
+STAGE="/brimstone3/mirror-stage/arch-repos"
+LIVE="/brimstone1/mirror/archlinux"
+LOG="/var/log/mirrors/arch-repos.log"
+
+mkdir -p "$STAGE" "$LIVE"
+
+rsync -rtlH --safe-links --delete-delay --delay-updates \
+ --exclude iso/ --exclude other/ \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOG"
+
+rsync -rtlH --safe-links --delete-delay --delay-updates \
+ --exclude iso/ --exclude other/ \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOG"
+
+curl -fsS https://geo.mirror.pkgbuild.com/lastsync > "$LIVE/lastsync" \
+ || date -u +%s > "$LIVE/lastsync"
+
+ln -sfn "$STAGE" "$LIVE"
+date -u +%s > "$LIVE/lastsync"
+
diff --git a/archmirror-sync.sh b/archmirror-sync.sh
new file mode 100755
index 0000000..35b02da
--- /dev/null
+++ b/archmirror-sync.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# ====== CONFIG ======
+# Pick a nearby Tier-1. Examples (use ONE):
+# rsync://mirror.csclub.uwaterloo.ca/archlinux/
+# rsync://mirror.constant.com/archlinux/
+UPSTREAM="${UPSTREAM:-rsync://mirror.csclub.uwaterloo.ca/archlinux/}"
+
+# Local paths
+LIVE="${LIVE:-/brimstone1/mirror/archlinux}" # served path (symlink target)
+STAGE="${STAGE:-/brimstone3/mirror-stage/archlinux}" # staging path
+LOGDIR="${LOGDIR:-/var/log/mirrors}"
+LOCK="${LOCK:-/var/log/archmirror.lock}"
+
+# rsync knobs
+RSYNC_OPTS=(
+ -rtlH --safe-links
+ --delete-delay --delay-updates
+ --partial --partial-dir=.rsync-partial
+ --timeout=600 --contimeout=60
+)
+
+# Niceness (be kind to disks)
+IONICE=(ionice -c2 -n7)
+NICE=(nice -n 15)
+
+mkdir -p "$STAGE" "$LIVE" "$LOGDIR"
+exec 9>"$LOCK"
+flock -n 9 || { echo "[$(date -Is)] another archmirror-sync is running, exiting"; exit 0; }
+
+log() { echo "[$(date -Is)] $*"; }
+log "starting sync from $UPSTREAM"
+
+# First pass
+"${IONICE[@]}" "${NICE[@]}" rsync "${RSYNC_OPTS[@]}" \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOGDIR/arch-sync.log"
+
+# Quick second pass to catch files updated mid-run
+"${IONICE[@]}" "${NICE[@]}" rsync "${RSYNC_OPTS[@]}" \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOGDIR/arch-sync.log"
+
+# Atomic flip: make LIVE point at STAGE (symlink strategy)
+# If LIVE is a directory you want to replace, serve via a symlink path like /srv/mirror/arch -> /srv/mirror-stage/arch
+ln -sfn "$STAGE" "$LIVE"
+
+# Optional: write a local "lastsync" like Arch does, helps some clients
+date -u +%s > "$LIVE/lastsync"
+
+log "sync complete; flipped LIVE -> $STAGE"
diff --git a/ftpsync-mirror.sh b/ftpsync-mirror.sh
new file mode 100755
index 0000000..e330af5
--- /dev/null
+++ b/ftpsync-mirror.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+export HOSTNAME=stygian.failzero.net
+export ARCHIVE=debian
+export TO=/brimstone1/mirror/debian
+export RSYNC_HOST=syncproxy2.wna.debian.org
+export RSYNC_PATH=debian
+export LOGDIR=/var/log/ftpsync
+export LOCKDIR=/var/run/ftpsync
+
+/usr/bin/ftpsync sync:all
diff --git a/gentoo-lastsync.sh b/gentoo-lastsync.sh
new file mode 100755
index 0000000..e388c0e
--- /dev/null
+++ b/gentoo-lastsync.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Upstream (Arch Geo CDN points to a Tier-1 close to you)
+UPSTREAM="rsync://masterdistfiles.gentoo.org/gentoo/"
+
+# Your mirror (the VIP that Arch probes)
+MIRROR="https://stygian.failzero.net/mirror/gentoo/lastsync"
+
+# Log file
+LOGFILE="/var/log/mirrors/delay.log"
+mkdir -p "$(dirname "$LOGFILE")"
+
+# Fetch timestamps (seconds since epoch)
+u=$(curl -fsS "$UPSTREAM" || echo 0)
+m=$(curl -fsS "$MIRROR" || echo 0)
+
+if [[ "$u" =~ ^[0-9]+$ && "$m" =~ ^[0-9]+$ ]]; then
+ delay_min=$(( (u - m) / 60 ))
+ echo "$(date -Is) upstream=$u mirror=$m delay=${delay_min}m" >> "$LOGFILE"
+else
+ echo "$(date -Is) error fetching lastsync" >> "$LOGFILE"
+
+curl -fsS https://geo.mirror.pkgbuild.com/lastsync > "$LIVE/lastsync" \
+ || date -u +%s > "$LIVE/lastsync"
+
+fi
diff --git a/gentoomirror-sync.sh b/gentoomirror-sync.sh
new file mode 100755
index 0000000..0371725
--- /dev/null
+++ b/gentoomirror-sync.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# ====== CONFIG ======
+# Pick a nearby Tier-1. Examples (use ONE):
+# rsync://mirror.csclub.uwaterloo.ca/archlinux/
+# rsync://mirror.constant.com/archlinux/
+UPSTREAM="${UPSTREAM:-rsync://masterdistfiles.gentoo.org/gentoo/}"
+
+# Local paths
+LIVE="${LIVE:-/brimstone2/mirror/gentoo}" # served path (symlink target)
+STAGE="${STAGE:-/brimstone3/mirror-stage/gentoo}" # staging path
+LOGDIR="${LOGDIR:-/var/log/mirrors}"
+LOCK="${LOCK:-/var/log/archmirror.lock}"
+
+# rsync knobs
+RSYNC_OPTS=(
+ -rtlH --safe-links
+ --delete-delay --delay-updates
+ --partial --partial-dir=.rsync-partial
+ --timeout=600 --contimeout=60
+)
+
+# Niceness (be kind to disks)
+IONICE=(ionice -c2 -n7)
+NICE=(nice -n 15)
+
+mkdir -p "$STAGE" "$LIVE" "$LOGDIR"
+exec 9>"$LOCK"
+flock -n 9 || { echo "[$(date -Is)] another archmirror-sync is running, exiting"; exit 0; }
+
+log() { echo "[$(date -Is)] $*"; }
+log "starting sync from $UPSTREAM"
+
+# First pass
+"${IONICE[@]}" "${NICE[@]}" rsync "${RSYNC_OPTS[@]}" \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOGDIR/arch-sync.log"
+
+# Quick second pass to catch files updated mid-run
+"${IONICE[@]}" "${NICE[@]}" rsync "${RSYNC_OPTS[@]}" \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOGDIR/arch-sync.log"
+
+# Atomic flip: make LIVE point at STAGE (symlink strategy)
+# If LIVE is a directory you want to replace, serve via a symlink path like /srv/mirror/arch -> /srv/mirror-stage/arch
+ln -sfn "$STAGE" "$LIVE"
+
+# Optional: write a local "lastsync" like Arch does, helps some clients
+date -u +%s > "$LIVE/lastsync"
+
+log "sync complete; flipped LIVE -> $STAGE"
diff --git a/hbsd-lastsync.sh b/hbsd-lastsync.sh
new file mode 100755
index 0000000..b97b17f
--- /dev/null
+++ b/hbsd-lastsync.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Upstream (HBSD Geo CDN points to a Tier-1 close to you)
+UPSTREAM="rsync://rsync.hardenedbsd.org/all/"
+
+# Your mirror (the VIP that Arch probes)
+MIRROR="https://stygian.failzero.net/mirror/hardenedbsd/lastsync"
+
+# Log file
+LOGFILE="/var/log/mirrors/delay.log"
+mkdir -p "$(dirname "$LOGFILE")"
+
+# Fetch timestamps (seconds since epoch)
+u=$(curl -fsS "$UPSTREAM" || echo 0)
+m=$(curl -fsS "$MIRROR" || echo 0)
+
+if [[ "$u" =~ ^[0-9]+$ && "$m" =~ ^[0-9]+$ ]]; then
+ delay_min=$(( (u - m) / 60 ))
+ echo "$(date -Is) upstream=$u mirror=$m delay=${delay_min}m" >> "$LOGFILE"
+else
+ echo "$(date -Is) error fetching lastsync" >> "$LOGFILE"
+
+curl -fsS https://geo.mirror.pkgbuild.com/lastsync > "$LIVE/lastsync" \
+ || date -u +%s > "$LIVE/lastsync"
+
+fi
diff --git a/hbsdmirror-sync.sh b/hbsdmirror-sync.sh
new file mode 100755
index 0000000..c241883
--- /dev/null
+++ b/hbsdmirror-sync.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# ====== CONFIG ======
+# Pick a nearby Tier-1. Examples (use ONE):
+# rsync://mirror.csclub.uwaterloo.ca/archlinux/
+# rsync://mirror.constant.com/archlinux/
+UPSTREAM="${UPSTREAM:-rsync://rsync.hardenedbsd.org/all/}"
+
+# Local paths
+LIVE="${LIVE:-/brimstone2/mirror/hardenedbsd}" # served path (symlink target)
+STAGE="${STAGE:-/brimstone3/mirror-stage/hbsd}" # staging path
+LOGDIR="${LOGDIR:-/var/log/mirrors}"
+LOCK="${LOCK:-/var/log/archmirror.lock}"
+
+# rsync knobs
+RSYNC_OPTS=(
+ -rtlH --safe-links
+ --delete-delay --delay-updates
+ --partial --partial-dir=.rsync-partial
+ --timeout=600 --contimeout=60
+)
+
+# Niceness (be kind to disks)
+IONICE=(ionice -c2 -n7)
+NICE=(nice -n 15)
+
+mkdir -p "$STAGE" "$LIVE" "$LOGDIR"
+exec 9>"$LOCK"
+flock -n 9 || { echo "[$(date -Is)] another archmirror-sync is running, exiting"; exit 0; }
+
+log() { echo "[$(date -Is)] $*"; }
+log "starting sync from $UPSTREAM"
+
+# First pass
+"${IONICE[@]}" "${NICE[@]}" rsync "${RSYNC_OPTS[@]}" \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOGDIR/arch-sync.log"
+
+# Quick second pass to catch files updated mid-run
+"${IONICE[@]}" "${NICE[@]}" rsync "${RSYNC_OPTS[@]}" \
+ "$UPSTREAM" "$STAGE" | tee -a "$LOGDIR/arch-sync.log"
+
+# Atomic flip: make LIVE point at STAGE (symlink strategy)
+# If LIVE is a directory you want to replace, serve via a symlink path like /srv/mirror/arch -> /srv/mirror-stage/arch
+ln -sfn "$STAGE" "$LIVE"
+
+# Optional: write a local "lastsync" like Arch does, helps some clients
+date -u +%s > "$LIVE/lastsync"
+
+log "sync complete; flipped LIVE -> $STAGE"
diff --git a/mirror-backup.sh b/mirror-backup.sh
new file mode 100755
index 0000000..c46ed2b
--- /dev/null
+++ b/mirror-backup.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Backup critical mirror server configs + ZFS snapshots
+# Docโ€™s "configs over cargo" edition ๐Ÿ’
+
+set -euo pipefail
+umask 022
+
+BACKUP_DIR="/mnt/brimstone/mirror-config-backups"
+TIMESTAMP=$(date +%Y%m%d-%H%M%S)
+ARCHIVE="$BACKUP_DIR/mirror-configs-$TIMESTAMP.tar.gz"
+
+mkdir -p "$BACKUP_DIR"
+
+echo "[$(date)] Creating config archive: $ARCHIVE"
+
+tar -czf "$ARCHIVE" \
+ /etc/rsyncd.conf \
+ /etc/rsyncd.motd \
+ /etc/mirror-gpg \
+ /usr/local/bin/mirror-verify.sh \
+ /usr/local/bin/mirror-backup.sh \
+ /etc/systemd/system/rsyncd.service \
+ /etc/systemd/system/mirror-verify.* \
+ /etc/cron.d/*mirror* 2>/dev/null || true
+
+echo "[$(date)] Archive complete."
+
+# Rotate old archives, keep last 7
+echo "[$(date)] Rotating archives (keeping last 7)..."
+ls -1t "$BACKUP_DIR"/mirror-configs-*.tar.gz 2>/dev/null | tail -n +8 | while read -r oldfile; do
+ echo "Removing old archive: $oldfile"
+ rm -f "$oldfile"
+done
+
+#rsync to backup server
+echo "[$(date)] Sending to Stygian2 Backup Server..."
+rsync -avhr /mnt/brimstone/mirror-config-backups/*.tar.gz doc@stygian2.failzero.net:/home/doc/stygianconfig
+
+# Trigger ZFS snapshots
+echo "[$(date)] Taking ZFS snapshots..."
+zfs snapshot brimstone@mirror-backup-$TIMESTAMP || true
+zfs snapshot brimstone2@mirror-backup-$TIMESTAMP || true
+
+echo "[$(date)] Snapshots created: brimstone@mirror-backup-$TIMESTAMP, brimstone2@mirror-backup-$TIMESTAMP"
+echo "[$(date)] Backup completed successfully."
+
diff --git a/mirror-sync.sh b/mirror-sync.sh
new file mode 100755
index 0000000..88197b6
--- /dev/null
+++ b/mirror-sync.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# mirror-sync.sh
+# Sync multiple mirrors with ZFS-friendly logging and checkpoints
+
+set -o pipefail
+set +e # donโ€™t stop the whole script on a non-zero exit
+
+LOG_DIR="/var/log/mirror-sync"
+mkdir -p "$LOG_DIR"
+
+MIRROR_ROOT="/brimstone2/mirror"
+MIRROR_ROOT2="/brimstone1/mirror"
+
+# Timestamp helper
+ts() {
+ date +"[%Y-%m-%d %H:%M:%S]"
+}
+
+sync_mirror() {
+ local name="$1"
+ local url="$2"
+ local path="$3"
+ local logfile="$LOG_DIR/${name}.log"
+
+ echo "===================================================" | tee -a "$logfile"
+ echo "$(ts) Starting $name sync..." | tee -a "$logfile"
+ echo "===================================================" | tee -a "$logfile"
+
+ rsync -avhr --delete "$url" "$path" >> "$logfile" 2>&1
+ local status=$?
+
+ if [[ $status -eq 0 ]]; then
+ echo "$(ts) $name mirror sync finished successfully." | tee -a "$logfile"
+ else
+ echo "$(ts) WARNING: $name mirror sync exited with status $status." | tee -a "$logfile"
+ fi
+}
+
+# Mirrors
+sync_mirror "gentoo" "rsync://masterdistfiles.gentoo.org/gentoo/" "$MIRROR_ROOT/gentoo/"
+sync_mirror "hbsd" "rsync://rsync.hardenedbsd.org/all/" "$MIRROR_ROOT/hardenedbsd/"
+sync_mirror "slackware" "rsync://mirrors.kernel.org/slackware/" "$MIRROR_ROOT/slackware/"
+sync_mirror "void" "rsync://mirrors.servercentral.com/voidlinux/" "$MIRROR_ROOT2/void"
diff --git a/mirror-verify.sh b/mirror-verify.sh
new file mode 100755
index 0000000..e51f93a
--- /dev/null
+++ b/mirror-verify.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# Unified mirror sync + verification script
+# Docโ€™s โ€œNot my circus, not my monkeysโ€ edition ๐Ÿ’ + runtime tracking + before/after trust
+
+set -euo pipefail
+umask 022
+
+LOGBASE="/var/log/mirror-verify"
+GPGDIR="/etc/mirror-gpg"
+
+MIRRORS=(
+ # name|rsync_source|local_dir|logfile|manifest_url|sig_url|gpg_keyring
+ "archlinux|rsync://arch.mirror.constant.com/archlinux/|/brimstone2/mirror/archlinux|$LOGBASE/arch-mirror-sync.log|https://geo.mirror.pkgbuild.com/iso/latest/archlinux-x86_64.iso|https://geo.mirror.pkgbuild.com/iso/latest/archlinux-x86_64.iso.sig|$GPGDIR/archlinux.gpg"
+ "gentoo|rsync://masterdistfiles.gentoo.org/gentoo/|/brimstone2/mirror/gentoo|$LOGBASE/gentoo-mirror-sync.log|https://distfiles.gentoo.org/releases/amd64/autobuilds/current-stage3-amd64/sha256sum.txt|https://distfiles.gentoo.org/releases/amd64/autobuilds/current-stage3-amd64/sha256sum.txt.sig|$GPGDIR/gentoo.gpg"
+ "hardenedbsd|rsync://rsync.hardenedbsd.org/all/|/mnt/brimstone/mirror/hardenedbsd|$LOGBASE/hbsd-sync.log|https://hardenedbsd.org/releases/CHECKSUMS.SHA256|https://hardenedbsd.org/releases/CHECKSUMS.SHA256.sig|$GPGDIR/hbsd.gpg"
+ "void|rsync://repo-sync.voidlinux.org/voidlinux/|/mnt/brimstone/mirror/void|$LOGBASE/void-sync.log|https://repo.voidlinux.org/live/current/sha256sum.txt|https://repo.voidlinux.org/live/current/sha256sum.txt.sig|$GPGDIR/void.gpg"
+ "slackware|rsync://mirrors.kernel.org/slackware/|/mnt/brimstone/mirror/slackware|$LOGBASE/slackware-sync.log|https://mirrors.slackware.com/slackware/slackware64-current/CHECKSUMS.md5|https://mirrors.slackware.com/slackware/slackware64-current/CHECKSUMS.md5.asc|$GPGDIR/slackware.gpg"
+)
+
+for entry in "${MIRRORS[@]}"; do
+ IFS="|" read -r NAME SOURCE DEST LOG MANIFEST SIG KEYRING <<< "$entry"
+
+ {
+ echo "========== [$(date)] Starting $NAME =========="
+ START=$(date +%s)
+
+ # Banner title
+ case "$NAME" in
+ archlinux) TITLE="Arch Linux Mirror Verifier" ;;
+ gentoo) TITLE="Gentoo Mirror Verifier" ;;
+ hardenedbsd) TITLE="HardenedBSD Mirror Verifier" ;;
+ void) TITLE="Void Linux Mirror Verifier" ;;
+ slackware) TITLE="Slackware Mirror Verifier" ;;
+ *) TITLE="Mirror Verifier" ;;
+ esac
+
+ cat << EOF
+ __ __ _
+| \/ (_) ___ _ __ ___ ___ _ __ ___
+| |\/| | |/ __| '_ \` _ \ / _ \| '__/ _ \\
+| | | | | (__| | | | | | (_) | | | __/
+|_| |_|_|\___|_| |_| |_|\___/|_| \___| v1.0
+
+ ๐Ÿ’ $TITLE โ€“ Not my circus
+EOF
+
+ echo "========== BEFORE Keyring Trust (fingerprints) for $NAME =========="
+ if [ -f "$KEYRING" ]; then
+ gpg --no-default-keyring --keyring "$KEYRING" --fingerprint || true
+ else
+ echo "[$NAME] No keyring available โ€“ cannot verify signatures."
+ fi
+
+ echo "========== Syncing $NAME =========="
+ rsync -avhr --delete "$SOURCE" "$DEST"
+
+ echo "========== Dry-run verification for $NAME =========="
+ DRYRUN=$(rsync -nrv --delete "$SOURCE" "$DEST")
+ if [[ -z "$DRYRUN" ]]; then
+ echo "[$NAME] In sync: no differences found"
+ else
+ echo "[$NAME] OUT OF SYNC โ€“ differences detected!"
+ echo "$DRYRUN"
+ fi
+
+ echo "========== Signature verification for $NAME =========="
+ TMPDIR=$(mktemp -d)
+ curl -s -L -o "$TMPDIR/manifest" "$MANIFEST"
+ curl -s -L -o "$TMPDIR/sig" "$SIG"
+
+ if [ ! -s "$TMPDIR/sig" ]; then
+ echo "[$NAME] No valid signature upstream โ€“ Not my circus, not my monkeys ๐Ÿ’"
+ else
+ if gpg --no-default-keyring --keyring "$KEYRING" \
+ --verify "$TMPDIR/sig" "$TMPDIR/manifest" 2>&1; then
+ echo "[$NAME] Signature verified successfully โœ…"
+ else
+ echo "[$NAME] Signature verification FAILED โŒ (Upstream problem?)"
+ fi
+ fi
+ rm -rf "$TMPDIR"
+
+ echo "========== AFTER Keyring Trust (fingerprints) for $NAME =========="
+ if [ -f "$KEYRING" ]; then
+ gpg --no-default-keyring --keyring "$KEYRING" --fingerprint || true
+ fi
+
+ END=$(date +%s)
+ RUNTIME=$(( (END - START) / 60 ))
+ echo "[$NAME] Completed in $RUNTIME minutes"
+ echo "========== [$(date)] Done with $NAME =========="
+
+ } >> "$LOG" 2>&1
+done
diff --git a/mirror-watch.sh b/mirror-watch.sh
new file mode 100755
index 0000000..24f5e80
--- /dev/null
+++ b/mirror-watch.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+LOG=/var/log/nginx/access.log
+echo "=== Mirror Hits Report (last 24h) ==="
+goaccess $LOG --log-format=COMBINED --date-spec=hr \
+ --ignore-crawlers \
+ --no-progress \
+ -o - | awk 'NR>5 && NR<20'
diff --git a/sha256.sh b/sha256.sh
new file mode 100755
index 0000000..296c8b6
--- /dev/null
+++ b/sha256.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# /usr/local/bin/mirror-checksum.sh
+# Sync mirrors and generate SHA256 checksums
+
+# Set umask so checksums aren't world-writable
+umask 022
+
+# Define an array of mirrors: "name|rsync_source|local_dir|logfile"
+MIRRORS=(
+ "archlinux|rsync://arch.mirror.constant.com/archlinux/|/brimstone2/mirror/archlinux|/var/log/arch-mirror-sync.log"
+ "gentoo|rsync://masterdistfiles.gentoo.org/gentoo/|/brimstone2/mirror/gentoo|/var/log/gentoo-mirror-sync.log"
+ "hardenedbsd|rsync://rsync.hardenedbsd.org/all/|/mnt/brimstone/mirror/hardenedbsd|/var/log/hbsd-sync.log"
+ "void|rsync://repo-sync.voidlinux.org/voidlinux/|/mnt/brimstone/mirror/void|/var/log/void-sync.log"
+ "slackware|rsync://mirrors.kernel.org/slackware/|/mnt/brimstone/mirror/slackware|/var/log/slackware-sync.log"
+)
+
+for entry in "${MIRRORS[@]}"; do
+ IFS="|" read -r NAME SOURCE DEST LOG <<< "$entry"
+
+ echo "[$(date)] Syncing $NAME mirror..." | tee -a "$LOG"
+ rsync -avhr --delete "$SOURCE" "$DEST" >> "$LOG" 2>&1
+
+ echo "[$(date)] Generating SHA256 checksums for $NAME..." | tee -a "$LOG"
+ (cd "$DEST" && \
+ find . -type f -print0 | sort -z | \
+ xargs -0 sha256sum > "$DEST/SHA256SUMS" )
+
+ echo "[$(date)] SHA256 complete for $NAME. Results stored at $DEST/SHA256SUMS" | tee -a "$LOG"
+done
diff --git a/void-key-bootstrap.sh b/void-key-bootstrap.sh
new file mode 100755
index 0000000..e59bfaf
--- /dev/null
+++ b/void-key-bootstrap.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Bootstrap Void Linux release GPG keys correctly
+
+set -euo pipefail
+
+GPGDIR="/etc/mirror-gpg"
+KEYRING="${GPGDIR}/void.gpg"
+mkdir -p "$GPGDIR"
+TMPDIR=$(mktemp -d)
+
+echo "[void] Fetching Void release GPG keys..."
+
+# URLs from raw.githubusercontent.com from correct path
+curl -sL -o "$TMPDIR/void-releases-20191127.asc" \
+ https://raw.githubusercontent.com/void-linux/void-packages/master/common/repo-keyring/void-releases-20191127.pub
+
+curl -sL -o "$TMPDIR/void-releases-20210826.asc" \
+ https://raw.githubusercontent.com/void-linux/void-packages/master/common/repo-keyring/void-releases-20210826.pub
+
+echo "[void] Downloaded files:"
+ls -l "$TMPDIR"
+
+echo "[void] Checking file previews:"
+for f in "$TMPDIR"/*.asc; do
+ head -n5 "$f"
+ echo "--------"
+done
+
+echo "[void] Importing into keyring..."
+gpg --no-default-keyring --keyring "$KEYRING" --import "$TMPDIR"/*.asc || {
+ echo "[void] GPG import failed!"
+ exit 1
+}
+
+rm -rf "$TMPDIR"
+echo "[void] Imported Void release keys into $KEYRING"
+echo "[void] Final keyring:"
+gpg --no-default-keyring --keyring "$KEYRING" --list-keys
+
+exit 0