#!/bin/bash # ═══════════════════════════════════════════════════════════════════════════════ # AelynaCP Installer — Fully Automatic # Copyright (c) 2026 AelynaCP. All rights reserved. # https://aelynacp.com # ═══════════════════════════════════════════════════════════════════════════════ set -uo pipefail # Reopen stdin from terminal exec < /dev/tty 2>/dev/null || true # ── Constants ───────────────────────────────────────────────────────────────── AELYNACP_VERSION="0.3.4" INSTALL_DIR="/opt/aelynacp" CONFIG_DIR="/etc/aelynacp" DATA_DIR="/var/lib/aelynacp" LOG_DIR="/var/log/aelynacp" RUN_DIR="/var/run/aelynacp" WEB_DIR="${INSTALL_DIR}/web" BIN_DIR="${INSTALL_DIR}/bin" LOG_FILE="/tmp/aelynacp-install.log" DB_NAME="aelynacp" DB_USER="aelynacp" DB_PASS="" ADMIN_PASS="" # ── Colors ──────────────────────────────────────────────────────────────────── RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m' MAGENTA='\033[0;35m'; WHITE='\033[1;37m'; GRAY='\033[0;90m'; BOLD='\033[1m'; NC='\033[0m' # ── Detect ──────────────────────────────────────────────────────────────────── OS_TYPE="" ; PKG_MGR="" HOSTNAME_INPUT=$(hostname -f 2>/dev/null || hostname 2>/dev/null || echo "server") PRIMARY_IP=$(curl -4 -s --max-time 5 https://ifconfig.me 2>/dev/null || curl -4 -s --max-time 5 https://api.ipify.org 2>/dev/null || hostname -I 2>/dev/null | awk '{print $1}' || echo "0.0.0.0") # ── Progress tracking ──────────────────────────────────────────────────────── TOTAL_TASKS=0 DONE_TASKS=0 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; } info() { echo -e " ${CYAN}▸${NC} $*"; log "INFO: $*"; } success() { DONE_TASKS=$((DONE_TASKS + 1)) echo -e " ${GREEN}✓${NC} $*" log "OK: $*" draw_progress } warn() { echo -e " ${YELLOW}⚠${NC} $*"; log "WARN: $*"; } error() { echo -e " ${RED}✗${NC} $*"; log "ERROR: $*"; } fatal() { echo -e "\n ${RED}${BOLD}✗ ERRORE FATALE:${NC} $*" echo -e " ${GRAY}Log: ${LOG_FILE}${NC}\n" exit 1 } draw_progress() { if [ "$TOTAL_TASKS" -le 0 ]; then return; fi local pct=$((DONE_TASKS * 100 / TOTAL_TASKS)) if [ "$pct" -gt 100 ]; then pct=100; fi local width=50 local filled=$((pct * width / 100)) local empty=$((width - filled)) local bar="" for ((i=0; i/dev/null; do echo -ne "\r ${CYAN}${chars:$i:1}${NC} ${msg}..." i=$(( (i + 1) % ${#chars} )) sleep 0.1 done wait "$pid" 2>/dev/null local rc=$? echo -ne "\r \r" return $rc } run_task() { local msg="$1"; shift "$@" >> "$LOG_FILE" 2>&1 & spinner $! "$msg" if [ $? -eq 0 ]; then success "$msg" else error "$msg" fi } pkg_install() { if [ "$PKG_MGR" = "dnf" ]; then dnf install -y "$@" >> "$LOG_FILE" 2>&1 else DEBIAN_FRONTEND=noninteractive apt-get install -y "$@" >> "$LOG_FILE" 2>&1 fi } detect_os() { if [ -f /etc/os-release ]; then . /etc/os-release case "$ID" in rocky|almalinux|rhel|centos|fedora|ol) OS_TYPE="rhel"; PKG_MGR="dnf" ;; debian|ubuntu) OS_TYPE="debian"; PKG_MGR="apt" ;; *) fatal "OS non supportato: $ID" ;; esac else fatal "Impossibile rilevare il sistema operativo" fi } generate_password() { tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 24; } generate_admin_password() { tr -dc 'A-Za-z0-9!@#%' < /dev/urandom | head -c 16; } generate_hex() { tr -dc 'a-f0-9' < /dev/urandom | head -c "${1:-64}"; } # ═══════════════════════════════════════════════════════════════════════════════ # MAIN # ═══════════════════════════════════════════════════════════════════════════════ clear echo -e "${MAGENTA}" echo ' ___ __ __________ ' echo ' / | ___ / /_ ______ ____ _/ ____/ __ \' echo ' / /| | / _ \/ / / / / __ \/ __ `/ / / /_/ /' echo ' / ___ |/ __/ / /_/ / / / / /_/ / /___/ ____/ ' echo '/_/ |_|\___/_/\__, /_/ /_/\__,_/\____/_/ ' echo ' /____/ ' echo -e "${NC}" echo -e "${WHITE}${BOLD} AELYNA${CYAN}™${WHITE}CP${NC} ${GRAY}v${AELYNACP_VERSION}${NC}" echo -e "${GRAY} Hosting Control Panel${NC}" echo "" # ── Preflight ───────────────────────────────────────────────────────────────── [ "$(id -u)" -ne 0 ] && fatal "Esegui come root" detect_os echo "=== AelynaCP Install ===" > "$LOG_FILE" echo "Date: $(date), OS: ${ID} ${VERSION_ID}, IP: ${PRIMARY_IP}" >> "$LOG_FILE" echo -e " ${WHITE}Server:${NC} ${CYAN}${HOSTNAME_INPUT}${NC} (${PRIMARY_IP})" echo -e " ${WHITE}OS:${NC} ${CYAN}${ID} ${VERSION_ID}${NC} (${OS_TYPE})" echo "" # Count total tasks for progress bar if [ "$OS_TYPE" = "rhel" ]; then TOTAL_TASKS=40 else TOTAL_TASKS=38 fi echo -e " ${WHITE}Installazione in corso...${NC}" echo "" # ── Install Packages ────────────────────────────────────────────────────────── if [ "$OS_TYPE" = "rhel" ]; then run_task "Tools base" pkg_install tar gzip rsync openssl unzip wget curl python3 python3-pip sudo run_task "EPEL" dnf install -y epel-release /usr/bin/crb enable >> "$LOG_FILE" 2>&1 || true rhel_ver=$(rpm -E %rhel) if ! rpm -q remi-release > /dev/null 2>&1; then run_task "Remi repo" dnf install -y "https://rpms.remirepo.net/enterprise/remi-release-${rhel_ver}.rpm" else success "Remi repo" fi dnf module reset php -y >> "$LOG_FILE" 2>&1 || true dnf module enable php:remi-8.3 -y >> "$LOG_FILE" 2>&1 || true # Remove broken PowerDNS repo for EL10 and refresh cache rm -f /etc/yum.repos.d/powerdns-auth.repo 2>/dev/null dnf clean metadata >> "$LOG_FILE" 2>&1 || true run_task "Nginx" pkg_install nginx run_task "PostgreSQL" pkg_install postgresql-server postgresql postgresql-contrib run_task "MariaDB" pkg_install mariadb-server mariadb run_task "PHP 8.3" pkg_install php-fpm php-cli php-mysqlnd php-pgsql php-gd php-xml php-mbstring php-zip php-intl php-opcache php-curl run_task "Postfix" pkg_install postfix run_task "Dovecot" pkg_install dovecot run_task "PowerDNS" pkg_install pdns pdns-backend-postgresql run_task "ProFTPD" pkg_install proftpd pkg_install valkey >> "$LOG_FILE" 2>&1 || pkg_install redis >> "$LOG_FILE" 2>&1 || true; success "Valkey/Redis" run_task "Certbot" pkg_install certbot python3-certbot-nginx run_task "Fail2Ban" pkg_install fail2ban run_task "Firewalld" pkg_install firewalld pkg_install smartmontools sysstat mdadm >> "$LOG_FILE" 2>&1 || true; success "Monitoring" pip3 install argon2-cffi >> "$LOG_FILE" 2>&1 || python3 -m pip install argon2-cffi >> "$LOG_FILE" 2>&1 || true else # Debian/Ubuntu export DEBIAN_FRONTEND=noninteractive run_task "Aggiornamento" apt-get update -y run_task "Nginx" pkg_install nginx run_task "PostgreSQL" pkg_install postgresql postgresql-client postgresql-contrib run_task "MariaDB" pkg_install mariadb-server mariadb-client run_task "PHP 8.3" pkg_install php8.3-fpm php8.3-cli php8.3-mysql php8.3-pgsql php8.3-gd php8.3-xml php8.3-mbstring php8.3-zip php8.3-intl php8.3-opcache php8.3-curl run_task "Postfix" pkg_install postfix run_task "Dovecot" pkg_install dovecot-imapd dovecot-pop3d pkg_install pdns-server pdns-backend-pgsql >> "$LOG_FILE" 2>&1 || true; success "PowerDNS" pkg_install proftpd-basic >> "$LOG_FILE" 2>&1 || true; success "ProFTPD" pkg_install redis-server >> "$LOG_FILE" 2>&1 || true; success "Redis" run_task "Certbot" pkg_install certbot python3-certbot-nginx run_task "Fail2Ban" pkg_install fail2ban pkg_install firewalld >> "$LOG_FILE" 2>&1 || true; success "Firewall" pkg_install smartmontools sysstat >> "$LOG_FILE" 2>&1 || true; success "Monitoring" pip3 install argon2-cffi >> "$LOG_FILE" 2>&1 || true fi # ── Configure Services ──────────────────────────────────────────────────────── # PostgreSQL if [ "$OS_TYPE" = "rhel" ]; then postgresql-setup --initdb >> "$LOG_FILE" 2>&1 || postgresql-setup initdb >> "$LOG_FILE" 2>&1 || true fi systemctl enable --now postgresql >> "$LOG_FILE" 2>&1 || true pg_hba=$(find /var/lib/pgsql /etc/postgresql -name pg_hba.conf 2>/dev/null | head -1) if [ -n "$pg_hba" ] && [ -f "$pg_hba" ]; then cp "$pg_hba" "${pg_hba}.bak" 2>/dev/null || true sed -i 's/^\(local.*all.*all.*\)peer/\1md5/' "$pg_hba" 2>/dev/null || true sed -i 's/^\(local.*all.*all.*\)ident/\1md5/' "$pg_hba" 2>/dev/null || true sed -i 's/^\(host.*all.*all.*127.0.0.1\/32.*\)ident/\1md5/' "$pg_hba" 2>/dev/null || true sed -i 's/^\(host.*all.*all.*::1\/128.*\)ident/\1md5/' "$pg_hba" 2>/dev/null || true grep -q "postgres.*peer" "$pg_hba" || sed -i '1i local all postgres peer' "$pg_hba" 2>/dev/null || true echo "host pdns ${DB_USER} 127.0.0.1/32 md5" >> "$pg_hba" fi systemctl restart postgresql >> "$LOG_FILE" 2>&1 || true DB_PASS=$(generate_password) sudo -u postgres psql -c "CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASS}';" >> "$LOG_FILE" 2>&1 || true sudo -u postgres psql -c "CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};" >> "$LOG_FILE" 2>&1 || true sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};" >> "$LOG_FILE" 2>&1 || true sudo -u postgres psql -d "$DB_NAME" -c "GRANT ALL ON SCHEMA public TO ${DB_USER};" >> "$LOG_FILE" 2>&1 || true sudo -u postgres psql -d "$DB_NAME" -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";" >> "$LOG_FILE" 2>&1 || true sudo -u postgres psql -d "$DB_NAME" -c "CREATE EXTENSION IF NOT EXISTS \"pgcrypto\";" >> "$LOG_FILE" 2>&1 || true success "PostgreSQL" # MariaDB systemctl enable --now mariadb >> "$LOG_FILE" 2>&1 || systemctl enable --now mysql >> "$LOG_FILE" 2>&1 || true mysql -e "DELETE FROM mysql.user WHERE User='';" >> "$LOG_FILE" 2>&1 || true mysql -e "FLUSH PRIVILEGES;" >> "$LOG_FILE" 2>&1 || true cat > /root/.my.cnf << 'MYCNF' [client] user=root MYCNF chmod 600 /root/.my.cnf success "MariaDB" # Nginx mkdir -p /etc/nginx/conf.d/vhosts mkdir -p /var/www/default cat > /var/www/default/index.html << 'HTML' Server

