Refactor entire project for Docker-native operation

Complete Docker-first refactor of the 6,800-line management script:

Core Architecture:
- Added is_docker() detection (/.dockerenv + /proc/1/cgroup check)
- Added asterisk_running() helper replacing all systemctl is-active calls
- Moved restart_asterisk_safe() to top-level with Docker/bare-metal branches
- Added webadmin_running(), start_webadmin(), stop_webadmin(), restart_webadmin()
  for process-based web admin management (replaces systemd service)

Functions Refactored (Docker-aware):
- fix_asterisk_systemd(): no-op in Docker (no systemd)
- install_asterisk_packages(): skips apt in Docker (pre-installed)
- install_baresip_packages(): skips in Docker (no local audio client)
- open_firewall_ports(): skips ufw in Docker (host responsibility)
- configure_asterisk(): skips systemctl enable in Docker
- enable_client_services(): skips entirely in Docker (no kiosk client)
- configure_baresip(): skips entirely in Docker
- configure_local_client(): shows error with guidance to use mobile clients
- run_client_diagnostics(): redirects to vpn-diagnostics
- fix_audio_manually(): not available in Docker (no audio hardware)
- uninstall_menu(): shows Docker-specific reset options
- manual_update_asterisk(): shows Docker rebuild instructions
- create_web_admin_service(): no-op in Docker (process-managed)
- web_admin_menu(): uses start/stop/restart_webadmin() instead of systemctl

Menu System:
- show_main_menu(): Docker-specific status display (Asterisk, Web Admin,
  VPN ICE status) with streamlined menu (no Client Settings option)
- submenu_install(): Docker shows Configure/Reset instead of Install/Uninstall
- submenu_tools(): Docker shows Room Directory, Update, VPN Diagnostics,
  DNS Whitelist (hides audio tools that need hardware)

Entrypoint:
- Proper signal trapping (SIGTERM/SIGINT) for clean shutdown
- Generates all Asterisk configs with STUN/ICE support from env vars
- Creates default device categories on first run
- Starts web admin as background process with env-based config

Dockerfile:
- Added lsof dependency (needed for port management)
- Added STUN port 3478 exposure
- Ensured /.dockerenv marker exists

Backward compatible: bare-metal installs work exactly as before.

