testsAndMisc/linux_configuration/features/lib/syncyomi_expose.sh
Krzysztof kuhy Rudnicki 4f2b0ccdf7 Dissolve linux_configuration/scripts/ and single_use/
Two levels of pure taxonomy carrying no information, and a 2-directory
cap leaves no room for them. Categories now sit directly under
linux_configuration/: features, fixes, utils, misc, fresh-install,
installers, diagnostics, gaming, boot_recovery, periodic_background, lib,
meta, tests. A script's own lib/ and tests/ are exempt from the cap, so
those stay put.

Depth violations 248 -> 139; roughly 40 of the remainder are inside
digital_wellbeing and hosts, deferred until the guard-lib repoint.

The moves are the easy half. What breaks is every path that counted
levels, and three classes of it had to be found by resolving paths rather
than reading diffs:

  - 52 relative `source` lines for lib/common.sh and lib/android.sh. The
    correct prefix differs per file: 40 were ../../ and 12 were ../../../,
    so a blanket replace would have fixed one set and broken the other.
  - REPO_ROOT in 7 fixes/lib/tests harnesses and setup_syncyomi_guard.sh,
    each walking up four levels from a directory now two levels shallower.
    This caused a real regression -- the fixes suite went red with
    "log_warn: command not found" -- caught by running it and comparing
    against the pre-move baseline worktree.
  - conftest.py's sys.path entries, which took the pytest gate down with
    14 collection errors, and the `# shellcheck source=` directives, which
    took shellcheck down with SC1091.

16 symlinks in $HOME broke, including the entire i3blocks bar. All
repointed, and cpu_monitor/memory/disk/time/volume were run to confirm
they emit real output rather than merely resolving.

Verified: 1798 tests pass at 100% coverage, 8 of 9 lib/tests suites pass
(the ninth needs the coverage jail, identically at baseline), pre-commit
is clean, and the two untracked secret configs are still ignored after
their gitignore paths changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
2026-08-23 18:53:30 +02:00

144 lines
4.9 KiB
Bash
Executable File