Server in configurazione

Gestito da AelynaCP

HTML if ! grep -q "conf.d/vhosts" /etc/nginx/nginx.conf 2>/dev/null; then sed -i '/include.*conf\.d.*\.conf/a\ include /etc/nginx/conf.d/vhosts/*.conf;' /etc/nginx/nginx.conf 2>/dev/null || true fi systemctl enable --now nginx >> "$LOG_FILE" 2>&1 || true success "Nginx" # PHP-FPM mkdir -p /var/run/php-fpm systemctl enable --now php-fpm >> "$LOG_FILE" 2>&1 || systemctl enable --now php8.3-fpm >> "$LOG_FILE" 2>&1 || true success "PHP-FPM" # Postfix postconf -e "myhostname = ${HOSTNAME_INPUT}" >> "$LOG_FILE" 2>&1 || true postconf -e "inet_interfaces = all" >> "$LOG_FILE" 2>&1 || true systemctl enable --now postfix >> "$LOG_FILE" 2>&1 || true success "Postfix" # Dovecot groupadd -g 5000 vmail >> "$LOG_FILE" 2>&1 || true useradd -u 5000 -g vmail -d /var/mail/vhosts -s /sbin/nologin vmail >> "$LOG_FILE" 2>&1 || true mkdir -p /var/mail/vhosts && chown -R vmail:vmail /var/mail/vhosts touch /etc/dovecot/users 2>/dev/null || true systemctl enable --now dovecot >> "$LOG_FILE" 2>&1 || true success "Dovecot" # PowerDNS pdns_api_key=$(generate_hex 32) sudo -u postgres psql -c "CREATE DATABASE pdns OWNER ${DB_USER};" >> "$LOG_FILE" 2>&1 || true sudo -u postgres psql -d pdns << 'PDNSQL' >> "$LOG_FILE" 2>&1 || true CREATE TABLE IF NOT EXISTS domains (id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL UNIQUE, master VARCHAR(128), last_check INT, type VARCHAR(8) NOT NULL DEFAULT 'NATIVE', notified_serial BIGINT, account VARCHAR(40)); CREATE TABLE IF NOT EXISTS records (id BIGSERIAL PRIMARY KEY, domain_id INT REFERENCES domains(id) ON DELETE CASCADE, name VARCHAR(255), type VARCHAR(10), content VARCHAR(65535), ttl INT, prio INT, disabled BOOL DEFAULT false, ordername VARCHAR(255), auth BOOL DEFAULT true); CREATE TABLE IF NOT EXISTS supermasters (ip VARCHAR(64) NOT NULL, nameserver VARCHAR(255) NOT NULL, account VARCHAR(40) NOT NULL); CREATE TABLE IF NOT EXISTS comments (id SERIAL PRIMARY KEY, domain_id INT NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(10) NOT NULL, modified_at INT NOT NULL, account VARCHAR(40) NOT NULL, comment TEXT NOT NULL); CREATE TABLE IF NOT EXISTS domainmetadata (id SERIAL PRIMARY KEY, domain_id INT REFERENCES domains(id) ON DELETE CASCADE, kind VARCHAR(32), content TEXT); CREATE TABLE IF NOT EXISTS cryptokeys (id SERIAL PRIMARY KEY, domain_id INT REFERENCES domains(id) ON DELETE CASCADE, flags INT NOT NULL, active BOOL, published BOOL DEFAULT true, content TEXT); CREATE TABLE IF NOT EXISTS tsigkeys (id SERIAL PRIMARY KEY, name VARCHAR(255), algorithm VARCHAR(50), secret VARCHAR(255)); CREATE INDEX IF NOT EXISTS rec_name_index ON records(name); CREATE INDEX IF NOT EXISTS rec_domain_id ON records(domain_id); CREATE INDEX IF NOT EXISTS dom_name_index ON domains(name); PDNSQL sudo -u postgres psql -d pdns -c "GRANT ALL ON ALL TABLES IN SCHEMA public TO ${DB_USER};" >> "$LOG_FILE" 2>&1 || true sudo -u postgres psql -d pdns -c "GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO ${DB_USER};" >> "$LOG_FILE" 2>&1 || true mkdir -p "$CONFIG_DIR" echo "$pdns_api_key" > "${CONFIG_DIR}/pdns_api_key" chmod 600 "${CONFIG_DIR}/pdns_api_key" pdns_conf=$(find /etc/pdns /etc/powerdns -name "pdns.conf" 2>/dev/null | head -1) [ -z "$pdns_conf" ] && mkdir -p /etc/pdns && pdns_conf="/etc/pdns/pdns.conf" cat > "$pdns_conf" << PDNSCFG launch=gpgsql gpgsql-host=/var/run/postgresql gpgsql-dbname=pdns gpgsql-user=${DB_USER} gpgsql-password=${DB_PASS} local-address=0.0.0.0 local-port=53 api=yes api-key=${pdns_api_key} webserver=yes webserver-address=127.0.0.1 webserver-port=8081 webserver-allow-from=127.0.0.1 default-soa-content=ns1.aelynacp.com. admin.${HOSTNAME_INPUT}. 0 10800 3600 604800 3600 PDNSCFG # Free port 53 if systemd-resolved is using it if ss -tlnp 2>/dev/null | grep -q ":53 "; then mkdir -p /etc/systemd/resolved.conf.d echo -e "[Resolve]\nDNSStubListener=no" > /etc/systemd/resolved.conf.d/no-stub.conf systemctl restart systemd-resolved >> "$LOG_FILE" 2>&1 || true sleep 1 fi systemctl enable --now pdns >> "$LOG_FILE" 2>&1 || true success "PowerDNS" # ProFTPD mkdir -p /etc/proftpd && touch /etc/proftpd/ftpd.passwd && chmod 600 /etc/proftpd/ftpd.passwd systemctl enable proftpd >> "$LOG_FILE" 2>&1 || true success "ProFTPD" # Valkey/Redis systemctl enable --now valkey >> "$LOG_FILE" 2>&1 || systemctl enable --now redis >> "$LOG_FILE" 2>&1 || true success "Valkey" # Fail2Ban mkdir -p /etc/fail2ban/jail.d cat > /etc/fail2ban/jail.d/aelynacp.conf << 'F2B' [sshd] enabled = true maxretry = 5 bantime = 3600 F2B systemctl enable --now fail2ban >> "$LOG_FILE" 2>&1 || true success "Fail2Ban" # Firewall systemctl enable --now firewalld >> "$LOG_FILE" 2>&1 || true for port in 80/tcp 443/tcp 21/tcp 25/tcp 110/tcp 143/tcp 465/tcp 587/tcp 993/tcp 995/tcp 53/tcp 53/udp 9443/tcp 9447/tcp 9448/tcp; do firewall-cmd --permanent --add-port="$port" >> "$LOG_FILE" 2>&1 || true done firewall-cmd --reload >> "$LOG_FILE" 2>&1 || true success "Firewall" # ── Deploy AelynaCP ────────────────────────────────────────────────────────── mkdir -p "$INSTALL_DIR" "$BIN_DIR" "$WEB_DIR" "$CONFIG_DIR" "$DATA_DIR" "$LOG_DIR" "$RUN_DIR" "${DATA_DIR}/backups" # Download info "Download AelynaCP v${AELYNACP_VERSION}..." pkg_url="https://get.aelynacp.com/aelynacp-${AELYNACP_VERSION}-linux-x86_64.tar.gz" pkg_file="/tmp/aelynacp-${AELYNACP_VERSION}.tar.gz" rm -f "$pkg_file" curl -L --progress-bar -o "$pkg_file" "$pkg_url" 2>&1 | tail -1 pkg_size=$(stat -c%s "$pkg_file" 2>/dev/null || echo "0") if [ "$pkg_size" -lt 100000 ]; then fatal "Download fallito (${pkg_size} bytes). Verifica che v${AELYNACP_VERSION} esista." fi success "Download ($(( pkg_size / 1048576 ))MB)" tar xzf "$pkg_file" -C "$INSTALL_DIR" >> "$LOG_FILE" 2>&1 chmod +x "${BIN_DIR}/aelynacp-web" "${BIN_DIR}/aelynacp-agent" 2>/dev/null || true success "Estrazione pacchetto" # Generate config JWT_SECRET=$(generate_hex 64) ADMIN_PASS=$(generate_admin_password) cat > "${CONFIG_DIR}/aelynacp.toml" << TOML [server] hostname = "${HOSTNAME_INPUT}" primary_ip = "${PRIMARY_IP}" admin_port = 9443 user_port = 9447 api_port = 8450 nameservers = ["ns1.aelynacp.com", "ns2.aelynacp.com"] webserver = "nginx" max_upload_mb = 200 [database] url = "postgres://${DB_USER}:${DB_PASS}@localhost/${DB_NAME}" max_connections = 20 [redis] url = "redis://127.0.0.1:6379" [license] key = "" server_url = "https://panel.aelynacp.com" check_interval = 43200 [security] jwt_secret = "${JWT_SECRET}" jwt_expiration = 3600 session_expiration = 86400 max_login_attempts = 5 lockout_duration = 900 [paths] config_dir = "${CONFIG_DIR}" data_dir = "${DATA_DIR}" log_dir = "${LOG_DIR}" bin_dir = "${BIN_DIR}" web_dir = "${WEB_DIR}" home_dir = "/home" backup_dir = "${DATA_DIR}/backups" agent_socket = "${RUN_DIR}/agent.sock" [update] channel = "stable" auto_update = true [notifications] enabled = true admin_email = "" [smtp] use_local = true from_address = "noreply@${HOSTNAME_INPUT}" from_name = "AelynaCP" [defaults] php_version = "8.3" shell = "/sbin/nologin" auto_dns_zone = true TOML chmod 600 "${CONFIG_DIR}/aelynacp.toml" echo "$PRIMARY_IP" > "${CONFIG_DIR}/primary_ip" # Verify config was written if [ -f "${CONFIG_DIR}/aelynacp.toml" ]; then log "Config file OK: $(wc -c < ${CONFIG_DIR}/aelynacp.toml) bytes at ${CONFIG_DIR}/aelynacp.toml" success "Configurazione generata" else error "ERRORE: config file non creato!" fi # Run migrations for migration in "${INSTALL_DIR}/migrations"/*.sql; do [ -f "$migration" ] && PGPASSWORD="$DB_PASS" psql -U "$DB_USER" -d "$DB_NAME" -f "$migration" >> "$LOG_FILE" 2>&1 || true done success "Database schema" # Create admin account admin_hash=$(python3 -c "import argon2; print(argon2.PasswordHasher().hash('${ADMIN_PASS}'))" 2>/dev/null || echo "") if [ -n "$admin_hash" ]; then PGPASSWORD="$DB_PASS" psql -U "$DB_USER" -d "$DB_NAME" -c "DELETE FROM admins WHERE username = 'admin';" >> "$LOG_FILE" 2>&1 || true PGPASSWORD="$DB_PASS" psql -U "$DB_USER" -d "$DB_NAME" -c "INSERT INTO admins (username, password_hash, role, email) VALUES ('admin', '${admin_hash}', 'admin', '');" >> "$LOG_FILE" 2>&1 || true fi PGPASSWORD="$DB_PASS" psql -U "$DB_USER" -d "$DB_NAME" -c "INSERT INTO server_settings (key, value) VALUES ('setup_completed', 'false') ON CONFLICT (key) DO UPDATE SET value = 'false';" >> "$LOG_FILE" 2>&1 || true echo "$AELYNACP_VERSION" > "${CONFIG_DIR}/.current_version" success "Account admin" # Nginx panels cat > /etc/nginx/conf.d/aelynacp-panels.conf << NGINX server { listen 9443; server_name _; root ${WEB_DIR}/admin; index index.html; add_header Cache-Control "no-cache" always; location / { try_files \$uri \$uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8450; proxy_http_version 1.1; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } } server { listen 9447; server_name _; client_max_body_size 256m; root ${WEB_DIR}/user; index index.html; location / { try_files \$uri \$uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8450; proxy_http_version 1.1; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } } server { listen 9448; server_name _; root ${WEB_DIR}/webmail; index index.html; location / { try_files \$uri \$uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8450; proxy_http_version 1.1; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } } NGINX nginx -t >> "$LOG_FILE" 2>&1 && systemctl reload nginx >> "$LOG_FILE" 2>&1 || true success "Nginx pannelli" # Systemd services cat > /etc/systemd/system/aelynacp-agent.service << SVC [Unit] Description=AelynaCP Agent After=network.target postgresql.service [Service] Type=simple User=root WorkingDirectory=${INSTALL_DIR} ExecStart=${BIN_DIR}/aelynacp-agent Restart=on-failure RestartSec=5 StandardOutput=append:${LOG_DIR}/agent.log StandardError=append:${LOG_DIR}/agent.log Environment=RUST_LOG=aelynacp_agent=info [Install] WantedBy=multi-user.target SVC cat > /etc/systemd/system/aelynacp-web.service << SVC [Unit] Description=AelynaCP Web After=network.target postgresql.service aelynacp-agent.service [Service] Type=simple User=root WorkingDirectory=${INSTALL_DIR} ExecStartPre=/usr/bin/test -f /etc/aelynacp/aelynacp.toml ExecStart=${BIN_DIR}/aelynacp-web Restart=on-failure RestartSec=10 StandardOutput=append:${LOG_DIR}/web.log StandardError=append:${LOG_DIR}/web.log Environment=RUST_LOG=aelynacp_web=info,tower_http=info [Install] WantedBy=multi-user.target SVC systemctl daemon-reload systemctl enable --now aelynacp-agent >> "$LOG_FILE" 2>&1; sleep 2 systemctl enable --now aelynacp-web >> "$LOG_FILE" 2>&1; sleep 3 systemctl reload nginx >> "$LOG_FILE" 2>&1 || true success "Servizi AelynaCP" # Health check sleep 2 if curl -s --max-time 5 http://localhost:8450/api/v1/health | grep -q '"ok"' 2>/dev/null; then success "Health check OK" else warn "Health check fallito — controlla i log in ${LOG_DIR}/" fi # ── Done ────────────────────────────────────────────────────────────────────── echo "" echo -e " ${MAGENTA}${BOLD}═══════════════════════════════════════════════════${NC}" echo -e " ${GREEN}${BOLD} AelynaCP installato con successo!${NC}" echo -e " ${MAGENTA}${BOLD}═══════════════════════════════════════════════════${NC}" echo "" echo -e " ${WHITE}Pannello Admin:${NC} ${CYAN}http://${PRIMARY_IP}:9443${NC}" echo -e " ${WHITE}Pannello Utente:${NC} ${CYAN}http://${PRIMARY_IP}:9447${NC}" echo -e " ${WHITE}Webmail:${NC} ${CYAN}http://${PRIMARY_IP}:9448${NC}" echo "" echo -e " ${WHITE}Username:${NC} ${GREEN}admin${NC}" echo -e " ${WHITE}Password:${NC} ${GREEN}${ADMIN_PASS}${NC}" echo "" echo -e " ${YELLOW}Completa il setup iniziale accedendo al pannello.${NC}" echo -e " ${GRAY}Log: ${LOG_FILE}${NC}" echo "" echo -e " ${MAGENTA}${BOLD}═══════════════════════════════════════════════════${NC}" echo ""