https://claude.ai/code/session_01Vm6NLaQuzM4VosAotqS1q8
This commit is contained in:
Claude
2026-02-21 14:39:38 +00:00
parent 9caa795a78
commit d05f1f9e3b
3 changed files with 462 additions and 216 deletions
+102 -61
View File
@@ -2,12 +2,12 @@
# ================================================================
# Easy Asterisk Docker Entrypoint
#
# Starts Asterisk + Web Admin, applies environment configuration
# Initializes configuration, starts Asterisk + Web Admin
# Uses the same config functions as the main script
# ================================================================
set -e
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
@@ -16,7 +16,16 @@ NC='\033[0m'
log_info() { echo -e "${GREEN}[entrypoint]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[entrypoint]${NC} $1"; }
# ── 1. Generate self-signed certs if missing ──────────────────
CONFIG_DIR="/etc/easy-asterisk"
CONFIG_FILE="${CONFIG_DIR}/config"
WEB_ADMIN_SCRIPT="/usr/local/bin/easy-asterisk-webadmin"
# ── 1. Ensure asterisk user exists ───────────────────────────
if ! id asterisk >/dev/null 2>&1; then
useradd -r -s /bin/false -d /var/lib/asterisk asterisk 2>/dev/null || true
fi
# ── 2. Generate self-signed certs if missing ──────────────────
if [[ ! -f /etc/asterisk/certs/server.crt ]]; then
log_info "Generating self-signed TLS certificate..."
mkdir -p /etc/asterisk/certs
@@ -29,12 +38,9 @@ if [[ ! -f /etc/asterisk/certs/server.crt ]]; then
chmod 600 /etc/asterisk/certs/server.key
fi
# ── 2. Apply environment-based configuration ──────────────────
CONFIG_DIR="/etc/easy-asterisk"
CONFIG_FILE="${CONFIG_DIR}/config"
# ── 3. Create config from environment if first run ────────────
mkdir -p "$CONFIG_DIR"
# If no config exists, create from environment variables
if [[ ! -f "$CONFIG_FILE" ]]; then
log_info "Creating initial configuration from environment..."
cat > "$CONFIG_FILE" << EOF
@@ -65,41 +71,55 @@ EOF
chmod 644 "$CONFIG_FILE"
fi
# ── 3. Configure STUN if self-hosted coturn is available ──────
if [[ -n "$STUN_SERVER" ]]; then
log_info "Using STUN server: ${STUN_SERVER}"
source "$CONFIG_FILE" 2>/dev/null || true
# Source config for use in this script
source "$CONFIG_FILE" 2>/dev/null || true
# Update rtp.conf with custom STUN
cat > /etc/asterisk/rtp.conf << EOF
[general]
rtpstart=${RTP_START:-10000}
rtpend=${RTP_END:-20000}
strictrtp=yes
icesupport=yes
stunaddr=${STUN_SERVER}
# ── 4. Initialize default categories if missing ──────────────
CATEGORIES_FILE="${CONFIG_DIR}/categories.conf"
if [[ ! -f "$CATEGORIES_FILE" ]]; then
log_info "Creating default device categories..."
cat > "$CATEGORIES_FILE" << 'EOF'
kiosks|Kiosks|yes|Fixed wall-mount tablets & intercoms
mobile|Mobile|no|Phones & tablets (ring normally)
custom|Custom|no|Custom configuration
EOF
chown asterisk:asterisk /etc/asterisk/rtp.conf
fi
# ── 4. Generate default Asterisk configs if missing ───────────
if [[ ! -f /etc/asterisk/pjsip.conf ]] || [[ ! -s /etc/asterisk/pjsip.conf ]]; then
log_info "Generating default PJSIP configuration..."
local_ip=$(hostname -I | awk '{print $1}')
raw_cidr=$(ip -o -f inet addr show | awk '/scope global/ {print $4}' | head -1)
default_cidr="$raw_cidr"
if [[ "$raw_cidr" =~ \.([0-9]+)/24$ ]]; then default_cidr="${raw_cidr%.*}.0/24"; fi
nat_settings=""
source "$CONFIG_FILE" 2>/dev/null || true
if [[ "$HAS_VLANS" == "y" && -n "$VLAN_SUBNETS" ]]; then
nat_settings="local_net=${default_cidr}"
for subnet in $VLAN_SUBNETS; do
nat_settings="${nat_settings}
local_net=${subnet}"
done
# ── 5. Configure STUN/ICE ────────────────────────────────────
# Allow STUN_SERVER env to override config
if [[ -n "${STUN_SERVER:-}" ]]; then
log_info "STUN server configured: ${STUN_SERVER}"
# Update config file
if ! grep -q "^VPN_ICE_ENABLED=" "$CONFIG_FILE" 2>/dev/null; then
echo "VPN_ICE_ENABLED=\"y\"" >> "$CONFIG_FILE"
echo "CUSTOM_STUN_SERVER=\"${STUN_SERVER}\"" >> "$CONFIG_FILE"
else
sed -i "s|^VPN_ICE_ENABLED=.*|VPN_ICE_ENABLED=\"y\"|" "$CONFIG_FILE"
sed -i "s|^CUSTOM_STUN_SERVER=.*|CUSTOM_STUN_SERVER=\"${STUN_SERVER}\"|" "$CONFIG_FILE"
fi
VPN_ICE_ENABLED="y"
CUSTOM_STUN_SERVER="${STUN_SERVER}"
fi
# ── 6. Generate Asterisk configs if missing ───────────────────
local_ip=$(hostname -I 2>/dev/null | awk '{print $1}')
raw_cidr=$(ip -o -f inet addr show 2>/dev/null | awk '/scope global/ {print $4}' | head -1)
default_cidr="$raw_cidr"
if [[ "$raw_cidr" =~ \.([0-9]+)/24$ ]]; then default_cidr="${raw_cidr%.*}.0/24"; fi
# Build NAT/local_net settings
nat_settings=""
all_local_nets="local_net=${LOCAL_CIDR:-$default_cidr}"
if [[ "${HAS_VLANS:-n}" == "y" && -n "${VLAN_SUBNETS:-}" ]]; then
for subnet in $VLAN_SUBNETS; do
all_local_nets="${all_local_nets}
local_net=${subnet}"
done
nat_settings="${all_local_nets}"
fi
if [[ ! -f /etc/asterisk/pjsip.conf ]] || [[ ! -s /etc/asterisk/pjsip.conf ]]; then
log_info "Generating PJSIP configuration..."
cat > /etc/asterisk/pjsip.conf << EOF
; Easy Asterisk (Docker)
[global]
@@ -136,8 +156,8 @@ EOF
fi
if [[ ! -f /etc/asterisk/extensions.conf ]] || [[ ! -s /etc/asterisk/extensions.conf ]]; then
log_info "Generating default dialplan..."
cat > /etc/asterisk/extensions.conf << EOF
log_info "Generating dialplan..."
cat > /etc/asterisk/extensions.conf << 'EOF'
[general]
static=yes
writeprotect=no
@@ -148,27 +168,28 @@ EOF
chown asterisk:asterisk /etc/asterisk/extensions.conf
fi
if [[ ! -f /etc/asterisk/rtp.conf ]]; then
log_info "Generating default RTP configuration..."
cat > /etc/asterisk/rtp.conf << EOF
# RTP config with STUN/ICE support
log_info "Configuring RTP..."
ice_stun_config="# icesupport disabled - LAN only mode"
if [[ "${VPN_ICE_ENABLED:-n}" == "y" ]] || [[ -n "${DOMAIN_NAME:-}" ]]; then
stun_addr="${CUSTOM_STUN_SERVER:-stun.l.google.com:19302}"
ice_stun_config="icesupport=yes
stunaddr=${stun_addr}"
log_info "ICE enabled, STUN: ${stun_addr}"
fi
cat > /etc/asterisk/rtp.conf << EOF
[general]
rtpstart=${RTP_START:-10000}
rtpend=${RTP_END:-20000}
strictrtp=yes
# icesupport disabled - LAN only mode
${ice_stun_config}
EOF
chown asterisk:asterisk /etc/asterisk/rtp.conf
fi
# Generate other required configs
for conf in asterisk.conf logger.conf modules.conf; do
if [[ ! -f "/etc/asterisk/$conf" ]]; then
log_info "Generating /etc/asterisk/$conf..."
fi
done
chown asterisk:asterisk /etc/asterisk/rtp.conf
# Generate other core configs if missing
if [[ ! -f /etc/asterisk/asterisk.conf ]]; then
cat > /etc/asterisk/asterisk.conf << EOF
cat > /etc/asterisk/asterisk.conf << 'EOF'
[directories]
[options]
runuser = asterisk
@@ -177,33 +198,53 @@ EOF
fi
if [[ ! -f /etc/asterisk/logger.conf ]]; then
cat > /etc/asterisk/logger.conf << EOF
cat > /etc/asterisk/logger.conf << 'EOF'
[general]
[logfiles]
console => notice,warning,error
EOF
fi
# ── 5. Fix permissions ───────────────────────────────────────
if [[ ! -f /etc/asterisk/modules.conf ]]; then
cat > /etc/asterisk/modules.conf << 'EOF'
[modules]
autoload = yes
EOF
fi
# ── 7. Fix permissions ───────────────────────────────────────
chown -R asterisk:asterisk /etc/asterisk /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk 2>/dev/null || true
# ── 6. Start Web Admin in background (if script exists) ──────
WEB_ADMIN_SCRIPT="/usr/local/bin/easy-asterisk-webadmin"
# ── 8. Start Web Admin in background ─────────────────────────
if [[ -f "$WEB_ADMIN_SCRIPT" ]]; then
source "$CONFIG_FILE" 2>/dev/null || true
log_info "Starting Web Admin on port ${WEB_ADMIN_PORT:-8080}..."
WEBADMIN_PORT="${WEB_ADMIN_PORT:-8080}" \
WEBADMIN_AUTH_DISABLED="${WEB_ADMIN_AUTH_DISABLED:-false}" \
python3 "$WEB_ADMIN_SCRIPT" &
fi
# ── 7. Start Asterisk in foreground ──────────────────────────
# ── 9. Trap signals for clean shutdown ────────────────────────
cleanup() {
log_info "Shutting down..."
# Stop web admin
pkill -f "easy-asterisk-webadmin" 2>/dev/null || true
# Graceful Asterisk shutdown
asterisk -rx "core stop now" 2>/dev/null || true
exit 0
}
trap cleanup SIGTERM SIGINT
# ── 10. Start Asterisk in foreground ──────────────────────────
log_info "Starting Asterisk PBX..."
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${CYAN} Easy Asterisk (Docker)${NC}"
echo -e "${CYAN} Management: docker exec -it easy-asterisk easy-asterisk${NC}"
echo -e "${CYAN} Diagnostics: docker exec -it easy-asterisk vpn-diagnostics${NC}"
echo -e "${CYAN} DNS Check: docker exec -it easy-asterisk dns-whitelist${NC}"
echo -e "${CYAN} Server IP: ${local_ip}${NC}"
[[ "${VPN_ICE_ENABLED:-n}" == "y" ]] && echo -e "${CYAN} STUN/ICE: ${CUSTOM_STUN_SERVER:-auto}${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${CYAN} Management: docker exec -it easy-asterisk easy-asterisk${NC}"
echo -e "${CYAN} Diagnostics: docker exec -it easy-asterisk vpn-diagnostics${NC}"
echo -e "${CYAN} DNS Check: docker exec -it easy-asterisk dns-whitelist${NC}"
echo -e "${CYAN} Web Admin: http://${local_ip}:${WEB_ADMIN_PORT:-8080}/clients${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
exec asterisk -f -U asterisk -G asterisk