Merge pull request #290 from outis1one/claude/ionos-script-integration-x32ofw
Claude/ionos script integration x32ofw
This commit is contained in:
+10
-1
@@ -425,7 +425,16 @@ AUTHELIA_USERS
|
|||||||
local CADDY_FILE="$DOCKER_DIR/caddy/Caddyfile"
|
local CADDY_FILE="$DOCKER_DIR/caddy/Caddyfile"
|
||||||
if [ -f "$CADDY_FILE" ]; then
|
if [ -f "$CADDY_FILE" ]; then
|
||||||
echo " Configuring Caddy for Authelia..."
|
echo " Configuring Caddy for Authelia..."
|
||||||
if ! grep -q "(authelia)" "$CADDY_FILE"; then
|
# Anchored to an actual, uncommented snippet definition — a bare
|
||||||
|
# `grep -q "(authelia)"` also matches the commented-out example
|
||||||
|
# block caddy.sh's starter Caddyfile ships ("# (authelia) {" as
|
||||||
|
# documentation). Confirmed live: that false match made this skip
|
||||||
|
# writing the real snippet entirely, leaving any later `import
|
||||||
|
# authelia` reference elsewhere in the file dangling — Caddy then
|
||||||
|
# refuses to start at all ("File to import not found: authelia"),
|
||||||
|
# taking down every site it fronts, not just the Authelia-protected
|
||||||
|
# one.
|
||||||
|
if ! grep -qE '^\(authelia\)[[:space:]]*\{' "$CADDY_FILE"; then
|
||||||
cp "$CADDY_FILE" "$CADDY_FILE.backup.$(date +%Y%m%d-%H%M%S)"
|
cp "$CADDY_FILE" "$CADDY_FILE.backup.$(date +%Y%m%d-%H%M%S)"
|
||||||
{ cat << 'SNIPPET_EOF'
|
{ cat << 'SNIPPET_EOF'
|
||||||
# ── Authelia forward auth snippet ─────────────────────────────────────────────
|
# ── Authelia forward auth snippet ─────────────────────────────────────────────
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ install_caddy() {
|
|||||||
echo "[DRY-RUN] Would write $CADDY_DIR/docker-compose.yml (ports 80/443 + HTTP/3)"
|
echo "[DRY-RUN] Would write $CADDY_DIR/docker-compose.yml (ports 80/443 + HTTP/3)"
|
||||||
echo "[DRY-RUN] Would write a starter $CADDY_DIR/Caddyfile (if none exists)"
|
echo "[DRY-RUN] Would write a starter $CADDY_DIR/Caddyfile (if none exists)"
|
||||||
echo "[DRY-RUN] Would write $CADDY_DIR/README.md"
|
echo "[DRY-RUN] Would write $CADDY_DIR/README.md"
|
||||||
|
echo "[DRY-RUN] Would open 80/tcp, 443/tcp, 443/udp in UFW (Docker's own iptables rules let this traffic through either way, but ufw status should actually reflect it)"
|
||||||
echo "[DRY-RUN] Would optionally start Caddy (docker compose up -d)"
|
echo "[DRY-RUN] Would optionally start Caddy (docker compose up -d)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -384,6 +385,24 @@ CADDYFILE
|
|||||||
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$CADDY_DIR"
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$CADDY_DIR"
|
||||||
echo " ✓ Caddy configured at $CADDY_DIR"
|
echo " ✓ Caddy configured at $CADDY_DIR"
|
||||||
|
|
||||||
|
# Every other service in this repo opens its own UFW rule; this file
|
||||||
|
# never did — Docker manipulates iptables directly for published
|
||||||
|
# container ports (the ports: mapping above), which bypasses UFW's own
|
||||||
|
# filtering entirely for 80/tcp, 443/tcp, and 443/udp regardless of
|
||||||
|
# what `ufw status` shows. Confirmed live: sites were reachable over
|
||||||
|
# HTTPS with zero matching UFW rule for either port. That's not a
|
||||||
|
# meaningful protection gap on its own — 80/443 are supposed to be open
|
||||||
|
# to everyone, that's the whole point of a reverse proxy — but it means
|
||||||
|
# `ufw status` actively misrepresents this box's real exposure on its
|
||||||
|
# two most externally-facing ports, which is confusing and worth fixing
|
||||||
|
# even though nothing was actually unprotected as a result.
|
||||||
|
if command -v ufw &>/dev/null; then
|
||||||
|
ufw allow 80/tcp comment "Caddy HTTP" >/dev/null 2>&1
|
||||||
|
ufw allow 443/tcp comment "Caddy HTTPS" >/dev/null 2>&1
|
||||||
|
ufw allow 443/udp comment "Caddy HTTP/3" >/dev/null 2>&1
|
||||||
|
declare -F ensure_ufw_enabled >/dev/null 2>&1 && ensure_ufw_enabled
|
||||||
|
fi
|
||||||
|
|
||||||
write_readme "$CADDY_DIR" << 'CADDY_README'
|
write_readme "$CADDY_DIR" << 'CADDY_README'
|
||||||
# Caddy — reverse proxy + automatic HTTPS
|
# Caddy — reverse proxy + automatic HTTPS
|
||||||
|
|
||||||
|
|||||||
+42
-8
@@ -231,7 +231,8 @@ install_traccar() {
|
|||||||
echo " - Point Traccar at it via env vars (CONFIG_USE_ENVIRONMENT_VARIABLES) — no secrets in a config file"
|
echo " - Point Traccar at it via env vars (CONFIG_USE_ENVIRONMENT_VARIABLES) — no secrets in a config file"
|
||||||
echo " - Deploy an autoheal container that restarts Traccar if its healthcheck fails"
|
echo " - Deploy an autoheal container that restarts Traccar if its healthcheck fails"
|
||||||
echo " - Expose port 8082 (web) and 5000-5150 (device protocols; 5038/5060/5061 skipped — Asterisk keeps"
|
echo " - Expose port 8082 (web) and 5000-5150 (device protocols; 5038/5060/5061 skipped — Asterisk keeps"
|
||||||
echo " priority on those); an additional instance's device-protocol range shifts by 1000 instead"
|
echo " priority on those); shifts by 1000 instead, whether for an additional instance or because"
|
||||||
|
echo " something else already has a port in that range"
|
||||||
echo " - No default login — register the first account at the web UI, it becomes admin"
|
echo " - No default login — register the first account at the web UI, it becomes admin"
|
||||||
echo " - Offer optional ntfy push notifications (self-hosted anywhere, or ntfy.sh)"
|
echo " - Offer optional ntfy push notifications (self-hosted anywhere, or ntfy.sh)"
|
||||||
echo " - Offer a Caddy reverse proxy and to start the container"
|
echo " - Offer a Caddy reverse proxy and to start the container"
|
||||||
@@ -310,6 +311,36 @@ install_traccar() {
|
|||||||
# directory-count-based mechanism (not an ss scan) and is unaffected.
|
# directory-count-based mechanism (not an ss scan) and is unaffected.
|
||||||
find_free_port WEB_PORT "$WEB_PORT"
|
find_free_port WEB_PORT "$WEB_PORT"
|
||||||
|
|
||||||
|
# Live-check the whole device-protocol range too — the directory-count
|
||||||
|
# offset above only avoids colliding with an *earlier Traccar instance*,
|
||||||
|
# not an unrelated single-port service. Confirmed live: this range sat
|
||||||
|
# unclaimed at the OS level while this Traccar instance's own container
|
||||||
|
# had never actually started (still `docker compose up`'d for the first
|
||||||
|
# time), so a completely unrelated service's own find_free_port scan
|
||||||
|
# found 5007 "free" (nothing was listening there yet) and took it —
|
||||||
|
# invisible to any check until Traccar itself actually tried to bind
|
||||||
|
# its declared range. Shift by 1000 (reusing the same offset step the
|
||||||
|
# multi-instance path uses) until the whole range is genuinely clear.
|
||||||
|
_traccar_range_conflict() {
|
||||||
|
local min="$1" max="$2" p
|
||||||
|
for ((p = min; p <= max; p++)); do
|
||||||
|
# The base 5000-5150 range's own carve-outs for Asterisk are
|
||||||
|
# expected occupants, not a conflict — only relevant at the
|
||||||
|
# unshifted range; a shifted range never overlaps them anyway.
|
||||||
|
if [ "$min" -eq 5000 ] && { [ "$p" -eq 5038 ] || [ "$p" -eq 5060 ] || [ "$p" -eq 5061 ]; }; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
port_in_use "$p" tcp && return 0
|
||||||
|
port_in_use "$p" udp && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
while _traccar_range_conflict "$PROTO_MIN" "$PROTO_MAX"; do
|
||||||
|
log_warning "Device-protocol range $PROTO_MIN-$PROTO_MAX collides with something already running — shifting to $((PROTO_MIN + 1000))-$((PROTO_MAX + 1000))."
|
||||||
|
PROTO_MIN=$((PROTO_MIN + 1000))
|
||||||
|
PROTO_MAX=$((PROTO_MAX + 1000))
|
||||||
|
done
|
||||||
|
|
||||||
mkdir -p "$TRACCAR_DIR"
|
mkdir -p "$TRACCAR_DIR"
|
||||||
# Non-recursive on purpose — a rerun already has a `db/` full of Postgres's
|
# Non-recursive on purpose — a rerun already has a `db/` full of Postgres's
|
||||||
# own data files, owned by whatever uid the postgres container runs as
|
# own data files, owned by whatever uid the postgres container runs as
|
||||||
@@ -406,13 +437,16 @@ networks:
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# First instance keeps the exact existing Asterisk-exclusion port block
|
# Keyed on whether the range is still the unshifted default (5000), not
|
||||||
# (5000-5150 with 5038/5060/5061 carved out). An additional instance's
|
# on INSTANCE_SUFFIX — a first instance can also end up shifted now, if
|
||||||
# range is shifted by 1000 per instance (computed above), which never
|
# the live-collision check above moved it off 5000 (see that check's
|
||||||
# lands on Asterisk's fixed ports, so it just publishes the plain range
|
# comment). Only the unshifted base range needs Asterisk's ports carved
|
||||||
# with no exclusions needed.
|
# out; any shifted range (whether from a genuine additional instance or
|
||||||
|
# a first instance that got bumped for a live collision) never lands on
|
||||||
|
# Asterisk's fixed ports, so it just publishes the plain range with no
|
||||||
|
# exclusions needed.
|
||||||
local _PROTO_PORT_BLOCK
|
local _PROTO_PORT_BLOCK
|
||||||
if [ -z "$INSTANCE_SUFFIX" ]; then
|
if [ "$PROTO_MIN" -eq 5000 ]; then
|
||||||
_PROTO_PORT_BLOCK=" # 5038 (AMI), 5060 (SIP, tcp+udp), and 5061 (SIP TLS, tcp) are skipped:
|
_PROTO_PORT_BLOCK=" # 5038 (AMI), 5060 (SIP, tcp+udp), and 5061 (SIP TLS, tcp) are skipped:
|
||||||
# they're Asterisk's ports (services/asterisk.sh runs Asterisk with
|
# they're Asterisk's ports (services/asterisk.sh runs Asterisk with
|
||||||
# network_mode: host, so it binds them directly on the host, not
|
# network_mode: host, so it binds them directly on the host, not
|
||||||
@@ -584,7 +618,7 @@ Traccar instance.")
|
|||||||
stays open to anyone who reaches this server until you turn it off, so do
|
stays open to anyone who reaches this server until you turn it off, so do
|
||||||
this right away, then go to Settings → Server → Permissions and uncheck
|
this right away, then go to Settings → Server → Permissions and uncheck
|
||||||
Registration.
|
Registration.
|
||||||
- Device protocols: ports ${PROTO_MIN}-${PROTO_MAX} (TCP + UDP$( [ -z "$INSTANCE_SUFFIX" ] && echo "; 5038/tcp, 5060/tcp+udp, and 5061/tcp are skipped — reserved for Asterisk's AMI and SIP if this box also runs Asterisk from this repo, which gets priority on those ports"))
|
- Device protocols: ports ${PROTO_MIN}-${PROTO_MAX} (TCP + UDP$( [ "$PROTO_MIN" -eq 5000 ] && echo "; 5038/tcp, 5060/tcp+udp, and 5061/tcp are skipped — reserved for Asterisk's AMI and SIP if this box also runs Asterisk from this repo, which gets priority on those ports"))
|
||||||
- App data: \`data/\` and \`logs/\`
|
- App data: \`data/\` and \`logs/\`
|
||||||
- Database: PostgreSQL (\`$DB_CONTAINER\` container, data in \`db/\`)
|
- Database: PostgreSQL (\`$DB_CONTAINER\` container, data in \`db/\`)
|
||||||
- All database settings (name, user, password) live in \`.env\` — Traccar
|
- All database settings (name, user, password) live in \`.env\` — Traccar
|
||||||
|
|||||||
@@ -372,6 +372,61 @@ _vdm_remove_mount() {
|
|||||||
log_success "Removed the existing mount for '$label' (fstab backup: $(basename "$bk"))"
|
log_success "Removed the existing mount for '$label' (fstab backup: $(basename "$bk"))"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Every configured mount, for the removal menu below ─────────────────────
|
||||||
|
# Prints "label|host:share|mount_point" one per line. Unlike
|
||||||
|
# _vdm_find_existing_mount, not scoped to a particular host+share.
|
||||||
|
_vdm_list_all_mounts() {
|
||||||
|
grep -E "^${_VDM_TAG_PREFIX} " /etc/fstab 2>/dev/null \
|
||||||
|
| sed -E "s/^${_VDM_TAG_PREFIX} ([^ ]+) — ([^ ]+) -> (.*)\$/\1|\2|\3/"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Pick one or more configured mounts by number and remove them ──────────
|
||||||
|
_vdm_remove_mount_interactive() {
|
||||||
|
local entries=()
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
entries+=("$line")
|
||||||
|
done < <(_vdm_list_all_mounts)
|
||||||
|
|
||||||
|
if [ "${#entries[@]}" -eq 0 ]; then
|
||||||
|
log_info "No vpn-data-mount mounts configured — nothing to remove."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
echo ""
|
||||||
|
echo " Configured mounts:"
|
||||||
|
local i label hostshare point
|
||||||
|
for i in "${!entries[@]}"; do
|
||||||
|
IFS='|' read -r label hostshare point <<< "${entries[$i]}"
|
||||||
|
printf " %d) %-15s %-28s -> %s\n" "$((i + 1))" "$label" "$hostshare" "$point"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
local CHOICE=""
|
||||||
|
prompt_text " Remove which one? (number, or blank to stop):" "" CHOICE
|
||||||
|
[ -z "$CHOICE" ] && break
|
||||||
|
|
||||||
|
if ! [[ "$CHOICE" =~ ^[0-9]+$ ]] || [ "$CHOICE" -lt 1 ] || [ "$CHOICE" -gt "${#entries[@]}" ]; then
|
||||||
|
log_warning "'$CHOICE' isn't one of the listed mounts."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS='|' read -r label hostshare point <<< "${entries[$((CHOICE - 1))]}"
|
||||||
|
local CONFIRM=""
|
||||||
|
prompt_yn " Remove '$label' ($point)? This unmounts it, removes its credentials, and removes it from /etc/fstab (backed up first). (y/n):" "n" CONFIRM
|
||||||
|
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
|
||||||
|
_vdm_remove_mount "$label" "$point"
|
||||||
|
unset "entries[$((CHOICE - 1))]"
|
||||||
|
entries=("${entries[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "${#entries[@]}" -eq 0 ] && break
|
||||||
|
local AGAIN=""
|
||||||
|
prompt_yn " Remove another? (y/n):" "n" AGAIN
|
||||||
|
[[ "$AGAIN" =~ ^[Yy]$ ]] || break
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# ── Prompt for a password twice, hidden, matching ──────────────────────────
|
# ── Prompt for a password twice, hidden, matching ──────────────────────────
|
||||||
# Prints the password on success. No log_* calls — same reason as above;
|
# Prints the password on success. No log_* calls — same reason as above;
|
||||||
# uses plain stderr output instead so it's visible without corrupting a
|
# uses plain stderr output instead so it's visible without corrupting a
|
||||||
@@ -771,6 +826,7 @@ install_vpn-data-mount() {
|
|||||||
echo "[DRY-RUN] Would let you pick one or more by number and mount them locally over CIFS"
|
echo "[DRY-RUN] Would let you pick one or more by number and mount them locally over CIFS"
|
||||||
echo "[DRY-RUN] Would add each to /etc/fstab with a root-only credentials file (not guest)"
|
echo "[DRY-RUN] Would add each to /etc/fstab with a root-only credentials file (not guest)"
|
||||||
echo "[DRY-RUN] Would offer a gocryptfs decrypt layer per share (opt-in, requires the home box already set up via tools/gocryptfs-setup-home.sh)"
|
echo "[DRY-RUN] Would offer a gocryptfs decrypt layer per share (opt-in, requires the home box already set up via tools/gocryptfs-setup-home.sh)"
|
||||||
|
echo "[DRY-RUN] Would offer to remove any existing mount (unmount, drop its credentials + fstab entry)"
|
||||||
echo "[DRY-RUN] Repeatable — can be run again for additional home boxes"
|
echo "[DRY-RUN] Repeatable — can be run again for additional home boxes"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -786,6 +842,10 @@ install_vpn-data-mount() {
|
|||||||
|
|
||||||
_vdm_list_existing
|
_vdm_list_existing
|
||||||
|
|
||||||
|
local REMOVE=""
|
||||||
|
prompt_yn "Remove any existing VPN data mounts? (y/n):" "n" REMOVE
|
||||||
|
[[ "$REMOVE" =~ ^[Yy]$ ]] && _vdm_remove_mount_interactive
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
local ADD=""
|
local ADD=""
|
||||||
prompt_yn "Connect to a home box and mount some of its shares now? (y/n):" "y" ADD
|
prompt_yn "Connect to a home box and mount some of its shares now? (y/n):" "y" ADD
|
||||||
|
|||||||
Reference in New Issue
Block a user