install.sh
Rama main · réplica de lectura del repositorio original.
#!/bin/bash
#
# Depl0y - Automated VM Deployment Panel Installer
# Complete automated installation - no manual steps required!
# Install: curl -fsSL https://raw.githubusercontent.com/agit8or1/Depl0y/main/install.sh -o install.sh
# less install.sh # read it before running it as root
# sudo bash install.sh
#
set -e
# Installer version for tracking. This is the single source of truth — the
# banner below renders it, so there is no second copy to forget to bump.
INSTALLER_VERSION="latest"
ENV_FILE=/etc/depl0y/config.env
# Release signing key (minisign); same as minisign.pub in the repository.
MINISIGN_PUBKEY="RWSr/WW0BJrhEcOJU3TiPs935jc6Qqy7yjLeuu5l+jaG0jlZ0CaHHRjH"
INSTALLER_BUILD="$(date +%Y%m%d%H%M%S)"
echo "╔══════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ██████╗ ███████╗██████╗ ██╗ ██████╗ ██╗ ██╗ ║"
echo "║ ██╔══██╗██╔════╝██╔══██╗██║ ██╔═████╗╚██╗ ██╔╝ ║"
echo "║ ██║ ██║█████╗ ██████╔╝██║ ██║██╔██║ ╚████╔╝ ║"
echo "║ ██║ ██║██╔══╝ ██╔═══╝ ██║ ████╔╝██║ ╚██╔╝ ║"
echo "║ ██████╔╝███████╗██║ ███████╗╚██████╔╝ ██║ ║"
echo "║ ╚═════╝ ╚══════╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ║"
echo "║ ║"
echo "║ Automated VM Deployment Panel for Proxmox VE ║"
echo "║ https://deploy.agit8or.net ║"
printf "\xe2\x95\x91%*s%*s\xe2\x95\x91\n" $(( (57 + ${#INSTALLER_VERSION} + 8) / 2 )) "Version $INSTALLER_VERSION" $(( (57 - ${#INSTALLER_VERSION} - 8 + 1) / 2 )) ""
echo "║ ║"
echo "╚══════════════════════════════════════════════════════════╝"
echo ""
echo "This installer will:"
echo " ✓ Install all dependencies"
echo " ✓ Set up Depl0y application"
echo " ✓ Configure cloud images (optional)"
echo " ✓ Configure inter-node SSH (optional)"
echo " ✓ No manual steps required!"
echo ""
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "ERROR: Please run as root (use sudo)"
exit 1
fi
echo "🚀 Starting Depl0y installation..."
echo ""
# Check if Depl0y is already installed
UPGRADE_MODE=false
RESET_PASSWORD=false
if [ -d "/opt/depl0y" ] && [ -f "/etc/systemd/system/depl0y-backend.service" ]; then
UPGRADE_MODE=true
echo "📦 Existing Depl0y installation detected"
echo " This will upgrade your installation while preserving your database"
echo ""
# Ask if user wants to reset admin password
echo "⚠️ Do you want to reset the admin password to 'admin'?"
echo " This will reset the 'admin' user credentials to default (admin/admin)"
echo " and disable 2FA for the admin account."
echo ""
echo -n " Type YES (all caps) to reset password, or press Enter to skip: "
# Read from the terminal, not stdin: with `curl ... | sudo bash` stdin is this
# script, and in unattended runs there is nothing to read. No terminal: skip.
if ! read -r RESET_CONFIRM 2>/dev/null < /dev/tty; then
RESET_CONFIRM=""
echo "(no terminal)"
fi
echo ""
if [ "$RESET_CONFIRM" = "YES" ]; then
RESET_PASSWORD=true
echo "✓ Password reset scheduled for after installation"
echo ""
else
echo "✓ Skipping password reset"
echo ""
fi
fi
# Detect OS
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
VER=$VERSION_ID
else
echo "ERROR: Cannot detect OS"
exit 1
fi
echo "✓ Detected OS: $OS $VER"
# Check if Ubuntu/Debian
if [[ "$OS" != "ubuntu" && "$OS" != "debian" ]]; then
echo "ERROR: This installer currently only supports Ubuntu and Debian"
exit 1
fi
# Function to validate dependencies after installation
validate_dependencies() {
echo ""
echo "🔍 Validating installed dependencies..."
local MISSING_DEPS=()
local REQUIRED_PACKAGES=(
"python3"
"python3-pip"
"python3-venv"
"python3-cryptography"
"sudo"
"nginx"
"nodejs"
"npm"
"sqlite3"
"curl"
"wget"
"git"
"sshpass"
"at"
)
for pkg in "${REQUIRED_PACKAGES[@]}"; do
if ! dpkg -l | grep -q "^ii.*$pkg"; then
MISSING_DEPS+=("$pkg")
fi
done
# Also check for critical commands
if ! command -v python3 &> /dev/null; then
MISSING_DEPS+=("python3-binary")
fi
if ! command -v sudo &> /dev/null; then
MISSING_DEPS+=("sudo-binary")
fi
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
echo "❌ ERROR: Missing required dependencies:"
for dep in "${MISSING_DEPS[@]}"; do
echo " • $dep"
done
echo ""
echo "Please install missing dependencies manually or check apt-get logs above."
return 1
fi
echo "✓ All dependencies validated successfully"
return 0
}
# Update system
echo ""
echo "📦 Updating system packages..."
apt-get update -qq
# Install ALL dependencies
echo "📦 Installing dependencies..."
echo " This includes: Python, Node.js, nginx, SQLite, PDF libraries, and more"
apt-get install -y -qq \
sudo \
python3 \
python3-pip \
python3-venv \
python3-dev \
python3-cryptography \
build-essential \
libssl-dev \
nginx \
nodejs \
npm \
sqlite3 \
curl \
wget \
git \
sshpass \
openssh-client \
at \
ca-certificates \
minisign \
gnupg \
lsb-release \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libgdk-pixbuf2.0-0 \
libffi-dev \
shared-mime-info
echo "✓ Dependencies installed"
# Validate all dependencies are present
if ! validate_dependencies; then
echo ""
echo "❌ Installation failed due to missing dependencies"
exit 1
fi
# Create depl0y user
echo ""
echo "👤 Creating depl0y system user..."
if ! id -u depl0y > /dev/null 2>&1; then
useradd -r -m -d /opt/depl0y -s /bin/bash depl0y
echo "✓ User 'depl0y' created"
else
echo "✓ User 'depl0y' already exists"
fi
# If upgrading, stop the backend service and backup encryption keys
if [ "$UPGRADE_MODE" = true ]; then
echo "🔄 Preparing for upgrade..."
# Clear any stale Python cache first
echo "🗑️ Clearing old Python cache..."
find /opt/depl0y/backend -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find /opt/depl0y/backend -type f -name "*.pyc" -delete 2>/dev/null || true
echo "✓ Cache cleared"
if systemctl is-active --quiet depl0y-backend; then
systemctl stop depl0y-backend
echo "✓ Stopped backend service"
fi
# Find the existing keys. /etc/depl0y/config.env is where they belong; older
# installs kept them in the (world-readable) service unit instead.
KEYS_VALID=false
UNIT_FILE=/etc/systemd/system/depl0y-backend.service
EXISTING_SECRET=""
EXISTING_ENCRYPTION=""
# Same precedence as systemd: config.env counts only if the unit loads it (or there
# is no unit), and then it overrides any Environment= line.
if [ -f "$ENV_FILE" ] && { [ ! -f "$UNIT_FILE" ] || grep -q "^EnvironmentFile=-\{0,1\}$ENV_FILE" "$UNIT_FILE"; }; then
EXISTING_SECRET=$(sed -n 's/^SECRET_KEY=["'"'"']\{0,1\}\([^"'"'"']*\).*/\1/p' "$ENV_FILE" | tail -1)
EXISTING_ENCRYPTION=$(sed -n 's/^ENCRYPTION_KEY=["'"'"']\{0,1\}\([^"'"'"']*\).*/\1/p' "$ENV_FILE" | tail -1)
fi
if [ -z "$EXISTING_ENCRYPTION" ] && [ -f "$UNIT_FILE" ]; then
EXISTING_ENCRYPTION=$(sed -n 's/^Environment="\{0,1\}ENCRYPTION_KEY=\([^"]*\)"\{0,1\}$/\1/p' "$UNIT_FILE" | tail -1)
# A SECRET_KEY found only in the unit file was readable by every local user,
# so it is not reused: a new one is generated (everyone signs in again).
EXISTING_SECRET=""
fi
if [ -n "$EXISTING_ENCRYPTION" ]; then
echo "🔍 Found the existing encryption key, validating..."
if python3 -c "import sys; from cryptography.fernet import Fernet; Fernet(sys.argv[1].encode())" "$EXISTING_ENCRYPTION" 2>/dev/null; then
echo "✓ Existing encryption key is valid and will be preserved"
KEYS_VALID=true
else
echo "⚠️ Existing encryption key is INVALID (wrong format)"
echo " Will generate new keys - you'll need to re-enter Proxmox credentials"
fi
else
echo "⚠️ Could not find the existing encryption key"
echo " Will generate new keys"
fi
fi
# Download latest Depl0y
echo ""
echo "⬇️ Downloading the latest Depl0y release from GitHub..."
cd /tmp
rm -f depl0y-latest.tar.gz depl0y-SHA256SUMS depl0y-SHA256SUMS.minisig
# Pin the release we expect *before* downloading, and require the signature to be
# for exactly that tag. Without this, any older signed release served in place of
# "latest" would verify (a downgrade to a version with known bugs).
# Set DEPL0Y_TAG=vX.Y.Z to install a specific release.
EXPECTED_TAG="${DEPL0Y_TAG:-}"
if [ -z "$EXPECTED_TAG" ]; then
EXPECTED_TAG=$(curl -fsSL -H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/agit8or1/Depl0y/releases/latest" \
| sed -n 's/^[[:space:]]*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
fi
if ! [[ "$EXPECTED_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "❌ Could not determine the release to install (got '${EXPECTED_TAG}'); set DEPL0Y_TAG=vX.Y.Z." >&2
exit 1
fi
echo " Release: $EXPECTED_TAG"
RELEASE_BASE="https://github.com/agit8or1/Depl0y/releases/download/$EXPECTED_TAG"
curl -fsSL "$RELEASE_BASE/depl0y.tar.gz" -o depl0y-latest.tar.gz
curl -fsSL "$RELEASE_BASE/SHA256SUMS" -o depl0y-SHA256SUMS
if ! curl -fsSL "$RELEASE_BASE/SHA256SUMS.minisig" -o depl0y-SHA256SUMS.minisig; then
echo "❌ The latest release is not signed (no SHA256SUMS.minisig); aborting." >&2
exit 1
fi
if ! SIG_OUT=$(minisign -V -P "$MINISIGN_PUBKEY" -m depl0y-SHA256SUMS -x depl0y-SHA256SUMS.minisig 2>&1); then
echo "❌ SHA256SUMS is not signed by the Depl0y release key; aborting." >&2
exit 1
fi
# The signed trusted comment names the release ("depl0y vX.Y.Z"); checked against the
# extracted version below.
SIGNED_FOR=$(sed -n 's/^Trusted comment: depl0y v\([0-9]\+\.[0-9]\+\.[0-9]\+\)$/\1/p' <<<"$SIG_OUT")
if [ -z "$SIGNED_FOR" ]; then
echo "❌ Unexpected signature comment on SHA256SUMS; aborting." >&2
exit 1
fi
if [ "v$SIGNED_FOR" != "$EXPECTED_TAG" ]; then
echo "❌ The signature is for depl0y v$SIGNED_FOR, but $EXPECTED_TAG was expected; aborting." >&2
exit 1
fi
echo "✓ Signature verified (depl0y v$SIGNED_FOR)"
EXPECTED_SHA=$(awk '$2 == "depl0y.tar.gz" {print $1}' depl0y-SHA256SUMS)
ACTUAL_SHA=$(sha256sum depl0y-latest.tar.gz | awk '{print $1}')
if [ -z "$EXPECTED_SHA" ] || [ "$EXPECTED_SHA" != "$ACTUAL_SHA" ]; then
echo "❌ Checksum mismatch for the downloaded release; aborting." >&2
exit 1
fi
echo "✓ Checksum verified"
echo "📦 Extracting Depl0y..."
rm -rf /tmp/depl0y-install
mkdir -p /tmp/depl0y-install
cd /tmp/depl0y-install
tar -xzf /tmp/depl0y-latest.tar.gz
DEPL0Y_VERSION=$(grep -o 'return "[0-9]\+\.[0-9]\+\.[0-9]\+"' /tmp/depl0y-install/backend/app/core/config.py | grep -o '[0-9.]\+' | head -1)
if [ "$DEPL0Y_VERSION" != "$SIGNED_FOR" ]; then
echo "❌ The package is version ${DEPL0Y_VERSION:-unknown}, but the signature is for $SIGNED_FOR; aborting." >&2
exit 1
fi
echo "✓ Depl0y ${DEPL0Y_VERSION}"
# Refuse to downgrade an existing install unless asked to.
INSTALLED_VERSION=$(grep -o 'return "[0-9]\+\.[0-9]\+\.[0-9]\+"' /opt/depl0y/backend/app/core/config.py 2>/dev/null | grep -o '[0-9.]\+' | head -1 || true)
if [ -n "$INSTALLED_VERSION" ] && [ "$INSTALLED_VERSION" != "$DEPL0Y_VERSION" ] \
&& [ "$(printf '%s\n%s\n' "$INSTALLED_VERSION" "$DEPL0Y_VERSION" | sort -V | tail -1)" = "$INSTALLED_VERSION" ] \
&& [ "${DEPL0Y_ALLOW_DOWNGRADE:-0}" != "1" ]; then
echo "❌ v$INSTALLED_VERSION is installed; refusing to downgrade to v$DEPL0Y_VERSION (set DEPL0Y_ALLOW_DOWNGRADE=1 to force)." >&2
exit 1
fi
# Install backend
echo ""
echo "🔧 Installing backend..."
mkdir -p /opt/depl0y
chmod 755 /opt/depl0y # Allow nginx to traverse
cp -r backend /opt/depl0y/
chown -R depl0y:depl0y /opt/depl0y/backend
chmod -R 755 /opt/depl0y/backend
# Create Python virtual environment
echo "🐍 Setting up Python environment..."
cd /opt/depl0y/backend
sudo -u depl0y python3 -m venv venv
sudo -u depl0y venv/bin/pip install --upgrade pip -q
sudo -u depl0y venv/bin/pip install -r requirements.txt -q
# Install additional Python packages for features
echo " Installing additional Python packages..."
sudo -u depl0y venv/bin/pip install -q weasyprint markdown requests
echo "✓ Backend installed"
# Install scripts
echo ""
echo "📜 Installing scripts..."
if [ -d "/tmp/depl0y-install/scripts" ]; then
mkdir -p /opt/depl0y/scripts
cp -r /tmp/depl0y-install/scripts/* /opt/depl0y/scripts/
chmod -R 755 /opt/depl0y/scripts
echo "✓ Scripts installed"
else
echo "⚠️ No scripts directory found in package"
fi
# Install frontend
echo ""
echo "🎨 Installing frontend..."
if [ "$UPGRADE_MODE" = true ]; then
# During upgrade, use pre-built frontend from package (much faster!)
echo " Using pre-built frontend from package..."
if [ -d "/tmp/depl0y-install/frontend/dist" ]; then
mkdir -p /opt/depl0y/frontend/dist
chmod 755 /opt/depl0y/frontend
cp -r /tmp/depl0y-install/frontend/dist/* /opt/depl0y/frontend/dist/
chown -R www-data:www-data /opt/depl0y/frontend/dist
chmod -R 755 /opt/depl0y/frontend/dist
echo "✓ Frontend installed (pre-built)"
else
echo "⚠️ Pre-built frontend not found, building from source..."
cd /tmp/depl0y-install/frontend
npm install --silent
npm run build
mkdir -p /opt/depl0y/frontend/dist
chmod 755 /opt/depl0y/frontend
cp -r dist/* /opt/depl0y/frontend/dist/
chown -R www-data:www-data /opt/depl0y/frontend/dist
chmod -R 755 /opt/depl0y/frontend/dist
echo "✓ Frontend installed (built from source)"
fi
else
# Fresh install - try to use pre-built frontend first
if [ -d "/tmp/depl0y-install/frontend/dist" ]; then
echo " Using pre-built frontend from package..."
mkdir -p /opt/depl0y/frontend/dist
chmod 755 /opt/depl0y/frontend
cp -r /tmp/depl0y-install/frontend/dist/* /opt/depl0y/frontend/dist/
chown -R www-data:www-data /opt/depl0y/frontend/dist
chmod -R 755 /opt/depl0y/frontend/dist
echo "✓ Frontend installed (pre-built)"
else
echo " Building frontend from source (this may take 3-5 minutes)..."
cd /tmp/depl0y-install/frontend
npm install
npm run build
mkdir -p /opt/depl0y/frontend/dist
chmod 755 /opt/depl0y/frontend
cp -r dist/* /opt/depl0y/frontend/dist/
chown -R www-data:www-data /opt/depl0y/frontend/dist
chmod -R 755 /opt/depl0y/frontend/dist
echo "✓ Frontend installed (built from source)"
fi
fi
# Create database directory
echo ""
echo "💾 Setting up database..."
mkdir -p /var/lib/depl0y/db
mkdir -p /var/lib/depl0y/cloud-images
mkdir -p /var/lib/depl0y/isos
mkdir -p /var/lib/depl0y/ssh_keys
mkdir -p /var/log/depl0y
chown -R depl0y:depl0y /var/lib/depl0y
chown -R depl0y:depl0y /var/log/depl0y
chmod -R 755 /var/lib/depl0y
echo "✓ Database directories created"
# Copy documentation
echo ""
echo "📚 Installing documentation..."
if [ -d "/tmp/depl0y-install/docs" ]; then
mkdir -p /opt/depl0y/docs
cp -r /tmp/depl0y-install/docs/* /opt/depl0y/docs/
chown -R depl0y:depl0y /opt/depl0y/docs
echo "✓ Documentation installed"
fi
# Generate or reuse encryption keys
echo ""
if [ "$UPGRADE_MODE" = true ] && [ "$KEYS_VALID" = true ]; then
echo "🔐 Reusing existing encryption keys..."
SECRET_KEY="${EXISTING_SECRET:-$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')}"
ENCRYPTION_KEY="$EXISTING_ENCRYPTION"
echo "✓ Existing encryption key preserved"
else
echo "🔐 Generating new encryption keys..."
SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')
ENCRYPTION_KEY=$(python3 -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())')
echo "✓ New encryption keys generated"
if [ "$UPGRADE_MODE" = true ]; then
echo ""
echo "⚠️ IMPORTANT: New encryption keys have been generated"
echo " This means you will need to:"
echo " • Log in again (previous sessions are now invalid)"
echo " • Re-enter all Proxmox host credentials"
echo " • Your database and settings are preserved"
fi
fi
# Secrets live in /etc/depl0y/config.env (depl0y:depl0y 0600), never in the
# world-readable unit file. Other settings already in config.env are kept.
echo ""
echo "🔐 Writing keys to $ENV_FILE..."
install -d -m 0755 -o root -g root /etc/depl0y
ENV_TMP=$(mktemp /etc/depl0y/.config.env.XXXXXX)
if [ -f "$ENV_FILE" ] && [ ! -L "$ENV_FILE" ]; then
grep -vE '^(SECRET_KEY|ENCRYPTION_KEY)=' "$ENV_FILE" > "$ENV_TMP" || true
fi
printf 'SECRET_KEY=%s\nENCRYPTION_KEY=%s\n' "$SECRET_KEY" "$ENCRYPTION_KEY" >> "$ENV_TMP"
chown depl0y:depl0y "$ENV_TMP"
chmod 0600 "$ENV_TMP"
mv -f "$ENV_TMP" "$ENV_FILE"
echo "✓ Keys stored in $ENV_FILE"
# Create systemd service
echo ""
echo "⚙️ Creating systemd service..."
cat > /etc/systemd/system/depl0y-backend.service << SVCEOF
[Unit]
Description=Depl0y Backend API
After=network.target
[Service]
Type=simple
User=depl0y
Group=depl0y
WorkingDirectory=/opt/depl0y/backend
Environment="PATH=/opt/depl0y/backend/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
EnvironmentFile=${ENV_FILE}
ExecStart=/opt/depl0y/backend/venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
SVCEOF
# Clear Python cache to ensure new code is loaded
if [ "$UPGRADE_MODE" = true ]; then
echo "🗑️ Clearing Python cache again (ensuring fresh code)..."
else
echo "🗑️ Clearing Python cache..."
fi
find /opt/depl0y/backend -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find /opt/depl0y/backend -type f -name "*.pyc" -delete 2>/dev/null || true
systemctl daemon-reload
systemctl enable depl0y-backend
# Use restart to ensure service loads new code (important for upgrades)
if [ "$UPGRADE_MODE" = true ]; then
echo "🔄 Restarting backend service with new code..."
systemctl restart depl0y-backend
else
echo "🚀 Starting backend service..."
systemctl start depl0y-backend
fi
echo "✓ Backend service started"
# Configure nginx
echo ""
echo "🌐 Configuring nginx..."
cat > /etc/nginx/sites-available/depl0y << 'NGEOF'
server {
listen 80;
server_name _;
client_max_body_size 10G;
# Frontend
location / {
root /opt/depl0y/frontend/dist;
try_files $uri $uri/ /index.html;
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# Backend API
location /api {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
access_log /var/log/nginx/depl0y_access.log;
error_log /var/log/nginx/depl0y_error.log;
}
NGEOF
ln -sf /etc/nginx/sites-available/depl0y /etc/nginx/sites-enabled/depl0y
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl restart nginx
echo "✓ Nginx configured"
# Sudo rules and the root-owned updater (/usr/local/sbin/depl0y-update)
echo ""
echo "🔐 Configuring permissions..."
bash /tmp/depl0y-install/scripts/install-updater.sh
echo "✓ Permissions configured"
# Wait for backend to start
echo ""
echo "⏳ Waiting for backend to start..."
sleep 5
# Check if backend is running
if systemctl is-active --quiet depl0y-backend; then
echo "✓ Backend is running"
else
echo ""
echo "❌ ERROR: Backend failed to start!"
echo ""
echo "Last 30 lines of backend logs:"
journalctl -u depl0y-backend -n 30 --no-pager
echo ""
echo "Installation failed. Please check the logs above for errors."
exit 1
fi
# Create default admin user
echo ""
echo "👤 Creating default admin user..."
cd /opt/depl0y/backend
if sudo -u depl0y /opt/depl0y/backend/venv/bin/python3 create_admin.py; then
echo "✓ Default credentials: admin / admin"
else
echo "❌ ERROR: Failed to create admin user!"
echo "Check permissions and database connection."
exit 1
fi
# Initialize system settings in database
echo ""
echo "⚙️ Initializing system settings..."
sudo -u depl0y sqlite3 /var/lib/depl0y/db/depl0y.db "CREATE TABLE IF NOT EXISTS system_settings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key VARCHAR(100) UNIQUE NOT NULL,
value TEXT NOT NULL,
description TEXT,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);" 2>/dev/null || true
sudo -u depl0y sqlite3 /var/lib/depl0y/db/depl0y.db "INSERT OR REPLACE INTO system_settings (key, value, description) VALUES
('app_version', '${DEPL0Y_VERSION}', 'Current application version'),
('app_name', 'Depl0y', 'Application name');" 2>/dev/null || true
echo "✓ System settings initialized"
# Optional Proxmox setup
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Optional: Proxmox Integration Setup"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Would you like to configure Proxmox integration now?"
echo "This will:"
echo " • Set up cloud images for fast VM deployment"
echo " • Configure inter-node SSH for multi-node clusters"
echo ""
read -p "Configure Proxmox now? (y/N): " -n 1 -r SETUP_PROXMOX < /dev/tty || SETUP_PROXMOX="N"
echo ""
if [[ $SETUP_PROXMOX =~ ^[Yy]$ ]]; then
echo ""
echo "📋 Proxmox Configuration"
echo ""
# Get Proxmox details
read -p "Enter Proxmox hostname or IP: " PROXMOX_HOST < /dev/tty
read -p "Enter Proxmox root username [root]: " PROXMOX_USER < /dev/tty
PROXMOX_USER=${PROXMOX_USER:-root}
echo ""
echo "⚠️ Note: Password will be used to set up SSH keys only"
read -s -p "Enter Proxmox root password: " PROXMOX_PASSWORD < /dev/tty
echo ""
echo ""
# Setup SSH keys for depl0y user
echo "🔑 Setting up SSH keys..."
if [ ! -f "/opt/depl0y/.ssh/id_rsa" ]; then
sudo -u depl0y mkdir -p /opt/depl0y/.ssh
sudo -u depl0y ssh-keygen -t rsa -b 4096 -f /opt/depl0y/.ssh/id_rsa -N "" -q
echo "✓ SSH keys generated"
else
echo "✓ SSH keys already exist"
fi
# Copy SSH key to Proxmox
echo "📤 Copying SSH key to Proxmox..."
sudo -u depl0y sshpass -p "$PROXMOX_PASSWORD" ssh-copy-id -o StrictHostKeyChecking=no "${PROXMOX_USER}@${PROXMOX_HOST}" 2>/dev/null || {
echo "⚠️ Failed to copy SSH key. You may need to do this manually later."
}
# Test SSH connection
if sudo -u depl0y ssh -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=no "${PROXMOX_USER}@${PROXMOX_HOST}" "echo SSH_OK" 2>/dev/null | grep -q "SSH_OK"; then
echo "✓ SSH connection verified"
# Setup cloud images
echo ""
echo "☁️ Setting up cloud images..."
sudo -u depl0y ssh -o StrictHostKeyChecking=no "${PROXMOX_USER}@${PROXMOX_HOST}" 'bash -s' << 'CLOUDEOF'
# Check if cloud-init is available
if ! which cloud-init >/dev/null 2>&1; then
apt-get update -qq
apt-get install -y -qq cloud-init
fi
# Create cloud-init snippet storage if needed
mkdir -p /var/lib/vz/snippets
chmod 755 /var/lib/vz/snippets
echo "✓ Cloud images configured"
CLOUDEOF
# Setup inter-node SSH for cluster
echo ""
echo "🔗 Setting up inter-node SSH for cluster..."
sudo -u depl0y ssh -o StrictHostKeyChecking=no "${PROXMOX_USER}@${PROXMOX_HOST}" 'bash -s' << 'SSHEOF'
# Get cluster nodes
NODES=$(pvesh get /cluster/status --output-format json 2>/dev/null | grep -o '"name":"[^"]*"' | cut -d'"' -f4 | grep -v "^$" || echo "")
if [ -n "$NODES" ]; then
echo " Found cluster nodes: $NODES"
# Generate SSH key on this node if needed
if [ ! -f ~/.ssh/id_rsa ]; then
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N "" -q
fi
# Copy key to other nodes
for node in $NODES; do
if [ "$node" != "$(hostname)" ]; then
echo " Setting up SSH to $node..."
ssh-copy-id -o StrictHostKeyChecking=no "root@$node" 2>/dev/null || true
fi
done
echo "✓ Inter-node SSH configured"
else
echo " Single node or cluster not configured, skipping"
fi
SSHEOF
echo ""
echo "✓ Proxmox integration complete!"
else
echo "⚠️ SSH connection failed. You can set this up later via Settings in the web interface."
fi
else
echo ""
echo "⏭️ Skipping Proxmox setup. You can configure this later via:"
echo " Settings → Cloud Images"
echo " Settings → Proxmox Cluster SSH"
fi
# Cleanup
echo ""
echo "🧹 Cleaning up..."
cd /
rm -rf /tmp/depl0y-install
rm -f /tmp/depl0y-latest.tar.gz
# Reset admin password if requested
if [ "$RESET_PASSWORD" = true ]; then
echo ""
echo "🔐 Resetting admin password..."
# Hash for 'admin' password using bcrypt
# Generated with: python3 -c "from passlib.hash import bcrypt; print(bcrypt.hash('admin'))"
ADMIN_HASH='$2b$12$LQKvFz5K5w5Y5Y5Y5Y5Y5uKX8yN0gZGZGZGZGZGZGZGZGZGZGZGZG'
# Use Python from venv to properly reset the password
sudo -u depl0y /opt/depl0y/backend/venv/bin/python3 << 'EOF'
import sqlite3
import sys
import bcrypt
try:
# Connect to database
db_path = '/var/lib/depl0y/db/depl0y.db'
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Hash the password using bcrypt (same as security.py)
password = 'admin'
salt = bcrypt.gensalt(rounds=12)
hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
hashed_password = hashed.decode('utf-8')
# Update admin user - reset password and disable 2FA
cursor.execute("""
UPDATE users
SET hashed_password = ?,
totp_enabled = 0,
totp_secret = NULL
WHERE username = 'admin'
""", (hashed_password,))
if cursor.rowcount > 0:
conn.commit()
print("✓ Admin password reset to 'admin'")
print("✓ 2FA disabled for admin account")
else:
print("⚠️ Admin user not found in database")
sys.exit(1)
conn.close()
except Exception as e:
print(f"❌ Failed to reset password: {e}")
sys.exit(1)
EOF
if [ $? -eq 0 ]; then
echo "✓ Password reset complete"
else
echo "❌ Password reset failed - please check the error above"
fi
echo ""
fi
# Final restart for upgrades to ensure new code is loaded
if [ "$UPGRADE_MODE" = true ]; then
echo ""
echo "🔄 Final restart to load new code..."
find /opt/depl0y/backend -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find /opt/depl0y/backend -type f -name "*.pyc" -delete 2>/dev/null || true
systemctl restart depl0y-backend
sleep 3
if systemctl is-active --quiet depl0y-backend; then
echo "✓ Backend restarted successfully"
else
echo "⚠️ Backend restart may have issues, check logs"
fi
fi
# Get IP address
IP=$(hostname -I | awk '{print $1}')
echo ""
if [ "$UPGRADE_MODE" = true ]; then
echo "╔══════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ✅ UPGRADE COMPLETE ║"
echo "║ ║"
echo "╚══════════════════════════════════════════════════════════╝"
echo ""
echo "🎉 Depl0y v${DEPL0Y_VERSION} has been successfully upgraded!"
echo ""
echo "📍 Access Depl0y at:"
echo " http://$IP"
echo ""
if [ "$RESET_PASSWORD" = true ]; then
echo "🔐 Password Reset:"
echo " • Admin password has been reset to: admin"
echo " • 2FA has been disabled for admin account"
echo " • ⚠️ CHANGE PASSWORD IMMEDIATELY!"
echo ""
fi
echo "📚 Note:"
echo " • Your database has been preserved"
echo " • Your encryption keys have been preserved"
echo " • All users and settings retained"
else
echo "╔══════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ✅ INSTALLATION COMPLETE ║"
echo "║ ║"
echo "╚══════════════════════════════════════════════════════════╝"
echo ""
echo "🎉 Depl0y v${DEPL0Y_VERSION} has been successfully installed!"
echo ""
echo "📍 Access Depl0y at:"
echo " http://$IP"
echo ""
echo "👤 Default Credentials:"
echo " Username: admin"
echo " Password: admin"
echo " 🔐 2FA: Disabled (enable in Settings after login)"
echo " ⚠️ CHANGE PASSWORD IMMEDIATELY AFTER FIRST LOGIN!"
echo ""
echo "✨ Features:"
echo " • High Availability wizard"
echo " • Cloud image management"
echo " • Automated VM deployment"
echo ""
echo "📚 Next Steps:"
echo " 1. Access the web interface"
echo " 2. Change the default password"
echo " 3. Add your Proxmox host in Settings (if not done)"
echo " 4. Try the HA Setup Wizard!"
fi
echo ""
echo "📖 Documentation: http://$IP → Documentation"
echo "🆘 Support: Check /opt/depl0y/docs/"
echo ""
echo "Thank you for using Depl0y! 🚀"
echo ""