#!/bin/bash ############################################################################### # Layer 3: Reverse Proxy (Caddy) # # This script deploys Caddy reverse proxy on VPS machines. # Must be run after Layer 1A (VPS setup) is 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_layer_0_complete() { print_header "Verifying Layer 0 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 if [ $errors -gt 0 ]; then print_error "Layer 0 is not complete" exit 1 fi print_success "Layer 0 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_target_hosts() { print_header "Checking Target Hosts" local has_hosts=false print_info "Caddy will be deployed to these hosts:" echo "" for group in vipy watchtower spacey; do local hosts=$(get_hosts_from_inventory "$group") if [ -n "$hosts" ]; then echo " [$group]: $hosts" has_hosts=true else print_warning "[$group]: not configured (skipping)" fi done echo "" if [ "$has_hosts" = false ]; then print_error "No target hosts configured for Caddy" print_info "Caddy needs vipy, watchtower, or spacey in inventory.ini" exit 1 fi print_success "Target hosts verified" } check_ssh_connectivity() { print_header "Testing SSH Connectivity" 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 all_good=true for group in vipy watchtower spacey; do local hosts=$(get_hosts_from_inventory "$group") if [ -n "$hosts" ]; then for host in $hosts; do print_info "Testing SSH to $host as counterweight..." if timeout 10 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$host "echo 'SSH OK'" &>/dev/null; then print_success "SSH to $host: OK" else print_error "Cannot SSH to $host as counterweight" print_warning "Make sure Layer 1A is complete for this host" all_good=false fi done fi done if [ "$all_good" = false ]; then echo "" print_error "SSH connectivity test failed" print_info "Ensure Layer 1A (VPS setup) is complete" echo "" if ! confirm_action "Continue anyway?"; then exit 1 fi fi echo "" print_success "SSH connectivity verified" } ############################################################################### # Caddy Deployment ############################################################################### deploy_caddy() { print_header "Deploying Caddy" cd "$ANSIBLE_DIR" print_info "This will:" echo " • Install Caddy from official repositories" echo " • Configure Caddy service" echo " • Open firewall ports 80/443" echo " • Create sites-enabled directory structure" echo " • Enable automatic HTTPS with Let's Encrypt" echo "" print_info "Target hosts: vipy, watchtower, spacey (if configured)" echo "" print_warning "Important:" echo " • Caddy will start with empty configuration" echo " • Services will add their own config files in later layers" echo " • Ports 80/443 must be available on the VPSs" echo "" if ! confirm_action "Proceed with Caddy deployment?"; then print_warning "Skipped Caddy deployment" return 1 fi print_info "Running: ansible-playbook -i inventory.ini services/caddy_playbook.yml" echo "" if ansible-playbook -i inventory.ini services/caddy_playbook.yml; then print_success "Caddy deployment complete" return 0 else print_error "Caddy deployment failed" return 1 fi } ############################################################################### # Verification Functions ############################################################################### verify_caddy() { print_header "Verifying Caddy Installation" 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}" echo "Checking Caddy on each host..." echo "" for group in vipy watchtower spacey; do local hosts=$(get_hosts_from_inventory "$group") if [ -n "$hosts" ]; then for host in $hosts; do print_info "Checking $host..." # Check if caddy is installed if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$host "command -v caddy" &>/dev/null; then print_success "$host: Caddy installed" else print_error "$host: Caddy not found" continue fi # Check if caddy service is running if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$host "sudo systemctl is-active caddy" &>/dev/null; then print_success "$host: Caddy service running" else print_error "$host: Caddy service not running" fi # Check if sites-enabled directory exists if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$host "test -d /etc/caddy/sites-enabled" &>/dev/null; then print_success "$host: sites-enabled directory exists" else print_warning "$host: sites-enabled directory not found" fi # Check if ports 80/443 are open if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$host "sudo ufw status | grep -E '80|443'" &>/dev/null; then print_success "$host: Firewall ports 80/443 open" else print_warning "$host: Could not verify firewall ports" fi echo "" done fi done } ############################################################################### # Summary Functions ############################################################################### print_summary() { print_header "Layer 3 Setup Complete! 🎉" echo "Summary of what was configured:" echo "" print_success "Caddy installed on VPS hosts" print_success "Caddy service running" print_success "Firewall ports 80/443 opened" print_success "Sites-enabled directory structure created" echo "" print_info "What Caddy provides:" echo " • Automatic HTTPS with Let's Encrypt" echo " • Reverse proxy for all web services" echo " • HTTP/2 support" echo " • Simple per-service configuration" echo "" print_info "How services use Caddy:" echo " • Each service adds a config file to /etc/caddy/sites-enabled/" echo " • Main Caddyfile imports all configs" echo " • Caddy automatically manages SSL certificates" echo "" print_warning "Important Notes:" echo " • Caddy is currently running with default/empty config" echo " • Services deployed in later layers will add their configs" echo " • DNS must point to your VPS IPs for SSL to work" echo "" print_info "Next steps:" echo " 1. Verify Caddy is accessible (optional): curl http://" echo " 2. Proceed to Layer 4: ./scripts/setup_layer_4_monitoring.sh" echo "" } ############################################################################### # Main Execution ############################################################################### main() { clear print_header "🌐 Layer 3: Reverse Proxy (Caddy)" echo "This script will deploy Caddy reverse proxy on your VPS machines." echo "" print_info "Targets: vipy, watchtower, spacey" echo "" if ! confirm_action "Continue with Layer 3 setup?"; then echo "Setup cancelled." exit 0 fi check_layer_0_complete check_target_hosts check_ssh_connectivity # Deploy Caddy if deploy_caddy; then verify_caddy print_summary else print_error "Caddy deployment failed" exit 1 fi } # Run main function main "$@"