asterisk-standalone-backup.sh: fix external IP on cross-box restore
User confirmed via a live pjsip.conf on their actual DO box: both external_media_address and external_signaling_address are literal IPs, written by easy-asterisk at first container start (not something this repo's install script controls directly). A straight restore of a backup archive from a DIFFERENT box onto the new IONOS box would leave the OLD DigitalOcean IP baked into pjsip.conf — dialplan and PJSIP device credentials would come back fine, but RTP media (and likely SIP signaling/registration) would stay broken, silently, since nothing in the restore path previously touched these values. Fix: after extracting the archive, `restore` reads the archive's own external_signaling_address as "old IP", detects this host's actual current public IP (same DO-metadata -> ifconfig.me -> hostname -I fallback chain services/asterisk.sh's own install already uses), and if they differ, rewrites every occurrence across config/ and .env (fixed-string match, not a regex, so the IP's dots can't be misinterpreted). Deliberately does NOT touch spool/, logs/, or lib/ — those hold voicemail messages and call recordings, and a blind text substitution across binary audio would corrupt it. A restore onto the same host (e.g. rolling back a bad config change, no IP change) leaves every file untouched — the check only fires on an actual mismatch. Verified against the real generated script (extracted verbatim from the heredoc, not a reimplementation) with a full mock backup/restore cycle: built a fixture archive with pjsip.conf's three transport blocks (udp/tcp/tls) and .env's TURN_SERVER all hardcoded to a fake "old box" IP, plus a fake binary voicemail file; restored it onto a mocked "new box" with a different detected IP via a stubbed curl. Confirmed every occurrence in both pjsip.conf and .env was correctly rewritten to the new IP, and confirmed via byte-for-byte comparison that the binary voicemail file was completely untouched. Separately verified the same-IP case (mocked curl returning the archive's own IP) makes no changes at all, matching a same-host config rollback. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn
This commit is contained in:
@@ -591,6 +591,37 @@ case "$cmd" in
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# pjsip.conf bakes external_media_address/external_signaling_address
|
||||
# in as literal IPs (easy-asterisk writes them at first container
|
||||
# start, not this repo) — restoring an archive from a DIFFERENT box
|
||||
# verbatim leaves the OLD box's IP in place, breaking RTP media (and
|
||||
# likely SIP signaling) on THIS box even though the dialplan itself
|
||||
# comes back fine. Detect the mismatch and patch it automatically —
|
||||
# this is the whole reason "restore" onto a new host exists, so a
|
||||
# stale IP left behind would defeat the point every single time.
|
||||
PJSIP_CONF="$HERE/config/asterisk/pjsip.conf"
|
||||
if [ -f "$PJSIP_CONF" ]; then
|
||||
OLD_EXT_IP="$(grep -m1 '^external_signaling_address=' "$PJSIP_CONF" | cut -d= -f2)"
|
||||
NEW_EXT_IP="$(curl -fsS --max-time 2 http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address 2>/dev/null || true)"
|
||||
[ -z "$NEW_EXT_IP" ] && NEW_EXT_IP="$(curl -fsS --max-time 3 https://ifconfig.me 2>/dev/null || true)"
|
||||
[ -z "$NEW_EXT_IP" ] && NEW_EXT_IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
|
||||
if [ -n "$OLD_EXT_IP" ] && [ -n "$NEW_EXT_IP" ] && [ "$OLD_EXT_IP" != "$NEW_EXT_IP" ]; then
|
||||
echo "This archive's SIP config was for a different box's public IP"
|
||||
echo "($OLD_EXT_IP) — this box's is $NEW_EXT_IP. Updating"
|
||||
echo "external_media_address/external_signaling_address so RTP/SIP work here."
|
||||
# Fixed-string match/replace, restricted to config + .env —
|
||||
# never spool/logs/lib, which hold voicemail/recording audio
|
||||
# that a text substitution would corrupt.
|
||||
ESC_OLD_IP="${OLD_EXT_IP//./\\.}"
|
||||
grep -rlF "$OLD_EXT_IP" "$HERE/config" "$HERE/.env" 2>/dev/null | while read -r _f; do
|
||||
sed -i "s/$ESC_OLD_IP/$NEW_EXT_IP/g" "$_f"
|
||||
done
|
||||
echo "Updated. If this PBX uses VLANs/extra subnets, re-check them:"
|
||||
echo " docker exec -it $CONTAINER easy-asterisk # Server Settings -> Configure VLAN/VPN Subnets"
|
||||
fi
|
||||
fi
|
||||
|
||||
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$HERE"
|
||||
|
||||
if [ "$WAS_RUNNING" = true ]; then
|
||||
@@ -1705,6 +1736,19 @@ To migrate to a new host: run \`backup\` on the old one, copy the archive
|
||||
over, then run \`restore\` after a fresh \`sudo ./setup.sh asterisk\` install
|
||||
(or directly into an empty \`${EA_DIR}\`) on the new host.
|
||||
|
||||
\`restore\` also detects and fixes the one thing that doesn't travel between
|
||||
boxes on its own: \`pjsip.conf\`'s \`external_media_address\`/
|
||||
\`external_signaling_address\` are literal IPs, baked in by easy-asterisk at
|
||||
first container start — restoring an archive from a different box verbatim
|
||||
would otherwise leave the OLD box's IP in place, breaking RTP media (and
|
||||
likely SIP registration) even though the dialplan itself comes back fine.
|
||||
\`restore\` compares the archive's IP against this host's own (same
|
||||
DO-metadata → ifconfig.me → \`hostname -I\` detection this script's own
|
||||
install uses) and, if they differ, rewrites every occurrence across
|
||||
\`config/\` and \`.env\` — never \`spool/\`/\`logs/\`/\`lib/\`, which hold voicemail
|
||||
and recording audio a text substitution would corrupt. A same-host restore
|
||||
(rolling back a config mistake, no IP change) leaves everything untouched.
|
||||
|
||||
## VLANs / other subnets
|
||||
|
||||
\`.env\` → \`HAS_VLANS\`/\`VLAN_SUBNETS\` lists extra networks (space-separated
|
||||
|
||||
Reference in New Issue
Block a user