#!/bin/bash
# Caddy vhost, DuckDNS record and firewall rules for exposing SyncYomi.
#
# Sourced by setup_syncyomi.sh; split out to keep syncyomi_stack.sh under
# the 250-line cap. Sourced rather than run, so it inherits the caller's
# strict mode and the variables defined above the source line.
# --- Step 6: Caddy reverse-proxy block (append + reload) ---------------------
configure_caddy() {
if grep -qE "^${SYNCYOMI_SUBDOMAIN} \{" "${CADDYFILE}"; then
log_ok "Caddyfile already has a block for ${SYNCYOMI_SUBDOMAIN}"
else
log_info "Adding Caddy block for ${SYNCYOMI_SUBDOMAIN}"
# NOTE: appended to the shared Gitea Caddyfile. Re-running setup_gitea.sh
# regenerates that file and drops this block — re-run setup_syncyomi.sh
# to restore it. Caddyfile uses tab indentation.
printf '\n%s {\n\treverse_proxy 127.0.0.1:%s\n}\n' "${SYNCYOMI_SUBDOMAIN}" "${SYNCYOMI_PORT}" \
>>"${CADDYFILE}"
fi
docker exec "${CADDY_CONTAINER}" caddy reload --config "${CADDYFILE_IN_CONTAINER}" ||
die "caddy reload failed — check 'docker logs ${CADDY_CONTAINER}'."
log_ok "Caddy reloaded (auto-HTTPS will be issued once the subdomain resolves)"
}
# --- Step 7: DuckDNS subdomain (extend existing updater; no new cron) --------
configure_duckdns() {
local label="${SYNCYOMI_SUBDOMAIN%.duckdns.org}"
if grep -qE "domains=[^&\"']*${label}([,&\"']|$)" "${DUCKDNS_UPDATER}"; then
log_ok "DuckDNS updater already includes '${label}'"
else
log_info "Adding '${label}' to the existing DuckDNS updater"
sed -i -E "s|(domains=)([^&\"']*)|\1\2,${label}|" "${DUCKDNS_UPDATER}"
fi
# Refresh now (harmless if the subdomain isn't registered yet).
bash "${DUCKDNS_UPDATER}" >/dev/null 2>&1 || log_warn "DuckDNS update returned non-zero (register the subdomain first)."
if getent hosts "${SYNCYOMI_SUBDOMAIN}" >/dev/null 2>&1; then
log_ok "${SYNCYOMI_SUBDOMAIN} resolves"
else
log_warn "${SYNCYOMI_SUBDOMAIN} does not resolve yet — create the '${label}' subdomain in the DuckDNS dashboard."
fi
}
# --- Step 8: firewall (open 80/443 via the owning script, idempotent) -------
ensure_firewall() {
if sudo nft list ruleset 2>/dev/null | grep -qE 'dport \{[^}]*80[^}]*443'; then
log_ok "Firewall already allows tcp/80 + tcp/443"
elif [[ -f ${WG_SCRIPT} ]]; then
log_info "Opening 80/443 via setup_wireguard_ssh.sh allow-web"
sudo bash "${WG_SCRIPT}" allow-web
else
log_warn "setup_wireguard_ssh.sh not found — ensure tcp/80+443 are open."
fi
}
# --- Step 9: report ----------------------------------------------------------
print_report() {
local url="https://${SYNCYOMI_SUBDOMAIN}"
local key="(create one in the web UI)"
[[ -f ${TOKEN_FILE} ]] && key="$(<"${TOKEN_FILE}")"
cat <<EOF
============================================================================
SyncYomi is up.
Host address : ${url}
API key : ${key}
Web UI login : ${SYNCYOMI_USER} / (password in ${CONF_FILE})
TachiyomiSY setup (on the phone):
Settings → Data & storage → Sync → SyncYomi
Host : ${url}
API key : ${key}
Use the SAME API key on every device you want to sync.
If the subdomain is new, create it once in the DuckDNS dashboard
(label: ${SYNCYOMI_SUBDOMAIN%.duckdns.org}) so Caddy can issue TLS.
Acceptance test: on your phone with Wi-Fi OFF (cellular), configure the
sync above and confirm the library round-trips.
============================================================================
EOF
}
# --- status subcommand -------------------------------------------------------
status_cmd() {
print_setup_header "SyncYomi status"
echo
if [[ -f ${COMPOSE_FILE} ]]; then
docker compose -f "${COMPOSE_FILE}" ps
else
log_warn "No compose file at ${COMPOSE_FILE}"
fi
echo
local code
code="$(syncyomi_ready "${SYNCYOMI_LOCAL}" || true)"
if [[ ${code} == "204" || ${code} == "403" ]]; then
log_ok "Local API answering (${SYNCYOMI_LOCAL}, HTTP ${code})"
else
log_warn "Local API not answering (HTTP ${code:-none})"
fi
local sub="${SYNCYOMI_SUBDOMAIN:-kuhy-sync.duckdns.org}"
if [[ -f ${CONF_FILE} ]]; then
# shellcheck source=/dev/null
source "${CONF_FILE}"
sub="${SYNCYOMI_SUBDOMAIN}"
fi
if grep -qE "^${sub} \{" "${CADDYFILE}" 2>/dev/null; then
log_ok "Caddy block present for ${sub}"
else
log_warn "No Caddy block for ${sub}"
fi
if getent hosts "${sub}" >/dev/null 2>&1; then
log_ok "${sub} resolves"
else
log_warn "${sub} does not resolve"
fi
code="$(syncyomi_ready "https://${sub}" || true)"
if [[ ${code} == "204" || ${code} == "403" ]]; then
log_ok "External HTTPS reachable (https://${sub}, HTTP ${code})"
else
log_warn "External HTTPS not reachable yet (HTTP ${code:-none})"
fi
}
# --- main --------------------------------------------------------------------
setup_cmd() {
print_setup_header "Self-hosted SyncYomi manga sync"
preflight
load_config
write_compose
start_containers
wait_for_syncyomi
ensure_local_config
mint_api_key
configure_caddy
configure_duckdns
ensure_firewall
print_report
}