#!/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 "" if [[ -f "$REPO_DIR/database/fusionpbx.sql.gz" ]]; then info "Backup DB dump: $REPO_DIR/database/fusionpbx.sql.gz (compressed)" info "Size: $(du -sh $REPO_DIR/database/fusionpbx.sql.gz 2>/dev/null | cut -f1)" elif [[ -f "$REPO_DIR/database/fusionpbx.sql" ]]; then info "Backup DB dump: $REPO_DIR/database/fusionpbx.sql" info "Size: $(wc -l < $REPO_DIR/database/fusionpbx.sql 2>/dev/null) lines" else warn "No database dump found!" fi 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 # Restore from compressed or uncompressed dump if [[ -f "$REPO_DIR/database/fusionpbx.sql.gz" ]]; then zcat "$REPO_DIR/database/fusionpbx.sql.gz" | su -c "psql fusionpbx" postgres else su -c "psql fusionpbx < '$REPO_DIR/database/fusionpbx.sql'" postgres fi 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 ""