personal_infra/scripts/setup_layer_7_services.sh
2025-11-06 23:09:44 +01:00

494 lines
16 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
###############################################################################
# Layer 7: Core Services
#
# This script deploys Vaultwarden, Forgejo, and LNBits on vipy.
# Must be run after Layers 0, 1A, 2, and 3 are complete.
###############################################################################
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Project root directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
ANSIBLE_DIR="$PROJECT_ROOT/ansible"
###############################################################################
# Helper Functions
###############################################################################
print_header() {
echo -e "\n${BLUE}========================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}========================================${NC}\n"
}
print_success() {
echo -e "${GREEN}${NC} $1"
}
print_error() {
echo -e "${RED}${NC} $1"
}
print_warning() {
echo -e "${YELLOW}${NC} $1"
}
print_info() {
echo -e "${BLUE}${NC} $1"
}
confirm_action() {
local prompt="$1"
local response
read -p "$(echo -e ${YELLOW}${prompt}${NC} [y/N]: )" response
[[ "$response" =~ ^[Yy]$ ]]
}
###############################################################################
# Verification Functions
###############################################################################
check_prerequisites() {
print_header "Verifying Prerequisites"
local errors=0
if [ -z "$VIRTUAL_ENV" ]; then
print_error "Virtual environment not activated"
echo "Run: source venv/bin/activate"
((errors++))
else
print_success "Virtual environment activated"
fi
if ! command -v ansible &> /dev/null; then
print_error "Ansible not found"
((errors++))
else
print_success "Ansible found"
fi
if [ ! -f "$ANSIBLE_DIR/inventory.ini" ]; then
print_error "inventory.ini not found"
((errors++))
else
print_success "inventory.ini exists"
fi
# Check if vipy is configured
if ! grep -q "^\[vipy\]" "$ANSIBLE_DIR/inventory.ini"; then
print_error "vipy not configured in inventory.ini"
print_info "Layer 7 requires vipy VPS"
((errors++))
else
print_success "vipy configured in inventory"
fi
if [ $errors -gt 0 ]; then
print_error "Prerequisites not met"
exit 1
fi
print_success "Prerequisites verified"
}
get_hosts_from_inventory() {
local group="$1"
cd "$ANSIBLE_DIR"
ansible-inventory -i inventory.ini --list | \
python3 -c "import sys, json; data=json.load(sys.stdin); print(' '.join(data.get('$group', {}).get('hosts', [])))" 2>/dev/null || echo ""
}
check_dns_configuration() {
print_header "Validating DNS Configuration"
cd "$ANSIBLE_DIR"
# Get vipy IP
local vipy_ip=$(ansible-inventory -i inventory.ini --list | python3 -c "import sys, json; data=json.load(sys.stdin); hosts=data.get('vipy', {}).get('hosts', []); print(hosts[0] if hosts else '')" 2>/dev/null)
if [ -z "$vipy_ip" ]; then
print_error "Could not determine vipy IP from inventory"
return 1
fi
print_info "Vipy IP: $vipy_ip"
echo ""
# Get domain from infra_vars.yml
local root_domain=$(grep "^root_domain:" "$ANSIBLE_DIR/infra_vars.yml" | awk '{print $2}' 2>/dev/null)
if [ -z "$root_domain" ]; then
print_error "Could not determine root_domain from infra_vars.yml"
return 1
fi
# Get subdomains from centralized config
local vw_subdomain="vault"
local fg_subdomain="git"
local ln_subdomain="lnbits"
if [ -f "$ANSIBLE_DIR/services_config.yml" ]; then
vw_subdomain=$(grep "^ vaultwarden:" "$ANSIBLE_DIR/services_config.yml" | awk '{print $2}' 2>/dev/null || echo "vault")
fg_subdomain=$(grep "^ forgejo:" "$ANSIBLE_DIR/services_config.yml" | awk '{print $2}' 2>/dev/null || echo "git")
ln_subdomain=$(grep "^ lnbits:" "$ANSIBLE_DIR/services_config.yml" | awk '{print $2}' 2>/dev/null || echo "lnbits")
fi
print_info "Checking DNS records..."
echo ""
local dns_ok=true
if command -v dig &> /dev/null; then
# Check each subdomain
for service in "vaultwarden:$vw_subdomain" "forgejo:$fg_subdomain" "lnbits:$ln_subdomain"; do
local name=$(echo "$service" | cut -d: -f1)
local subdomain=$(echo "$service" | cut -d: -f2)
local fqdn="${subdomain}.${root_domain}"
print_info "Checking $fqdn..."
local resolved=$(dig +short "$fqdn" | head -n1)
if [ "$resolved" = "$vipy_ip" ]; then
print_success "$fqdn$resolved"
elif [ -n "$resolved" ]; then
print_error "$fqdn$resolved (expected $vipy_ip)"
dns_ok=false
else
print_error "$fqdn does not resolve"
dns_ok=false
fi
done
else
print_warning "dig command not found, skipping DNS validation"
print_info "Install dnsutils/bind-tools to enable DNS validation"
return 1
fi
echo ""
if [ "$dns_ok" = false ]; then
print_error "DNS validation failed"
print_info "Please configure DNS records for all services"
echo ""
print_warning "DNS changes can take time to propagate"
echo ""
if ! confirm_action "Continue anyway? (SSL certificates will fail without proper DNS)"; then
exit 1
fi
else
print_success "DNS validation passed"
fi
}
###############################################################################
# Service Deployment
###############################################################################
deploy_vaultwarden() {
print_header "Deploying Vaultwarden (Password Manager)"
cd "$ANSIBLE_DIR"
print_info "This will:"
echo " • Deploy Vaultwarden via Docker"
echo " • Configure Caddy reverse proxy"
echo " • Set up fail2ban protection"
echo " • Enable sign-ups (disable after first user)"
echo ""
if ! confirm_action "Proceed with Vaultwarden deployment?"; then
print_warning "Skipped Vaultwarden deployment"
return 0
fi
print_info "Running: ansible-playbook -i inventory.ini services/vaultwarden/deploy_vaultwarden_playbook.yml"
echo ""
if ansible-playbook -i inventory.ini services/vaultwarden/deploy_vaultwarden_playbook.yml; then
print_success "Vaultwarden deployed"
echo ""
print_warning "POST-DEPLOYMENT:"
echo " 1. Visit your Vaultwarden subdomain"
echo " 2. Create your first user account"
echo " 3. Run: ansible-playbook -i inventory.ini services/vaultwarden/disable_vaultwarden_sign_ups_playbook.yml"
return 0
else
print_error "Vaultwarden deployment failed"
return 0
fi
}
deploy_forgejo() {
print_header "Deploying Forgejo (Git Server)"
cd "$ANSIBLE_DIR"
print_info "This will:"
echo " • Install Forgejo binary"
echo " • Create git user and directories"
echo " • Configure Caddy reverse proxy"
echo " • Enable SSH cloning on port 22"
echo ""
if ! confirm_action "Proceed with Forgejo deployment?"; then
print_warning "Skipped Forgejo deployment"
return 0
fi
print_info "Running: ansible-playbook -i inventory.ini services/forgejo/deploy_forgejo_playbook.yml"
echo ""
if ansible-playbook -i inventory.ini services/forgejo/deploy_forgejo_playbook.yml; then
print_success "Forgejo deployed"
echo ""
print_warning "POST-DEPLOYMENT:"
echo " 1. Visit your Forgejo subdomain"
echo " 2. Create admin account on first visit"
echo " 3. Add your SSH key for git cloning"
return 0
else
print_error "Forgejo deployment failed"
return 0
fi
}
deploy_lnbits() {
print_header "Deploying LNBits (Lightning Wallet)"
cd "$ANSIBLE_DIR"
print_info "This will:"
echo " • Install system dependencies and uv (Python 3.12 tooling)"
echo " • Clone LNBits repository (version v1.3.1)"
echo " • Sync dependencies with uv targeting Python 3.12"
echo " • Configure with FakeWallet (testing)"
echo " • Create systemd service"
echo " • Configure Caddy reverse proxy"
echo ""
if ! confirm_action "Proceed with LNBits deployment?"; then
print_warning "Skipped LNBits deployment"
return 0
fi
print_info "Running: ansible-playbook -i inventory.ini services/lnbits/deploy_lnbits_playbook.yml"
echo ""
if ansible-playbook -i inventory.ini services/lnbits/deploy_lnbits_playbook.yml; then
print_success "LNBits deployed"
echo ""
print_warning "POST-DEPLOYMENT:"
echo " 1. Visit your LNBits subdomain"
echo " 2. Create superuser on first visit"
echo " 3. Configure real Lightning backend (FakeWallet is for testing only)"
echo " 4. Disable new user registration"
return 0
else
print_error "LNBits deployment failed"
return 0
fi
}
###############################################################################
# Backup Configuration
###############################################################################
setup_backups() {
print_header "Setting Up Backups (Optional)"
cd "$ANSIBLE_DIR"
print_info "Configure automated backups to lapy"
echo ""
# Vaultwarden backup
if confirm_action "Set up Vaultwarden backup to lapy?"; then
print_info "Running: ansible-playbook -i inventory.ini services/vaultwarden/setup_backup_vaultwarden_to_lapy.yml"
if ansible-playbook -i inventory.ini services/vaultwarden/setup_backup_vaultwarden_to_lapy.yml; then
print_success "Vaultwarden backup configured"
else
print_error "Vaultwarden backup setup failed"
fi
echo ""
fi
# LNBits backup
if confirm_action "Set up LNBits backup to lapy (GPG encrypted)?"; then
print_info "Running: ansible-playbook -i inventory.ini services/lnbits/setup_backup_lnbits_to_lapy.yml"
if ansible-playbook -i inventory.ini services/lnbits/setup_backup_lnbits_to_lapy.yml; then
print_success "LNBits backup configured"
else
print_error "LNBits backup setup failed"
fi
echo ""
fi
print_warning "Forgejo backups are not automated - set up manually if needed"
}
###############################################################################
# Verification
###############################################################################
verify_services() {
print_header "Verifying Service Deployments"
cd "$ANSIBLE_DIR"
local ssh_key=$(grep "ansible_ssh_private_key_file" "$ANSIBLE_DIR/inventory.ini" | head -n1 | sed 's/.*ansible_ssh_private_key_file=\([^ ]*\).*/\1/')
ssh_key="${ssh_key/#\~/$HOME}"
local vipy_host=$(get_hosts_from_inventory "vipy")
if [ -z "$vipy_host" ]; then
print_error "Could not determine vipy host"
return
fi
print_info "Checking services on vipy ($vipy_host)..."
echo ""
# Check Vaultwarden
if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$vipy_host "docker ps | grep vaultwarden" &>/dev/null; then
print_success "Vaultwarden container running"
else
print_warning "Vaultwarden container not running (may not be deployed)"
fi
# Check Forgejo
if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$vipy_host "systemctl is-active forgejo" &>/dev/null; then
print_success "Forgejo service running"
else
print_warning "Forgejo service not running (may not be deployed)"
fi
# Check LNBits
if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$vipy_host "systemctl is-active lnbits" &>/dev/null; then
print_success "LNBits service running"
else
print_warning "LNBits service not running (may not be deployed)"
fi
# Check Caddy configs
if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$vipy_host "ls /etc/caddy/sites-enabled/*.conf 2>/dev/null" &>/dev/null; then
print_success "Caddy configs exist"
local configs=$(timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$vipy_host "ls /etc/caddy/sites-enabled/*.conf 2>/dev/null" | xargs -n1 basename)
print_info "Configured services:"
echo "$configs" | sed 's/^/ /'
else
print_warning "No Caddy configs found"
fi
echo ""
}
###############################################################################
# Summary
###############################################################################
print_summary() {
print_header "Layer 7 Setup Complete! 🎉"
echo "Summary of what was deployed:"
echo ""
print_success "Core services deployed on vipy"
echo ""
print_warning "CRITICAL POST-DEPLOYMENT STEPS:"
echo ""
echo "For each service you deployed, you MUST:"
echo ""
echo "1. Vaultwarden (if deployed):"
echo " • Visit web UI and create first user"
echo " • Disable sign-ups: ansible-playbook -i inventory.ini services/vaultwarden/disable_vaultwarden_sign_ups_playbook.yml"
echo " • Optional: Set up backup"
echo ""
echo "2. Forgejo (if deployed):"
echo " • Visit web UI and create admin account"
echo " • Add your SSH public key for git operations"
echo " • Test cloning: git clone git@<forgejo_subdomain>.<yourdomain>:username/repo.git"
echo ""
echo "3. LNBits (if deployed):"
echo " • Visit web UI and create superuser"
echo " • Configure real Lightning backend (currently FakeWallet)"
echo " • Disable new user registration"
echo " • Optional: Set up encrypted backup"
echo ""
print_info "Services are now accessible:"
echo " • Vaultwarden: https://<vaultwarden_subdomain>.<yourdomain>"
echo " • Forgejo: https://<forgejo_subdomain>.<yourdomain>"
echo " • LNBits: https://<lnbits_subdomain>.<yourdomain>"
echo ""
print_success "Uptime Kuma monitors automatically created:"
echo " • Check Uptime Kuma web UI"
echo " • Look in 'services' monitor group"
echo " • Monitors for Vaultwarden, Forgejo, LNBits should appear"
echo ""
print_info "Next steps:"
echo " 1. Complete post-deployment steps above"
echo " 2. Test each service"
echo " 3. Check Uptime Kuma monitors are working"
echo " 4. Proceed to Layer 8: ./scripts/setup_layer_8_secondary_services.sh"
echo ""
}
###############################################################################
# Main Execution
###############################################################################
main() {
clear
print_header "🚀 Layer 7: Core Services"
echo "This script will deploy core services on vipy:"
echo " • Vaultwarden (password manager)"
echo " • Forgejo (git server)"
echo " • LNBits (Lightning wallet)"
echo ""
if ! confirm_action "Continue with Layer 7 setup?"; then
echo "Setup cancelled."
exit 0
fi
check_prerequisites
check_dns_configuration
# Deploy services
deploy_vaultwarden
echo ""
deploy_forgejo
echo ""
deploy_lnbits
echo ""
verify_services
echo ""
setup_backups
print_summary
}
# Run main function
main "$@"