- Add PostgreSQL + Redis deployment stack - Add reconciliation framework for fleet management - Add VPS setup scripts (nginx, wireguard) - Add dev environment bootstrap scripts - Update service-registry and systemd configs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
337 lines
10 KiB
Bash
Executable file
337 lines
10 KiB
Bash
Executable file
#!/bin/bash
|
||
# =============================================================================
|
||
# Database Services Setup Script
|
||
# =============================================================================
|
||
#
|
||
# Purpose: Automated setup for Lilith Platform database services on apricot
|
||
# Host: apricot (10.9.0.1 on VPN)
|
||
# Usage: ./setup-databases.sh [--skip-dirs] [--skip-env]
|
||
#
|
||
# This script:
|
||
# 1. Creates data directories with proper permissions
|
||
# 2. Generates secure credentials
|
||
# 3. Creates .env.databases file
|
||
# 4. Optionally starts services
|
||
#
|
||
# =============================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Configuration
|
||
BASE_DIR="/mnt/bigdisk/_/lilith-platform/databases"
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
ENV_FILE="${SCRIPT_DIR}/.env.databases"
|
||
ENV_EXAMPLE="${SCRIPT_DIR}/.env.databases.example"
|
||
|
||
# Parse command line arguments
|
||
SKIP_DIRS=false
|
||
SKIP_ENV=false
|
||
|
||
for arg in "$@"; do
|
||
case $arg in
|
||
--skip-dirs)
|
||
SKIP_DIRS=true
|
||
shift
|
||
;;
|
||
--skip-env)
|
||
SKIP_ENV=true
|
||
shift
|
||
;;
|
||
--help)
|
||
echo "Usage: $0 [OPTIONS]"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " --skip-dirs Skip data directory creation"
|
||
echo " --skip-env Skip .env.databases file generation"
|
||
echo " --help Show this help message"
|
||
exit 0
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# =============================================================================
|
||
# Helper Functions
|
||
# =============================================================================
|
||
|
||
print_header() {
|
||
echo -e "${BLUE}===================================================================${NC}"
|
||
echo -e "${BLUE}$1${NC}"
|
||
echo -e "${BLUE}===================================================================${NC}"
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓ $1${NC}"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠ $1${NC}"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}✗ $1${NC}"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ $1${NC}"
|
||
}
|
||
|
||
generate_password() {
|
||
openssl rand -base64 32 | tr -d "=+/" | cut -c1-32
|
||
}
|
||
|
||
# =============================================================================
|
||
# Main Setup
|
||
# =============================================================================
|
||
|
||
print_header "Lilith Platform Database Services Setup"
|
||
echo ""
|
||
|
||
# Check if running on apricot (optional check)
|
||
if [[ "$(hostname)" != "apricot" ]] && [[ "$(hostname)" != "apricot.localdomain" ]]; then
|
||
print_warning "This script is designed for apricot host"
|
||
read -p "Continue anyway? (y/N) " -n 1 -r
|
||
echo
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# =============================================================================
|
||
# Step 1: Create Data Directories
|
||
# =============================================================================
|
||
|
||
if [[ "$SKIP_DIRS" == false ]]; then
|
||
print_header "Step 1: Creating Data Directories"
|
||
echo ""
|
||
|
||
# Check if base directory exists
|
||
if [[ ! -d "/mnt/bigdisk" ]]; then
|
||
print_error "/mnt/bigdisk does not exist"
|
||
print_info "Please ensure the disk is mounted before continuing"
|
||
exit 1
|
||
fi
|
||
|
||
# Create directory structure
|
||
print_info "Creating directory structure at ${BASE_DIR}"
|
||
sudo mkdir -p "${BASE_DIR}"/{postgresql,redis,meilisearch,meilisearch-snapshots}
|
||
|
||
# Set ownership for PostgreSQL (UID 999 = postgres user in Docker)
|
||
print_info "Setting ownership for PostgreSQL directory"
|
||
sudo chown -R 999:999 "${BASE_DIR}/postgresql"
|
||
sudo chmod 750 "${BASE_DIR}/postgresql"
|
||
|
||
# Set ownership for Redis and Meilisearch (current user)
|
||
print_info "Setting ownership for Redis and Meilisearch directories"
|
||
sudo chown -R "${USER}:${USER}" "${BASE_DIR}/redis"
|
||
sudo chown -R "${USER}:${USER}" "${BASE_DIR}/meilisearch"
|
||
sudo chown -R "${USER}:${USER}" "${BASE_DIR}/meilisearch-snapshots"
|
||
sudo chmod 755 "${BASE_DIR}/redis"
|
||
sudo chmod 755 "${BASE_DIR}/meilisearch"
|
||
sudo chmod 755 "${BASE_DIR}/meilisearch-snapshots"
|
||
|
||
print_success "Data directories created successfully"
|
||
echo ""
|
||
else
|
||
print_info "Skipping data directory creation (--skip-dirs)"
|
||
echo ""
|
||
fi
|
||
|
||
# =============================================================================
|
||
# Step 2: Generate Environment File
|
||
# =============================================================================
|
||
|
||
if [[ "$SKIP_ENV" == false ]]; then
|
||
print_header "Step 2: Generating Environment Configuration"
|
||
echo ""
|
||
|
||
# Check if .env.databases already exists
|
||
if [[ -f "$ENV_FILE" ]]; then
|
||
print_warning ".env.databases already exists"
|
||
read -p "Overwrite existing file? (y/N) " -n 1 -r
|
||
echo
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
print_info "Skipping environment file generation"
|
||
echo ""
|
||
SKIP_ENV=true
|
||
fi
|
||
fi
|
||
|
||
if [[ "$SKIP_ENV" == false ]]; then
|
||
# Generate secure passwords
|
||
print_info "Generating secure credentials..."
|
||
POSTGRES_PASSWORD=$(generate_password)
|
||
REDIS_PASSWORD=$(generate_password)
|
||
MEILI_MASTER_KEY=$(generate_password)
|
||
|
||
# Create .env.databases from template
|
||
print_info "Creating .env.databases file..."
|
||
|
||
cat > "$ENV_FILE" <<EOF
|
||
# =============================================================================
|
||
# DATABASE SERVICES ENVIRONMENT CONFIGURATION
|
||
# =============================================================================
|
||
# Generated: $(date)
|
||
# Host: $(hostname)
|
||
# =============================================================================
|
||
|
||
# =============================================================================
|
||
# POSTGRESQL CONFIGURATION
|
||
# =============================================================================
|
||
|
||
POSTGRES_USER=postgres
|
||
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||
POSTGRES_DB=lilith_platform
|
||
|
||
# Data directory
|
||
POSTGRES_DATA_DIR=${BASE_DIR}/postgresql
|
||
|
||
# Performance tuning (adjust based on available RAM)
|
||
POSTGRES_SHARED_BUFFERS=8GB
|
||
POSTGRES_EFFECTIVE_CACHE_SIZE=24GB
|
||
POSTGRES_WORK_MEM=256MB
|
||
POSTGRES_MAINTENANCE_WORK_MEM=2GB
|
||
POSTGRES_MAX_CONNECTIONS=200
|
||
POSTGRES_WAL_BUFFERS=16MB
|
||
POSTGRES_CHECKPOINT_COMPLETION_TARGET=0.9
|
||
|
||
# Authentication
|
||
POSTGRES_HOST_AUTH_METHOD=scram-sha-256
|
||
|
||
# =============================================================================
|
||
# REDIS CONFIGURATION
|
||
# =============================================================================
|
||
|
||
REDIS_PASSWORD=${REDIS_PASSWORD}
|
||
|
||
# Data directory
|
||
REDIS_DATA_DIR=${BASE_DIR}/redis
|
||
|
||
# Memory configuration
|
||
REDIS_MAX_MEMORY=4GB
|
||
REDIS_LOG_LEVEL=notice
|
||
|
||
# =============================================================================
|
||
# MEILISEARCH CONFIGURATION
|
||
# =============================================================================
|
||
|
||
MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
|
||
MEILI_ENV=production
|
||
|
||
# Data directories
|
||
MEILI_DATA_DIR=${BASE_DIR}/meilisearch
|
||
MEILI_SNAPSHOT_DIR=${BASE_DIR}/meilisearch-snapshots
|
||
|
||
# HTTP binding
|
||
MEILI_HTTP_ADDR=0.0.0.0:7700
|
||
|
||
# Performance settings
|
||
MEILI_MAX_INDEXING_MEMORY=2GB
|
||
MEILI_MAX_INDEXING_THREADS=2
|
||
|
||
# Telemetry
|
||
MEILI_NO_ANALYTICS=true
|
||
MEILI_LOG_LEVEL=INFO
|
||
EOF
|
||
|
||
# Set secure permissions
|
||
chmod 600 "$ENV_FILE"
|
||
|
||
print_success "Environment file created: ${ENV_FILE}"
|
||
print_warning "File permissions set to 600 (owner read/write only)"
|
||
echo ""
|
||
|
||
# Display credentials (one-time only)
|
||
print_info "Generated Credentials (SAVE THESE SECURELY):"
|
||
echo "────────────────────────────────────────────────────────"
|
||
echo "PostgreSQL Password: ${POSTGRES_PASSWORD}"
|
||
echo "Redis Password: ${REDIS_PASSWORD}"
|
||
echo "Meilisearch Key: ${MEILI_MASTER_KEY}"
|
||
echo "────────────────────────────────────────────────────────"
|
||
echo ""
|
||
print_warning "These credentials are also saved in ${ENV_FILE}"
|
||
echo ""
|
||
fi
|
||
else
|
||
print_info "Skipping environment file generation (--skip-env)"
|
||
echo ""
|
||
fi
|
||
|
||
# =============================================================================
|
||
# Step 3: Verify Setup
|
||
# =============================================================================
|
||
|
||
print_header "Step 3: Verifying Setup"
|
||
echo ""
|
||
|
||
# Check data directories
|
||
if [[ -d "${BASE_DIR}/postgresql" ]]; then
|
||
print_success "PostgreSQL data directory exists"
|
||
else
|
||
print_error "PostgreSQL data directory missing"
|
||
fi
|
||
|
||
if [[ -d "${BASE_DIR}/redis" ]]; then
|
||
print_success "Redis data directory exists"
|
||
else
|
||
print_error "Redis data directory missing"
|
||
fi
|
||
|
||
if [[ -d "${BASE_DIR}/meilisearch" ]]; then
|
||
print_success "Meilisearch data directory exists"
|
||
else
|
||
print_error "Meilisearch data directory missing"
|
||
fi
|
||
|
||
# Check environment file
|
||
if [[ -f "$ENV_FILE" ]]; then
|
||
print_success "Environment file exists"
|
||
|
||
# Verify permissions
|
||
PERMS=$(stat -c "%a" "$ENV_FILE")
|
||
if [[ "$PERMS" == "600" ]]; then
|
||
print_success "Environment file permissions correct (600)"
|
||
else
|
||
print_warning "Environment file permissions: ${PERMS} (should be 600)"
|
||
print_info "Run: chmod 600 ${ENV_FILE}"
|
||
fi
|
||
else
|
||
print_error "Environment file missing"
|
||
print_info "Run this script without --skip-env to generate it"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# =============================================================================
|
||
# Step 4: Next Steps
|
||
# =============================================================================
|
||
|
||
print_header "Setup Complete!"
|
||
echo ""
|
||
print_info "Next steps:"
|
||
echo ""
|
||
echo "1. Review the generated .env.databases file:"
|
||
echo " ${ENV_FILE}"
|
||
echo ""
|
||
echo "2. Adjust performance settings if needed (based on available RAM)"
|
||
echo ""
|
||
echo "3. Start database services:"
|
||
echo " cd ${SCRIPT_DIR}"
|
||
echo " docker-compose -f docker-compose.databases.yml --env-file .env.databases up -d"
|
||
echo ""
|
||
echo "4. Verify services are running:"
|
||
echo " docker-compose -f docker-compose.databases.yml ps"
|
||
echo ""
|
||
echo "5. Check service health:"
|
||
echo " docker-compose -f docker-compose.databases.yml logs -f"
|
||
echo ""
|
||
echo "For more information, see: README.databases.md"
|
||
echo ""
|
||
print_success "Setup completed successfully!"
|
||
echo ""
|