Initial: backup/restore scripts + README for FusionPBX

- backup.sh: weekly PostgreSQL dump + FreeSWITCH/nginx/fail2ban configs
- restore.sh: 10-phase interactive restore wizard
- README.md: full rebuild guide, PBX reference, SSH relay instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 04:07:27 +00:00
commit 1d41970b8d
4 changed files with 588 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
*.log
*.tmp
__pycache__/
+164
View File
@@ -0,0 +1,164 @@
# FusionPBX Config Backup & Restore
Weekly backup of the FusionPBX/FreeSWITCH PBX server (`fusion`, 134.209.72.226).
Debian 12, FreeSWITCH, FusionPBX, PostgreSQL 18, nginx, PHP 8.2.
---
## Critical: The Database IS the Config
FusionPBX stores **everything** in PostgreSQL (`fusionpbx` database):
- Extensions, voicemail boxes, passwords
- Dialplans and call routing
- SIP gateways (SignalWire trunk)
- IVR menus
- Ring groups
- Device provisioning (Yealink T48S settings)
- Users and permissions
- Call recordings index
The `database/fusionpbx.sql` dump in this repo is the heart of the backup.
---
## What's Backed Up
| Directory | Source | Contents |
|-----------|--------|----------|
| `database/` | `pg_dump fusionpbx` | Complete FusionPBX database — extensions, dialplans, SIP, IVR, everything |
| `database/postgres_globals.sql` | `pg_dumpall --globals` | PostgreSQL roles and passwords |
| `freeswitch/` | `/etc/freeswitch/` | vars.xml, sip_profiles, key autoload configs |
| `fusionpbx-app/` | `/var/www/fusionpbx/resources/` | config.php (DB credentials) |
| `nginx/` | `/etc/nginx/sites-enabled/` | fusionpbx nginx config (incl. all provisioning URL rewrites) |
| `fail2ban/` | `/etc/fail2ban/` | jail.local (trusted IPs: 107.178.2.130, 97.154.109.245) |
| `network/` | `/etc/netplan/` | 50-cloud-init.yaml, hosts, hostname |
| `systemd/` | `/etc/systemd/system/` | All FusionPBX service units |
| `ssh/` | `/root/.ssh/` | authorized_keys |
| `recordings/` | `/var/lib/freeswitch/recordings/` | Call recordings (~3.7MB) |
**Backup schedule:** Every Sunday at 5:00 AM
**Log:** `/var/log/fusionpbx-backup.log`
**Manual trigger:** `/usr/local/bin/fusionpbx-backup`
---
## SSH Access — Important
Port 22 is **firewalled** from the internet. Only accessible from:
- `107.178.2.130` (your home FortiGate external IP)
- `97.154.109.245` (FortiGate secondary)
**From anywhere else, relay through DO:**
```bash
ssh root@165.22.1.228 # DO server (always accessible)
ssh root@134.209.72.226 # then hop to FusionPBX
```
---
## Disaster Recovery — Full Rebuild
**Estimated time: 3045 minutes**
### Step 1 — New Debian 12 Droplet
Create a fresh Debian 12 droplet on DigitalOcean, same region as original.
Get SSH access, then relay via the DO server if needed.
### Step 2 — Clone this repo and run restore
```bash
apt update && apt install -y git
git clone https://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@github.com/myronblair/fusionpbx-config.git /opt/fusionpbx-config
bash /opt/fusionpbx-config/restore.sh
```
The restore script walks through all phases interactively.
### Step 3 — Update fail2ban trusted IPs if FortiGate IP changed
The FortiGate DDNS (`orbisne.fortiddns.com`) resolves to your home IP.
If your external IP changed, update `fail2ban/jail.local`:
```
ignoreip = 127.0.0.1/8 ::1 <new-home-ip> 97.154.109.245
```
### Step 4 — Update Yealink provisioning URL if server IP changed
If the new droplet has a different IP, update the Yealink T48S provisioning:
```
Old URL: http://134.209.72.226/app/provision/?mac={mac}
New URL: http://<new-ip>/app/provision/?mac={mac}
```
Set via Yealink web UI or FusionPBX → Apps → Provision → Devices.
---
## PBX Quick Reference
| Item | Value |
|------|-------|
| FusionPBX web | https://fusion.orbishosting.com |
| Admin login | admin / fY7XP5swgtpbzrYLhkeVYkA4744 |
| Root SSH | root / Joker1974!@# |
| PostgreSQL DB | fusionpbx (user: fusionpbx) |
| FreeSWITCH CLI | `fs_cli` |
| SIP trunk | SignalWire (mod_signalwire) |
| SIP profile | Use `internal` profile on port 5060 |
| NAT setting | `aggressive-nat-detection=true` |
## Extensions
| Ext | Name | Device | Location |
|-----|------|--------|----------|
| 1000 | Myron | Yealink T48S | 10.48.200.43 (FortiGate LAN) |
| 1001 | Tommy | Softphone | Remote |
| 1002 | (spare) | — | — |
| 900 | IVR | Main number auto-attendant | — |
## Key Commands
```bash
# FreeSWITCH CLI
fs_cli
# Inside fs_cli:
sofia status # show SIP profiles
sofia status gateway # show gateway registrations
show registrations # show registered extensions
reload mod_sofia # reload SIP after config change
reloadxml # reload dialplan XML
# Force FusionPBX to regenerate FreeSWITCH XML cache
rm /var/cache/fusionpbx/FusionPBX.configuration.sofia.conf
systemctl restart freeswitch
# Check all FusionPBX services
systemctl status active_calls active_conferences email_queue event_guard \
fax_queue system_status transcribe_queue websockets xml_cdr
# Logs
journalctl -u freeswitch -f
tail -f /var/log/freeswitch/freeswitch.log
tail -f /var/log/nginx/access.log
```
---
## What Is NOT Backed Up
| Item | Notes |
|------|-------|
| SSL certs | `/etc/letsencrypt/` — re-issue: `certbot --nginx -d fusion.orbishosting.com` |
| FusionPBX web app | `/var/www/fusionpbx/` — reinstalled by official installer |
| FreeSWITCH binary | Installed by FusionPBX installer |
| Voicemail audio files | `/var/lib/freeswitch/storage/voicemail/` — small, not critical |
---
## Architecture Notes
- FusionPBX uses a **Lua XML handler** — FreeSWITCH queries PostgreSQL via PHP/Lua for all routing decisions. No static XML dialplan files in production.
- **SignalWire** SIP trunk uses `transport=udp` — critical, TCP caused re-INVITE issues.
- **ext 1000 (Yealink T48S)** registers from behind FortiGate using `aggressive-nat-detection=true` on port 5080 to bypass SIP ALG.
- **FusionPBX cache**: `/var/cache/fusionpbx/FusionPBX.configuration.sofia.conf` — delete this file to force a full Sofia reload after changes.
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env bash
# =============================================================================
# FusionPBX Config Backup — runs on fusion (134.209.72.226)
# Critical: PostgreSQL fusionpbx DB dump + FreeSWITCH configs
# Install: /usr/local/bin/fusionpbx-backup
# Cron: 0 5 * * 0 /usr/local/bin/fusionpbx-backup >> /var/log/fusionpbx-backup.log 2>&1
# =============================================================================
set -euo pipefail
PAT="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"
REPO_URL="https://${PAT}@github.com/myronblair/fusionpbx-config.git"
REPO_DIR="/opt/fusionpbx-config"
LOG_PREFIX="[$(date '+%Y-%m-%d %H:%M:%S')] [fusion]"
log() { echo "$LOG_PREFIX $*"; }
# ---------------------------------------------------------------------------
# 1. Clone or pull repo
# ---------------------------------------------------------------------------
if [[ -d "$REPO_DIR/.git" ]]; then
log "Pulling latest from GitHub"
cd "$REPO_DIR"
git config user.email "backup@orbishosting.com"
git config user.name "FusionPBX Backup"
git pull --rebase origin main -q || true
else
log "Cloning repo to $REPO_DIR"
git clone "$REPO_URL" "$REPO_DIR"
cd "$REPO_DIR"
git config user.email "backup@orbishosting.com"
git config user.name "FusionPBX Backup"
fi
cd "$REPO_DIR"
mkdir -p database freeswitch/autoload_configs freeswitch/sip_profiles \
nginx fail2ban network systemd ssh recordings
# ---------------------------------------------------------------------------
# 2. PostgreSQL dump — THE most critical piece
# Everything (extensions, dialplans, SIP gateways, IVR, ring groups,
# devices, voicemail, users) lives here.
# ---------------------------------------------------------------------------
log "Dumping PostgreSQL fusionpbx database"
su -c "pg_dump --clean --if-exists fusionpbx" postgres > database/fusionpbx.sql 2>/dev/null
DUMP_SIZE=$(wc -c < database/fusionpbx.sql)
log " DB dump: $(numfmt --to=iec $DUMP_SIZE 2>/dev/null || echo ${DUMP_SIZE}B)"
# Also dump roles/users
su -c "pg_dumpall --globals-only" postgres > database/postgres_globals.sql 2>/dev/null
# ---------------------------------------------------------------------------
# 3. FreeSWITCH config (key files — FusionPBX dynamically generates the rest)
# ---------------------------------------------------------------------------
log "Backing up FreeSWITCH config"
cp /etc/freeswitch/vars.xml freeswitch/ 2>/dev/null || true
cp /etc/freeswitch/freeswitch.xml freeswitch/ 2>/dev/null || true
cp /etc/freeswitch/extensions.conf freeswitch/ 2>/dev/null || true
# SIP profiles (noload — managed by FusionPBX, but useful as reference)
rsync -a --delete /etc/freeswitch/sip_profiles/ freeswitch/sip_profiles/ 2>/dev/null || true
# Autoload configs that may have been customized
for f in switch.conf.xml sofia.conf.xml event_socket.conf.xml modules.conf.xml \
lua.conf.xml conference.conf logfile.conf.xml; do
[[ -f "/etc/freeswitch/autoload_configs/$f" ]] && \
cp "/etc/freeswitch/autoload_configs/$f" freeswitch/autoload_configs/ || true
done
# ---------------------------------------------------------------------------
# 4. FusionPBX application config (has DB credentials + domain settings)
# ---------------------------------------------------------------------------
log "Backing up FusionPBX app config"
mkdir -p fusionpbx-app
[[ -f /var/www/fusionpbx/resources/config.php ]] && \
cp /var/www/fusionpbx/resources/config.php fusionpbx-app/ || true
# ---------------------------------------------------------------------------
# 5. nginx config
# ---------------------------------------------------------------------------
log "Backing up nginx config"
[[ -f /etc/nginx/sites-enabled/fusionpbx ]] && \
cp /etc/nginx/sites-enabled/fusionpbx nginx/fusionpbx.conf || true
# ---------------------------------------------------------------------------
# 6. fail2ban
# ---------------------------------------------------------------------------
log "Backing up fail2ban"
[[ -f /etc/fail2ban/jail.local ]] && cp /etc/fail2ban/jail.local fail2ban/ || true
rsync -a --delete /etc/fail2ban/jail.d/ fail2ban/jail.d/ 2>/dev/null || true
# ---------------------------------------------------------------------------
# 7. Network / netplan
# ---------------------------------------------------------------------------
log "Backing up network"
for f in /etc/netplan/*.yaml; do
[[ -f "$f" ]] && cp "$f" network/ || true
done
cp /etc/hosts network/hosts 2>/dev/null || true
cp /etc/hostname network/hostname 2>/dev/null || true
# ---------------------------------------------------------------------------
# 8. Systemd units (FusionPBX service daemons)
# ---------------------------------------------------------------------------
log "Backing up systemd units"
FPBX_UNITS="active_calls active_conferences email_queue event_guard fax_queue system_status transcribe_queue websockets xml_cdr"
for unit in $FPBX_UNITS; do
[[ -f "/etc/systemd/system/$unit.service" ]] && \
cp "/etc/systemd/system/$unit.service" systemd/ || true
done
# ---------------------------------------------------------------------------
# 9. SSH authorized_keys
# ---------------------------------------------------------------------------
log "Backing up SSH keys"
[[ -f /root/.ssh/authorized_keys ]] && cp /root/.ssh/authorized_keys ssh/ || true
# ---------------------------------------------------------------------------
# 10. Recordings (small — 3.7MB)
# ---------------------------------------------------------------------------
log "Backing up recordings"
if [[ -d /var/lib/freeswitch/recordings ]]; then
rsync -a --delete /var/lib/freeswitch/recordings/ recordings/ 2>/dev/null || true
RECSIZE=$(du -sh recordings/ 2>/dev/null | cut -f1)
log " Recordings: $RECSIZE"
fi
# ---------------------------------------------------------------------------
# 11. Commit and push
# ---------------------------------------------------------------------------
log "Committing changes"
git add -A
if git diff --cached --quiet; then
log "No changes to commit"
else
CHANGES=$(git diff --cached --stat | tail -1)
git commit -m "[fusion] Weekly backup $(date '+%Y-%m-%d')$CHANGES"
log "Pushing to GitHub"
git push origin main
log "Backup complete"
fi
+283
View File
@@ -0,0 +1,283 @@
#!/usr/bin/env bash
# =============================================================================
# FusionPBX Restore — run on a fresh Debian 12 droplet
#
# Usage:
# bash restore.sh
#
# NOTE: SSH to this server is firewalled — access via DO server relay:
# ssh root@165.22.1.228
# ssh root@134.209.72.226
# =============================================================================
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
header() { echo -e "\n${CYAN}══════════════════════════════════════════════════${NC}"; echo -e "${CYAN}${BOLD} $*${NC}"; echo -e "${CYAN}══════════════════════════════════════════════════${NC}"; }
success() { echo -e "${GREEN}$*${NC}"; }
warn() { echo -e "${YELLOW}$*${NC}"; }
info() { echo -e "$*"; }
die() { echo -e "${RED}$*${NC}" >&2; exit 1; }
confirm() {
echo -e "\n${YELLOW} $1${NC}"
read -rp " Apply? [Y/n] " ans
[[ "${ans:-Y}" =~ ^[Yy]$ ]]
}
[[ $(id -u) -eq 0 ]] || die "Must run as root"
clear
echo -e "${CYAN}"
cat << 'BANNER'
╔══════════════════════════════════════════════════════╗
║ FUSIONPBX RESTORE — fusion.orbishosting.com ║
║ 134.209.72.226 | Debian 12 | FreeSWITCH ║
╚══════════════════════════════════════════════════════╝
BANNER
echo -e "${NC}"
echo " Source : $REPO_DIR"
echo " Date : $(date)"
echo ""
warn "SSH to this server is port-restricted."
warn "Access via: ssh root@165.22.1.228, then ssh root@134.209.72.226"
echo ""
read -rp " Type 'yes' to continue: " c
[[ "$c" == "yes" ]] || { echo "Aborted."; exit 0; }
APPLIED=(); SKIPPED=()
# ---------------------------------------------------------------------------
# PHASE 1: SSH & Network
# ---------------------------------------------------------------------------
header "PHASE 1 — SSH & Network"
if [[ -f "$REPO_DIR/ssh/authorized_keys" ]] && confirm "Restore SSH authorized_keys?"; then
mkdir -p /root/.ssh && chmod 700 /root/.ssh
cp "$REPO_DIR/ssh/authorized_keys" /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
success "authorized_keys restored"
APPLIED+=("ssh")
else; SKIPPED+=("ssh"); fi
if confirm "Set hostname to 'fusion' (fusion.orbishosting.com)?"; then
hostnamectl set-hostname fusion
echo "127.0.1.1 fusion.orbishosting.com" >> /etc/hosts
success "Hostname set"
APPLIED+=("hostname")
else; SKIPPED+=("hostname"); fi
# ---------------------------------------------------------------------------
# PHASE 2: Install FusionPBX + FreeSWITCH
# ---------------------------------------------------------------------------
header "PHASE 2 — Install FusionPBX (official installer)"
echo ""
warn "The official FusionPBX installer handles everything:"
warn "FreeSWITCH, PostgreSQL, nginx, PHP, fail2ban, all systemd units."
echo ""
info "Run this in a separate terminal and come back when done (~10-15 min):"
echo ""
echo -e " ${BOLD}wget -O - https://raw.githubusercontent.com/fusionpbx/fusionpbx-install.sh/master/debian/install.sh | bash${NC}"
echo ""
warn "During install, when asked for the domain: enter fusion.orbishosting.com"
warn "Note the admin username/password it generates — you'll change it after DB restore."
echo ""
read -rp " Press ENTER once FusionPBX is fully installed... "
# Verify install
if [[ ! -f /var/www/fusionpbx/index.php ]]; then
warn "FusionPBX doesn't appear to be installed at /var/www/fusionpbx/"
read -rp " Continue anyway? [y/N] " ans
[[ "${ans:-N}" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; }
fi
# ---------------------------------------------------------------------------
# PHASE 3: Restore PostgreSQL Database — THE critical step
# ---------------------------------------------------------------------------
header "PHASE 3 — Restore PostgreSQL Database (ALL CONFIG)"
echo ""
warn "This restores ALL FusionPBX config: extensions, dialplans, SIP gateways,"
warn "IVR menus, ring groups, devices, voicemail settings, users — everything."
echo ""
info "Backup DB dump: $REPO_DIR/database/fusionpbx.sql"
info "Size: $(wc -l < $REPO_DIR/database/fusionpbx.sql 2>/dev/null) lines"
echo ""
if confirm "Stop services and restore PostgreSQL fusionpbx database?"; then
# Stop FusionPBX services before restoring
for svc in active_calls active_conferences email_queue event_guard fax_queue \
system_status transcribe_queue websockets xml_cdr freeswitch; do
systemctl stop "$svc" 2>/dev/null || true
done
info "Services stopped"
# Drop and recreate the database
su -c "psql -c 'DROP DATABASE IF EXISTS fusionpbx;'" postgres
su -c "psql -c 'CREATE DATABASE fusionpbx OWNER fusionpbx;'" postgres
su -c "psql fusionpbx < '$REPO_DIR/database/fusionpbx.sql'" postgres
success "Database restored"
# Restore postgres globals (roles/passwords)
if [[ -f "$REPO_DIR/database/postgres_globals.sql" ]]; then
su -c "psql < '$REPO_DIR/database/postgres_globals.sql'" postgres 2>/dev/null || true
success "PostgreSQL globals restored"
fi
# Restart FreeSWITCH and FusionPBX services
systemctl start freeswitch
sleep 3
for svc in active_calls active_conferences email_queue event_guard fax_queue \
system_status transcribe_queue websockets xml_cdr; do
systemctl start "$svc" 2>/dev/null || true
done
success "Services restarted"
APPLIED+=("database")
else; SKIPPED+=("database"); fi
# ---------------------------------------------------------------------------
# PHASE 4: FreeSWITCH Config
# ---------------------------------------------------------------------------
header "PHASE 4 — FreeSWITCH Config"
if [[ -d "$REPO_DIR/freeswitch" ]] && confirm "Restore FreeSWITCH config files?"; then
[[ -f "$REPO_DIR/freeswitch/vars.xml" ]] && \
cp "$REPO_DIR/freeswitch/vars.xml" /etc/freeswitch/
[[ -f "$REPO_DIR/freeswitch/freeswitch.xml" ]] && \
cp "$REPO_DIR/freeswitch/freeswitch.xml" /etc/freeswitch/
# Autoload configs
if [[ -d "$REPO_DIR/freeswitch/autoload_configs" ]]; then
rsync -a "$REPO_DIR/freeswitch/autoload_configs/" \
/etc/freeswitch/autoload_configs/
fi
# Fix ownership
chown -R freeswitch:freeswitch /etc/freeswitch/ 2>/dev/null || true
# Force reload of FusionPBX XML cache
rm -f /var/cache/fusionpbx/FusionPBX.configuration.sofia.conf 2>/dev/null || true
systemctl reload freeswitch 2>/dev/null || systemctl restart freeswitch
success "FreeSWITCH config restored and reloaded"
APPLIED+=("freeswitch-config")
else; SKIPPED+=("freeswitch-config"); fi
# ---------------------------------------------------------------------------
# PHASE 5: FusionPBX App Config
# ---------------------------------------------------------------------------
header "PHASE 5 — FusionPBX App Config (DB credentials)"
if [[ -f "$REPO_DIR/fusionpbx-app/config.php" ]] && \
confirm "Restore FusionPBX resources/config.php (contains DB credentials)?"; then
cp "$REPO_DIR/fusionpbx-app/config.php" /var/www/fusionpbx/resources/config.php
chown www-data:www-data /var/www/fusionpbx/resources/config.php
success "FusionPBX config.php restored"
APPLIED+=("fusionpbx-config")
else; SKIPPED+=("fusionpbx-config"); fi
# ---------------------------------------------------------------------------
# PHASE 6: nginx Config
# ---------------------------------------------------------------------------
header "PHASE 6 — nginx Config"
if [[ -f "$REPO_DIR/nginx/fusionpbx.conf" ]] && confirm "Restore nginx fusionpbx config?"; then
cp "$REPO_DIR/nginx/fusionpbx.conf" /etc/nginx/sites-enabled/fusionpbx
nginx -t && systemctl reload nginx
success "nginx config restored and reloaded"
APPLIED+=("nginx")
else
SKIPPED+=("nginx")
warn "Skipped — installer's nginx config will work; restore if provisioning URLs break"
fi
# ---------------------------------------------------------------------------
# PHASE 7: fail2ban
# ---------------------------------------------------------------------------
header "PHASE 7 — fail2ban"
if [[ -f "$REPO_DIR/fail2ban/jail.local" ]] && confirm "Restore fail2ban jail.local (includes trusted IPs)?"; then
cp "$REPO_DIR/fail2ban/jail.local" /etc/fail2ban/jail.local
[[ -d "$REPO_DIR/fail2ban/jail.d" ]] && \
rsync -a "$REPO_DIR/fail2ban/jail.d/" /etc/fail2ban/jail.d/
systemctl restart fail2ban
success "fail2ban restored — trusted IPs: 107.178.2.130, 97.154.109.245"
APPLIED+=("fail2ban")
else; SKIPPED+=("fail2ban"); fi
# ---------------------------------------------------------------------------
# PHASE 8: Recordings
# ---------------------------------------------------------------------------
header "PHASE 8 — Recordings"
if [[ -d "$REPO_DIR/recordings" ]] && \
[[ -n "$(ls -A $REPO_DIR/recordings 2>/dev/null)" ]] && \
confirm "Restore call recordings?"; then
rsync -a "$REPO_DIR/recordings/" /var/lib/freeswitch/recordings/
chown -R freeswitch:freeswitch /var/lib/freeswitch/recordings/
success "Recordings restored"
APPLIED+=("recordings")
else; SKIPPED+=("recordings"); fi
# ---------------------------------------------------------------------------
# PHASE 9: Backup script + cron
# ---------------------------------------------------------------------------
header "PHASE 9 — Backup Script & Cron"
if confirm "Install fusionpbx-backup cron (weekly Sunday 5am)?"; then
cp "$REPO_DIR/backup.sh" /usr/local/bin/fusionpbx-backup
chmod +x /usr/local/bin/fusionpbx-backup
(crontab -l 2>/dev/null | grep -v fusionpbx-backup; \
echo "0 5 * * 0 /usr/local/bin/fusionpbx-backup >> /var/log/fusionpbx-backup.log 2>&1") | crontab -
success "Backup cron installed"
APPLIED+=("backup-cron")
else; SKIPPED+=("backup-cron"); fi
# ---------------------------------------------------------------------------
# PHASE 10: SSL (manual)
# ---------------------------------------------------------------------------
header "PHASE 10 — SSL Certificate"
echo ""
info "Re-issue SSL cert after DNS is pointing to this server:"
info " certbot --nginx -d fusion.orbishosting.com"
info " OR: FusionPBX web UI → Admin → Certificate Manager"
echo ""
read -rp " Press ENTER to continue... "
# ---------------------------------------------------------------------------
# PHASE 11: SignalWire SIP Trunk
# ---------------------------------------------------------------------------
header "PHASE 11 — SignalWire SIP Trunk"
echo ""
warn "The SignalWire SIP gateway is stored in the PostgreSQL DB and will"
warn "be restored automatically with the DB dump."
echo ""
info "After restore, verify in FusionPBX → Accounts → Gateways:"
info " Gateway: signalwire-inbound (or similar)"
info " SIP profile: external (transport=udp — required to avoid re-INVITE issues)"
info " If calls don't work: Admin → FreeSWITCH → Reload XML"
info " Also delete Sofia XML cache: rm /var/cache/fusionpbx/FusionPBX.configuration.sofia.conf"
echo ""
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
header "Restore Complete"
echo ""
[[ ${#APPLIED[@]} -gt 0 ]] && success "Applied: ${APPLIED[*]}"
[[ ${#SKIPPED[@]} -gt 0 ]] && warn "Skipped: ${SKIPPED[*]}"
echo ""
echo -e "${YELLOW} Final checklist:${NC}"
echo " • FusionPBX web UI: https://fusion.orbishosting.com (admin / fY7XP5swgtpbzrYLhkeVYkA4744)"
echo " • Check FreeSWITCH status: systemctl status freeswitch"
echo " • Check gateways registered: fs_cli -x 'sofia status gateway'"
echo " • Check extensions load: fs_cli -x 'show registrations'"
echo " • Check fail2ban trusted IPs: fail2ban-client status"
echo " • Test ext 1000 (Myron Yealink T48S at 10.48.200.43) — update provisioning URL if IP changed"
echo " • Test ext 1001 (Tommy) registration"
echo " • Test IVR 900 (main number)"
echo " • Verify SignalWire trunk: make outbound test call"
echo ""
echo " SSH access: only from 107.178.2.130 and 97.154.109.245 (FortiGate)"
echo " Or relay: ssh root@165.22.1.228 → ssh root@134.209.72.226"
echo ""