mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-06-03 20:12:58 +00:00
small fix, don't worry about it
This commit is contained in:
Executable
+600
@@ -0,0 +1,600 @@
|
||||
#!/bin/bash
|
||||
|
||||
# One-Click Docker Template Auto-Deployment
|
||||
# Fully automated deployment with no user interaction required
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
PURPLE='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
TEMPLATE_DIR="$(dirname "$0")/../templates"
|
||||
DEPLOYMENT_BASE_DIR="$(dirname "$0")/../deployments"
|
||||
LOG_FILE="/tmp/docker-auto-deploy.log"
|
||||
|
||||
# Auto-configuration
|
||||
AUTO_GENERATE_SECRETS=true
|
||||
AUTO_CREATE_DIRECTORIES=true
|
||||
AUTO_PULL_IMAGES=true
|
||||
AUTO_START_SERVICES=true
|
||||
AUTO_OPEN_BROWSER=false
|
||||
|
||||
# Template configurations with auto-generated defaults
|
||||
declare -A TEMPLATE_CONFIGS=(
|
||||
["umami"]="port:3000,database:postgres,secrets:APP_SECRET"
|
||||
["plex"]="port:32400,database:none,secrets:none"
|
||||
["immich"]="port:2283,database:postgres,secrets:DATABASE_PASSWORD"
|
||||
["n8n"]="port:5678,database:postgres,secrets:N8N_ENCRYPTION_KEY"
|
||||
["supabase"]="port:8000,database:postgres,secrets:JWT_SECRET"
|
||||
["home-assistant"]="port:8123,database:postgres,secrets:none"
|
||||
["uptime-kuma"]="port:3001,database:none,secrets:none"
|
||||
["grafana"]="port:3000,database:postgres,secrets:GF_SECURITY_ADMIN_PASSWORD"
|
||||
["traefik"]="port:80,database:none,secrets:none"
|
||||
["memos"]="port:5230,database:sqlite,secrets:none"
|
||||
["meilisearch"]="port:7700,database:none,secrets:MEILI_MASTER_KEY"
|
||||
["vaultwarden"]="port:8080,database:postgres,secrets:ADMIN_TOKEN"
|
||||
["pihole"]="port:80,database:none,secrets:FTLCONF_webserver_api_password"
|
||||
["appwrite"]="port:80,database:postgres,secrets:_APP_OPENSSL_KEY_V1"
|
||||
["gitea"]="port:3000,database:postgres,secrets:SECRET_KEY"
|
||||
["mastodon"]="port:3000,database:postgres,secrets:SECRET_KEY_BASE"
|
||||
["jellyfin"]="port:8096,database:none,secrets:none"
|
||||
["nextcloud"]="port:8080,database:postgres,secrets:NEXTCLOUD_ADMIN_PASSWORD"
|
||||
["glance"]="port:8080,database:none,secrets:none"
|
||||
["cloudreve"]="port:5212,database:postgres,secrets:CR_CONF_Database_Password"
|
||||
)
|
||||
|
||||
print_header() {
|
||||
echo -e "${PURPLE}========================================${NC}"
|
||||
echo -e "${PURPLE}$1${NC}"
|
||||
echo -e "${PURPLE}========================================${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
print_step() {
|
||||
echo -e "${CYAN}🔄 $1${NC}"
|
||||
}
|
||||
|
||||
log_message() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
check_dependencies() {
|
||||
print_step "Checking dependencies..."
|
||||
log_message "Starting dependency check"
|
||||
|
||||
# Check Docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
print_error "Docker is not installed"
|
||||
print_info "Installing Docker automatically..."
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
sudo usermod -aG docker $USER
|
||||
print_success "Docker installed"
|
||||
else
|
||||
print_success "Docker is installed"
|
||||
fi
|
||||
|
||||
# Check Docker Compose
|
||||
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
|
||||
print_error "Docker Compose is not installed"
|
||||
print_info "Installing Docker Compose automatically..."
|
||||
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
print_success "Docker Compose installed"
|
||||
else
|
||||
print_success "Docker Compose is installed"
|
||||
fi
|
||||
|
||||
log_message "Dependency check completed"
|
||||
}
|
||||
|
||||
generate_secret() {
|
||||
local length=${1:-32}
|
||||
openssl rand -base64 $length | tr -d "=+/" | cut -c1-$length
|
||||
}
|
||||
|
||||
generate_password() {
|
||||
local length=${1:-16}
|
||||
openssl rand -base64 $length | tr -d "=+/" | cut -c1-$length
|
||||
}
|
||||
|
||||
auto_generate_secrets() {
|
||||
local template="$1"
|
||||
local env_file="$2"
|
||||
|
||||
print_step "Auto-generating secrets for $template..."
|
||||
|
||||
local config="${TEMPLATE_CONFIGS[$template]}"
|
||||
local secrets=$(echo "$config" | cut -d',' -f3 | cut -d':' -f2)
|
||||
|
||||
if [[ "$secrets" == "none" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Read existing .env file
|
||||
local temp_env=$(mktemp)
|
||||
cp "$env_file" "$temp_env"
|
||||
|
||||
# Generate secrets for each required variable
|
||||
case "$template" in
|
||||
"umami")
|
||||
sed -i "s/APP_SECRET=change_me/APP_SECRET=$(generate_secret)/g" "$temp_env"
|
||||
;;
|
||||
"immich")
|
||||
sed -i "s/DATABASE_PASSWORD=change_me/DATABASE_PASSWORD=$(generate_password)/g" "$temp_env"
|
||||
;;
|
||||
"n8n")
|
||||
sed -i "s/N8N_ENCRYPTION_KEY=change_me/N8N_ENCRYPTION_KEY=$(generate_secret)/g" "$temp_env"
|
||||
;;
|
||||
"supabase")
|
||||
sed -i "s/JWT_SECRET=change_me/JWT_SECRET=$(generate_secret)/g" "$temp_env"
|
||||
;;
|
||||
"grafana")
|
||||
sed -i "s/GF_SECURITY_ADMIN_PASSWORD=change_me/GF_SECURITY_ADMIN_PASSWORD=$(generate_password)/g" "$temp_env"
|
||||
;;
|
||||
"vaultwarden")
|
||||
sed -i "s/ADMIN_TOKEN=change_me/ADMIN_TOKEN=$(generate_secret)/g" "$temp_env"
|
||||
;;
|
||||
"pihole")
|
||||
sed -i "s/FTLCONF_webserver_api_password=change_me/FTLCONF_webserver_api_password=$(generate_password)/g" "$temp_env"
|
||||
;;
|
||||
"appwrite")
|
||||
sed -i "s/_APP_OPENSSL_KEY_V1=change_me/_APP_OPENSSL_KEY_V1=$(generate_secret)/g" "$temp_env"
|
||||
;;
|
||||
"gitea")
|
||||
sed -i "s/SECRET_KEY=change_me/SECRET_KEY=$(generate_secret)/g" "$temp_env"
|
||||
;;
|
||||
"mastodon")
|
||||
sed -i "s/SECRET_KEY_BASE=change_me/SECRET_KEY_BASE=$(generate_secret)/g" "$temp_env"
|
||||
sed -i "s/OTP_SECRET=change_me/OTP_SECRET=$(generate_secret)/g" "$temp_env"
|
||||
sed -i "s/VAPID_PRIVATE_KEY=change_me/VAPID_PRIVATE_KEY=$(openssl ecparam -name prime256v1 -genkey -noout | openssl ec -outform DER | tail -c +8 | head -c 32 | base64)/g" "$temp_env"
|
||||
sed -i "s/VAPID_PUBLIC_KEY=change_me/VAPID_PUBLIC_KEY=$(openssl ecparam -name prime256v1 -genkey -noout | openssl ec -outform DER -pubout -outform DER | tail -c +8 | head -c 32 | base64)/g" "$temp_env"
|
||||
;;
|
||||
"nextcloud")
|
||||
sed -i "s/NEXTCLOUD_ADMIN_PASSWORD=change_me/NEXTCLOUD_ADMIN_PASSWORD=$(generate_password)/g" "$temp_env"
|
||||
;;
|
||||
"cloudreve")
|
||||
sed -i "s/CR_CONF_Database_Password=change_me/CR_CONF_Database_Password=$(generate_password)/g" "$temp_env"
|
||||
;;
|
||||
esac
|
||||
|
||||
mv "$temp_env" "$env_file"
|
||||
print_success "Secrets auto-generated"
|
||||
log_message "Secrets generated for $template"
|
||||
}
|
||||
|
||||
auto_create_directories() {
|
||||
local template="$1"
|
||||
local project_dir="$2"
|
||||
|
||||
print_step "Auto-creating directories for $template..."
|
||||
|
||||
# Create common directories
|
||||
local dirs=("data" "logs" "config" "uploads")
|
||||
|
||||
case "$template" in
|
||||
"plex")
|
||||
dirs+=("movies" "tvshows" "music" "photos")
|
||||
;;
|
||||
"immich")
|
||||
dirs+=("uploads" "library")
|
||||
;;
|
||||
"jellyfin")
|
||||
dirs+=("media" "movies" "tvshows" "music" "photos")
|
||||
;;
|
||||
"nextcloud")
|
||||
dirs+=("nextcloud-data" "nextcloud-config")
|
||||
;;
|
||||
"pihole")
|
||||
dirs+=("pihole-config" "pihole-dnsmasq" "pihole-logs")
|
||||
;;
|
||||
"vaultwarden")
|
||||
dirs+=("vaultwarden-data")
|
||||
;;
|
||||
"gitea")
|
||||
dirs+=("gitea-data" "gitea-db")
|
||||
;;
|
||||
"mastodon")
|
||||
dirs+=("mastodon-data" "postgres-data" "redis-data")
|
||||
;;
|
||||
esac
|
||||
|
||||
for dir in "${dirs[@]}"; do
|
||||
mkdir -p "$project_dir/$dir"
|
||||
print_success "Created directory: $dir"
|
||||
done
|
||||
|
||||
log_message "Directories created for $template"
|
||||
}
|
||||
|
||||
extract_docker_compose() {
|
||||
local template_file="$1"
|
||||
local project_dir="$2"
|
||||
|
||||
print_step "Extracting docker-compose.yml..."
|
||||
|
||||
# Extract docker-compose.yml from markdown file
|
||||
sed -n '/```yaml/,/```/p' "$template_file" | sed '1d;$d' > "$project_dir/docker-compose.yml"
|
||||
|
||||
if [[ ! -s "$project_dir/docker-compose.yml" ]]; then
|
||||
print_error "Failed to extract docker-compose.yml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Auto-fix common issues
|
||||
fix_docker_compose "$project_dir/docker-compose.yml" "$template"
|
||||
|
||||
print_success "docker-compose.yml extracted and optimized"
|
||||
log_message "docker-compose.yml extracted for $template"
|
||||
}
|
||||
|
||||
fix_docker_compose() {
|
||||
local compose_file="$1"
|
||||
local template="$2"
|
||||
|
||||
# Fix volume paths to use auto-created directories
|
||||
case "$template" in
|
||||
"plex")
|
||||
sed -i 's|/path/to/media|./media|g' "$compose_file"
|
||||
sed -i 's|/path/to/tvseries|./tvshows|g' "$compose_file"
|
||||
sed -i 's|/path/to/movies|./movies|g' "$compose_file"
|
||||
;;
|
||||
"immich")
|
||||
sed -i 's|/path/to/local-storage|./uploads|g' "$compose_file"
|
||||
;;
|
||||
"jellyfin")
|
||||
sed -i 's|/path/to/media|./media|g' "$compose_file"
|
||||
;;
|
||||
"nextcloud")
|
||||
sed -i 's|/path/to/nextcloud-data|./nextcloud-data|g' "$compose_file"
|
||||
;;
|
||||
"vaultwarden")
|
||||
sed -i 's|vaultwarden-data|./data|g' "$compose_file"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Fix port conflicts by auto-assigning available ports
|
||||
auto_assign_ports "$compose_file" "$template"
|
||||
}
|
||||
|
||||
auto_assign_ports() {
|
||||
local compose_file="$1"
|
||||
local template="$2"
|
||||
|
||||
local config="${TEMPLATE_CONFIGS[$template]}"
|
||||
local default_port=$(echo "$config" | cut -d',' -f1 | cut -d':' -f2)
|
||||
|
||||
# Check if default port is available
|
||||
if ! netstat -tuln 2>/dev/null | grep -q ":$default_port "; then
|
||||
print_info "Port $default_port is available"
|
||||
return
|
||||
fi
|
||||
|
||||
# Find next available port
|
||||
local new_port=$default_port
|
||||
while netstat -tuln 2>/dev/null | grep -q ":$new_port "; do
|
||||
new_port=$((new_port + 1))
|
||||
done
|
||||
|
||||
if [[ $new_port -ne $default_port ]]; then
|
||||
print_warning "Port $default_port is busy, using $new_port"
|
||||
sed -i "s/- \"$default_port:/- \"$new_port:/g" "$compose_file"
|
||||
sed -i "s/- $default_port:/- $new_port:/g" "$compose_file"
|
||||
log_message "Port changed from $default_port to $new_port for $template"
|
||||
fi
|
||||
}
|
||||
|
||||
create_env_file() {
|
||||
local template="$1"
|
||||
local project_dir="$2"
|
||||
local env_file="$project_dir/.env"
|
||||
|
||||
print_step "Creating .env file..."
|
||||
|
||||
# Extract environment variables from template
|
||||
local env_vars=$(sed -n '/## Environment Variables/,/##/p' "$TEMPLATE_DIR/$template.md" | grep -E '^- `[^`]+`')
|
||||
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
echo "# Auto-generated environment variables for $template" > "$env_file"
|
||||
echo "# Generated on $(date)" >> "$env_file"
|
||||
echo "" >> "$env_file"
|
||||
|
||||
echo "$env_vars" | while read -r line; do
|
||||
if [[ $line =~ -\s*\`([^`]+)\`.* ]]; then
|
||||
local var_name="${BASH_REMATCH[1]}"
|
||||
echo "$var_name=change_me" >> "$env_file"
|
||||
fi
|
||||
done
|
||||
|
||||
# Auto-generate secrets
|
||||
if [[ "$AUTO_GENERATE_SECRETS" == "true" ]]; then
|
||||
auto_generate_secrets "$template" "$env_file"
|
||||
fi
|
||||
|
||||
print_success ".env file created with $(wc -l < "$env_file") variables"
|
||||
else
|
||||
# Create minimal .env file
|
||||
echo "# Auto-generated environment variables for $template" > "$env_file"
|
||||
echo "# Generated on $(date)" >> "$env_file"
|
||||
echo "" >> "$env_file"
|
||||
echo "# No environment variables required" >> "$env_file"
|
||||
print_success ".env file created (no variables required)"
|
||||
fi
|
||||
|
||||
log_message ".env file created for $template"
|
||||
}
|
||||
|
||||
auto_deploy() {
|
||||
local template="$1"
|
||||
local project_dir="$2"
|
||||
|
||||
print_step "Auto-deploying $template..."
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Pull images
|
||||
if [[ "$AUTO_PULL_IMAGES" == "true" ]]; then
|
||||
print_info "Pulling Docker images..."
|
||||
docker-compose pull > /dev/null 2>&1
|
||||
print_success "Images pulled"
|
||||
fi
|
||||
|
||||
# Start services
|
||||
if [[ "$AUTO_START_SERVICES" == "true" ]]; then
|
||||
print_info "Starting services..."
|
||||
docker-compose up -d > /dev/null 2>&1
|
||||
|
||||
# Wait for services to be ready
|
||||
print_info "Waiting for services to start..."
|
||||
sleep 10
|
||||
|
||||
# Check service status
|
||||
if docker-compose ps | grep -q "Up"; then
|
||||
print_success "Services started successfully"
|
||||
else
|
||||
print_error "Some services failed to start"
|
||||
docker-compose ps
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_message "$template deployed successfully"
|
||||
}
|
||||
|
||||
show_access_info() {
|
||||
local template="$1"
|
||||
local project_dir="$2"
|
||||
|
||||
print_header "🎉 Deployment Complete!"
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Extract ports from docker-compose.yml
|
||||
local ports=$(grep -E "^\s*-\s*\"[0-9]+:[0-9]+\"" "$project_dir/docker-compose.yml")
|
||||
|
||||
if [[ -n "$ports" ]]; then
|
||||
print_success "Access URLs:"
|
||||
echo "$ports" | while read -r line; do
|
||||
if [[ $line =~ -\s*\"([0-9]+):([0-9]+)\" ]]; then
|
||||
local host_port="${BASH_REMATCH[1]}"
|
||||
local container_port="${BASH_REMATCH[2]}"
|
||||
echo " 🌐 http://localhost:$host_port (port: $container_port)"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
print_success "Management Commands:"
|
||||
echo " 📋 View logs: docker-compose logs -f"
|
||||
echo " 🛑 Stop services: docker-compose down"
|
||||
echo " 🔄 Restart: docker-compose restart"
|
||||
echo " 📊 Status: docker-compose ps"
|
||||
echo " 🗑️ Cleanup: docker-compose down -v"
|
||||
echo ""
|
||||
|
||||
print_info "Deployment directory: $project_dir"
|
||||
print_info "Log file: $LOG_FILE"
|
||||
|
||||
# Auto-open browser if enabled
|
||||
if [[ "$AUTO_OPEN_BROWSER" == "true" ]]; then
|
||||
local first_port=$(echo "$ports" | head -1 | grep -o -E '[0-9]+' | head -1)
|
||||
if [[ -n "$first_port" ]]; then
|
||||
print_info "Opening browser..."
|
||||
xdg-open "http://localhost:$first_port" 2>/dev/null || open "http://localhost:$first_port" 2>/dev/null || echo "Could not open browser automatically"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
auto_deploy_template() {
|
||||
local template="$1"
|
||||
local template_file="$TEMPLATE_DIR/$template.md"
|
||||
local project_dir="$DEPLOYMENT_BASE_DIR/$template"
|
||||
|
||||
print_header "🚀 Auto-Deploying $template"
|
||||
|
||||
# Validate template
|
||||
if [[ ! -f "$template_file" ]]; then
|
||||
print_error "Template not found: $template"
|
||||
print_info "Available templates:"
|
||||
ls -1 "$TEMPLATE_DIR" | sed 's/.md$//' | head -10
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create deployment directory
|
||||
mkdir -p "$DEPLOYMENT_BASE_DIR"
|
||||
if [[ -d "$project_dir" ]]; then
|
||||
print_warning "Deployment directory exists: $project_dir"
|
||||
print_info "Cleaning up previous deployment..."
|
||||
cd "$project_dir"
|
||||
docker-compose down -v 2>/dev/null || true
|
||||
cd ..
|
||||
rm -rf "$project_dir"
|
||||
fi
|
||||
|
||||
mkdir -p "$project_dir"
|
||||
print_success "Created deployment directory: $project_dir"
|
||||
|
||||
# Setup deployment
|
||||
extract_docker_compose "$template_file" "$project_dir"
|
||||
create_env_file "$template" "$project_dir"
|
||||
|
||||
if [[ "$AUTO_CREATE_DIRECTORIES" == "true" ]]; then
|
||||
auto_create_directories "$template" "$project_dir"
|
||||
fi
|
||||
|
||||
# Deploy
|
||||
if auto_deploy "$template" "$project_dir"; then
|
||||
show_access_info "$template" "$project_dir"
|
||||
print_success "🎉 $template deployed successfully!"
|
||||
else
|
||||
print_error "❌ $template deployment failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_all_templates() {
|
||||
print_header "🚀 Auto-Deploying All Templates"
|
||||
|
||||
local failed=()
|
||||
local success=0
|
||||
|
||||
for template in "${!TEMPLATE_CONFIGS[@]}"; do
|
||||
echo ""
|
||||
print_step "Deploying $template..."
|
||||
if auto_deploy_template "$template"; then
|
||||
((success++))
|
||||
else
|
||||
failed+=("$template")
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
print_header "📊 Deployment Summary"
|
||||
print_success "Successfully deployed: $success templates"
|
||||
|
||||
if [[ ${#failed[@]} -gt 0 ]]; then
|
||||
print_error "Failed deployments: ${#failed[@]} templates"
|
||||
print_info "Failed templates: ${failed[*]}"
|
||||
fi
|
||||
}
|
||||
|
||||
show_help() {
|
||||
echo "🚀 Docker Template Auto-Deployment"
|
||||
echo ""
|
||||
echo "Usage: $0 [OPTIONS] [TEMPLATE]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h, --help Show this help message"
|
||||
echo " -l, --list List available templates"
|
||||
echo " -a, --all Deploy all templates"
|
||||
echo " --no-secrets Don't auto-generate secrets"
|
||||
echo " --no-dirs Don't auto-create directories"
|
||||
echo " --no-pull Don't auto-pull images"
|
||||
echo " --no-start Don't auto-start services"
|
||||
echo " --open-browser Auto-open browser after deployment"
|
||||
echo ""
|
||||
echo "Templates:"
|
||||
for template in "${!TEMPLATE_CONFIGS[@]}"; do
|
||||
echo " • $template"
|
||||
done
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Interactive mode"
|
||||
echo " $0 umami # Auto-deploy umami"
|
||||
echo " $0 --all # Auto-deploy all templates"
|
||||
echo " $0 --open-browser umami # Deploy and open browser"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
# Create deployment directory
|
||||
mkdir -p "$DEPLOYMENT_BASE_DIR"
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-l|--list)
|
||||
print_header "Available Templates"
|
||||
for template in "${!TEMPLATE_CONFIGS[@]}"; do
|
||||
echo " • $template - ${TEMPLATE_CONFIGS[$template]}"
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
-a|--all)
|
||||
check_dependencies
|
||||
deploy_all_templates
|
||||
exit 0
|
||||
;;
|
||||
--no-secrets)
|
||||
AUTO_GENERATE_SECRETS=false
|
||||
shift
|
||||
;;
|
||||
--no-dirs)
|
||||
AUTO_CREATE_DIRECTORIES=false
|
||||
shift
|
||||
;;
|
||||
--no-pull)
|
||||
AUTO_PULL_IMAGES=false
|
||||
shift
|
||||
;;
|
||||
--no-start)
|
||||
AUTO_START_SERVICES=false
|
||||
shift
|
||||
;;
|
||||
--open-browser)
|
||||
AUTO_OPEN_BROWSER=true
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
print_error "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
SELECTED_TEMPLATE="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies
|
||||
|
||||
# Execute deployment
|
||||
if [[ -n "$SELECTED_TEMPLATE" ]]; then
|
||||
auto_deploy_template "$SELECTED_TEMPLATE"
|
||||
else
|
||||
# Interactive mode - deploy a simple template by default
|
||||
print_info "No template specified, deploying Glance (simple dashboard)..."
|
||||
auto_deploy_template "glance"
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Quick Test Script - Try out the setup system
|
||||
# This script demonstrates the auto-setup with a simple template
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Docker Template Auto-Setup Demo"
|
||||
echo "=================================="
|
||||
echo ""
|
||||
|
||||
# Check if we're in the right directory
|
||||
if [[ ! -f "scripts/setup-template.sh" ]]; then
|
||||
echo "❌ Error: Please run this script from the project root directory"
|
||||
echo " Current directory: $(pwd)"
|
||||
echo " Expected: scripts/setup-template.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Found setup script"
|
||||
echo ""
|
||||
|
||||
# Make script executable
|
||||
chmod +x scripts/setup-template.sh
|
||||
|
||||
echo "📋 Available Templates:"
|
||||
./scripts/setup-template.sh --list
|
||||
echo ""
|
||||
|
||||
echo "🎯 Let's try setting up a simple template (Glance Dashboard)..."
|
||||
echo ""
|
||||
|
||||
# Create a test deployment
|
||||
echo "Setting up Glance template..."
|
||||
./scripts/setup-template.sh --setup glance
|
||||
|
||||
echo ""
|
||||
echo "📁 Created files:"
|
||||
ls -la glance-deployment/
|
||||
echo ""
|
||||
|
||||
echo "📄 Generated docker-compose.yml:"
|
||||
echo "---"
|
||||
head -20 glance-deployment/docker-compose.yml
|
||||
echo "---"
|
||||
echo ""
|
||||
|
||||
echo "🔧 Generated .env file:"
|
||||
if [[ -f "glance-deployment/.env" ]]; then
|
||||
echo "---"
|
||||
cat glance-deployment/.env
|
||||
echo "---"
|
||||
else
|
||||
echo "No .env file generated (Glance doesn't require environment variables)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "✅ Setup completed successfully!"
|
||||
echo ""
|
||||
echo "🎯 Next steps:"
|
||||
echo "1. cd glance-deployment"
|
||||
echo "2. Review the configuration"
|
||||
echo "3. Run: docker-compose up -d"
|
||||
echo "4. Access: http://localhost:8080"
|
||||
echo ""
|
||||
echo "🧹 Cleanup (when done):"
|
||||
echo " cd glance-deployment && docker-compose down"
|
||||
echo " cd .. && rm -rf glance-deployment"
|
||||
echo ""
|
||||
|
||||
echo "🚀 Try other templates:"
|
||||
echo " ./scripts/setup-template.sh umami # Analytics"
|
||||
echo " ./scripts/setup-template.sh memos # Notes"
|
||||
echo " ./scripts/setup-template.sh uptime-kuma # Monitoring"
|
||||
echo ""
|
||||
echo "📖 Full guide: SETUP_GUIDE.md"
|
||||
Executable
+264
@@ -0,0 +1,264 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Production Readiness Check Script
|
||||
# This script validates that all production requirements are met
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔍 Containr Production Readiness Check"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
ERRORS=0
|
||||
WARNINGS=0
|
||||
|
||||
# Color codes
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
error() {
|
||||
echo -e "${RED}❌ ERROR: $1${NC}"
|
||||
((ERRORS++))
|
||||
}
|
||||
|
||||
warning() {
|
||||
echo -e "${YELLOW}⚠️ WARNING: $1${NC}"
|
||||
((WARNINGS++))
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo "ℹ️ $1"
|
||||
}
|
||||
|
||||
# Check if production env file exists
|
||||
ENV_FILE=".env.prod"
|
||||
if [ ! -f "$ENV_FILE" ] && [ -f ".env" ]; then
|
||||
ENV_FILE=".env"
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
error "No production env file found. Copy .env.production.example to .env.prod"
|
||||
else
|
||||
success "$ENV_FILE exists"
|
||||
fi
|
||||
|
||||
# Load environment variables
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "1. Environment Configuration"
|
||||
echo "----------------------------"
|
||||
|
||||
# Check ENVIRONMENT
|
||||
if [ "$ENVIRONMENT" != "production" ]; then
|
||||
warning "ENVIRONMENT is not set to 'production' (current: ${ENVIRONMENT:-not set})"
|
||||
else
|
||||
success "ENVIRONMENT is set to production"
|
||||
fi
|
||||
|
||||
# Check JWT_SECRET
|
||||
if [ -z "$JWT_SECRET" ] || [ "$JWT_SECRET" = "your-secret-key-change-in-production" ]; then
|
||||
error "JWT_SECRET is not set or using default value"
|
||||
elif [ ${#JWT_SECRET} -lt 32 ]; then
|
||||
error "JWT_SECRET must be at least 32 characters (current: ${#JWT_SECRET})"
|
||||
else
|
||||
success "JWT_SECRET is properly configured"
|
||||
fi
|
||||
|
||||
# Check BETTER_AUTH_SECRET
|
||||
if [ -z "$BETTER_AUTH_SECRET" ] || [ "$BETTER_AUTH_SECRET" = "PLACEHOLDER_BETTER_AUTH_SECRET_CHANGE_ME_32CHARS_MIN" ]; then
|
||||
error "BETTER_AUTH_SECRET is not set or using placeholder"
|
||||
elif [ ${#BETTER_AUTH_SECRET} -lt 32 ]; then
|
||||
error "BETTER_AUTH_SECRET must be at least 32 characters"
|
||||
else
|
||||
success "BETTER_AUTH_SECRET is properly configured"
|
||||
fi
|
||||
|
||||
# Check COOKIE_SECURE
|
||||
if [ "$COOKIE_SECURE" != "true" ]; then
|
||||
error "COOKIE_SECURE must be 'true' in production (current: ${COOKIE_SECURE:-not set})"
|
||||
else
|
||||
success "COOKIE_SECURE is enabled"
|
||||
fi
|
||||
|
||||
# Check CORS_ORIGINS
|
||||
if [ -z "$CORS_ORIGINS" ] || [ "$CORS_ORIGINS" = "*" ]; then
|
||||
error "CORS_ORIGINS must be set to specific domains in production"
|
||||
elif [[ "$CORS_ORIGINS" == *"*"* ]]; then
|
||||
error "CORS_ORIGINS cannot contain wildcards in production"
|
||||
else
|
||||
success "CORS_ORIGINS is properly configured"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "2. Database Configuration"
|
||||
echo "-------------------------"
|
||||
|
||||
# Check database password
|
||||
if [ -z "$POSTGRES_PASSWORD" ] || [ "$POSTGRES_PASSWORD" = "dev_password_123" ]; then
|
||||
error "POSTGRES_PASSWORD is not set or using default value"
|
||||
else
|
||||
success "POSTGRES_PASSWORD is configured"
|
||||
fi
|
||||
|
||||
# Check Redis password
|
||||
if [ -z "$REDIS_PASSWORD" ] || [ "$REDIS_PASSWORD" = "dev_redis_123" ]; then
|
||||
error "REDIS_PASSWORD is not set or using default value"
|
||||
else
|
||||
success "REDIS_PASSWORD is configured"
|
||||
fi
|
||||
|
||||
# Check AUTO_MIGRATE
|
||||
if [ "$AUTO_MIGRATE" = "true" ]; then
|
||||
success "AUTO_MIGRATE is enabled"
|
||||
else
|
||||
warning "AUTO_MIGRATE is disabled - ensure migrations are run manually"
|
||||
fi
|
||||
|
||||
# Check SEED_DATA_ON_START
|
||||
if [ "$SEED_DATA_ON_START" = "true" ]; then
|
||||
error "SEED_DATA_ON_START must be false in production"
|
||||
else
|
||||
success "SEED_DATA_ON_START is disabled"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "3. Security Configuration"
|
||||
echo "-------------------------"
|
||||
|
||||
# Check CONTAINR_AGENT_AUTH_TOKEN
|
||||
if [ -z "$CONTAINR_AGENT_AUTH_TOKEN" ] || [ "$CONTAINR_AGENT_AUTH_TOKEN" = "replace_with_strong_agent_secret" ]; then
|
||||
error "CONTAINR_AGENT_AUTH_TOKEN is not set or using placeholder"
|
||||
else
|
||||
success "CONTAINR_AGENT_AUTH_TOKEN is configured"
|
||||
fi
|
||||
|
||||
# Check BCRYPT_COST
|
||||
if [ -z "$BCRYPT_COST" ]; then
|
||||
warning "BCRYPT_COST not set, using default"
|
||||
elif [ "$BCRYPT_COST" -lt 12 ]; then
|
||||
warning "BCRYPT_COST should be at least 12 for production (current: $BCRYPT_COST)"
|
||||
else
|
||||
success "BCRYPT_COST is properly configured"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "4. Domain Configuration"
|
||||
echo "-----------------------"
|
||||
|
||||
# Check DOMAIN
|
||||
if [ -z "$DOMAIN" ] || [ "$DOMAIN" = "localhost" ]; then
|
||||
error "DOMAIN must be set to your actual domain"
|
||||
else
|
||||
success "DOMAIN is configured: $DOMAIN"
|
||||
fi
|
||||
|
||||
# Check ACME_EMAIL
|
||||
if [ -z "$ACME_EMAIL" ] || [ "$ACME_EMAIL" = "admin@localhost" ]; then
|
||||
warning "ACME_EMAIL should be set to a valid email for SSL certificates"
|
||||
else
|
||||
success "ACME_EMAIL is configured"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "5. File Structure"
|
||||
echo "-----------------"
|
||||
|
||||
# Check critical files
|
||||
CRITICAL_FILES=(
|
||||
"docker-compose.yml"
|
||||
"infra/docker-compose.yml"
|
||||
"app/backend/Dockerfile"
|
||||
"app/frontend/Dockerfile"
|
||||
"app/backend/go.mod"
|
||||
"app/frontend/package.json"
|
||||
)
|
||||
|
||||
for file in "${CRITICAL_FILES[@]}"; do
|
||||
if [ -f "$file" ]; then
|
||||
success "$file exists"
|
||||
else
|
||||
error "$file is missing"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "6. Docker Configuration"
|
||||
echo "-----------------------"
|
||||
|
||||
# Check if Docker is installed
|
||||
if command -v docker &> /dev/null; then
|
||||
success "Docker is installed"
|
||||
docker --version
|
||||
else
|
||||
error "Docker is not installed"
|
||||
fi
|
||||
|
||||
# Check if Docker Compose is available
|
||||
if docker compose version &> /dev/null; then
|
||||
success "Docker Compose is available"
|
||||
docker compose version
|
||||
else
|
||||
error "Docker Compose is not available"
|
||||
fi
|
||||
|
||||
# Validate docker-compose.yml
|
||||
if [ -f "infra/docker-compose.yml" ]; then
|
||||
if docker compose -f infra/docker-compose.yml config -q 2>/dev/null; then
|
||||
success "docker-compose.yml is valid"
|
||||
else
|
||||
error "docker-compose.yml has syntax errors"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "7. Build Checks"
|
||||
echo "---------------"
|
||||
|
||||
# Check backend build
|
||||
if [ -f "app/backend/go.mod" ]; then
|
||||
cd app/backend
|
||||
if go mod verify &> /dev/null; then
|
||||
success "Backend Go modules are valid"
|
||||
else
|
||||
warning "Backend Go modules verification failed"
|
||||
fi
|
||||
cd ../..
|
||||
fi
|
||||
|
||||
# Check frontend build
|
||||
if [ -f "app/frontend/package.json" ]; then
|
||||
if [ -d "app/frontend/node_modules" ]; then
|
||||
success "Frontend dependencies are installed"
|
||||
else
|
||||
warning "Frontend dependencies not installed - run 'npm install'"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "Summary"
|
||||
echo "========================================"
|
||||
|
||||
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
|
||||
echo -e "${GREEN}✅ All checks passed! Ready for production deployment.${NC}"
|
||||
exit 0
|
||||
elif [ $ERRORS -eq 0 ]; then
|
||||
echo -e "${YELLOW}⚠️ $WARNINGS warning(s) found. Review before deploying.${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}❌ $ERRORS error(s) and $WARNINGS warning(s) found.${NC}"
|
||||
echo -e "${RED}Please fix all errors before deploying to production.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
# One-Click Docker Deployment - Quick Start Script
|
||||
# This script provides the simplest possible deployment experience
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 One-Click Docker Deployment"
|
||||
echo "============================"
|
||||
echo ""
|
||||
|
||||
# Check if we're in the right directory
|
||||
if [[ ! -f "scripts/auto-deploy.sh" ]]; then
|
||||
echo "❌ Error: Please run this script from the project root directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make script executable
|
||||
chmod +x scripts/auto-deploy.sh
|
||||
|
||||
echo "🎯 Choose your deployment:"
|
||||
echo ""
|
||||
echo "1. 🌐 Deploy Glance Dashboard (Recommended - Simple & Fast)"
|
||||
echo "2. 📊 Deploy Umami Analytics (Web Analytics)"
|
||||
echo "3. 📝 Deploy Memos (Note-taking)"
|
||||
echo "4. 🔍 Deploy MeiliSearch (Search Engine)"
|
||||
echo "5. 📈 Deploy Uptime Kuma (Monitoring)"
|
||||
echo "6. 🚀 Deploy ALL Templates (Advanced)"
|
||||
echo ""
|
||||
read -p "Enter your choice (1-6): " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
echo ""
|
||||
echo "🌐 Deploying Glance Dashboard..."
|
||||
./scripts/auto-deploy.sh glance
|
||||
;;
|
||||
2)
|
||||
echo ""
|
||||
echo "📊 Deploying Umami Analytics..."
|
||||
./scripts/auto-deploy.sh umami
|
||||
;;
|
||||
3)
|
||||
echo ""
|
||||
echo "📝 Deploying Memos..."
|
||||
./scripts/auto-deploy.sh memos
|
||||
;;
|
||||
4)
|
||||
echo ""
|
||||
echo "🔍 Deploying MeiliSearch..."
|
||||
./scripts/auto-deploy.sh meilisearch
|
||||
;;
|
||||
5)
|
||||
echo ""
|
||||
echo "📈 Deploying Uptime Kuma..."
|
||||
./scripts/auto-deploy.sh uptime-kuma
|
||||
;;
|
||||
6)
|
||||
echo ""
|
||||
echo "🚀 Deploying ALL Templates (this will take a while)..."
|
||||
./scripts/auto-deploy.sh --all
|
||||
;;
|
||||
*)
|
||||
echo "❌ Invalid choice. Defaulting to Glance Dashboard..."
|
||||
./scripts/auto-deploy.sh glance
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "✅ Deployment process started!"
|
||||
echo ""
|
||||
echo "📋 What's happening automatically:"
|
||||
echo " 🔍 Checking dependencies (Docker, Docker Compose)"
|
||||
echo " 📁 Creating deployment directories"
|
||||
echo " 🔧 Extracting docker-compose.yml"
|
||||
echo " 🔐 Generating secrets and passwords"
|
||||
echo " 🐳 Pulling Docker images"
|
||||
echo " 🚀 Starting all services"
|
||||
echo " 🌐 Showing access URLs"
|
||||
echo ""
|
||||
echo "📊 Watch the progress above. When complete, you'll see access URLs!"
|
||||
echo ""
|
||||
echo "🛑 To stop services: cd deployments/template-name && docker-compose down"
|
||||
Executable
+430
@@ -0,0 +1,430 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Docker Template Auto-Setup Script
|
||||
# This script provides a guided walkthrough for deploying any template
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Template directory
|
||||
TEMPLATE_DIR="$(dirname "$0")/../templates"
|
||||
|
||||
# Available templates
|
||||
declare -A TEMPLATES=(
|
||||
["umami"]="Umami Analytics - Privacy-focused web analytics"
|
||||
["plex"]="Plex Media Server - Media streaming and organization"
|
||||
["immich"]="Immich - Photo and video backup solution"
|
||||
["n8n"]="n8n - Workflow automation platform"
|
||||
["supabase"]="Supabase - Open source Firebase alternative"
|
||||
["home-assistant"]="Home Assistant - Smart home automation"
|
||||
["uptime-kuma"]="Uptime Kuma - Monitoring dashboard"
|
||||
["grafana"]="Grafana - Metrics visualization and monitoring"
|
||||
["traefik"]="Traefik - Reverse proxy and load balancer"
|
||||
["memos"]="Memos - Note-taking and knowledge management"
|
||||
["meilisearch"]="MeiliSearch - Fast search engine"
|
||||
["vaultwarden"]="Vaultwarden - Password manager (Bitwarden alternative)"
|
||||
["pihole"]="Pi-hole - DNS ad blocker"
|
||||
["appwrite"]="Appwrite - Backend-as-a-Service platform"
|
||||
["gitea"]="Gitea - Git hosting service"
|
||||
["mastodon"]="Mastodon - Decentralized social network"
|
||||
["jellyfin"]="Jellyfin - Media server (Plex alternative)"
|
||||
["nextcloud"]="Nextcloud - Cloud storage and collaboration"
|
||||
["glance"]="Glance - Personal dashboard"
|
||||
["cloudreve"]="Cloudreve - File manager with multiple backends"
|
||||
)
|
||||
|
||||
print_header() {
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
check_dependencies() {
|
||||
print_header "Checking Dependencies"
|
||||
|
||||
# Check Docker
|
||||
if command -v docker &> /dev/null; then
|
||||
print_success "Docker is installed"
|
||||
docker_version=$(docker --version | cut -d' ' -f3 | cut -d',' -f1)
|
||||
print_info "Docker version: $docker_version"
|
||||
else
|
||||
print_error "Docker is not installed"
|
||||
print_info "Please install Docker: https://docs.docker.com/get-docker/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Docker Compose
|
||||
if command -v docker-compose &> /dev/null; then
|
||||
print_success "Docker Compose is installed"
|
||||
compose_version=$(docker-compose --version | cut -d' ' -f3 | cut -d',' -f1)
|
||||
print_info "Docker Compose version: $compose_version"
|
||||
elif docker compose version &> /dev/null; then
|
||||
print_success "Docker Compose (plugin) is installed"
|
||||
compose_version=$(docker compose version | cut -d' ' -f3 | cut -d',' -f1)
|
||||
print_info "Docker Compose version: $compose_version"
|
||||
DOCKER_COMPOSE_CMD="docker compose"
|
||||
else
|
||||
print_error "Docker Compose is not installed"
|
||||
print_info "Please install Docker Compose: https://docs.docker.com/compose/install/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if template directory exists
|
||||
if [[ ! -d "$TEMPLATE_DIR" ]]; then
|
||||
print_error "Template directory not found: $TEMPLATE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "All dependencies are met"
|
||||
}
|
||||
|
||||
list_templates() {
|
||||
print_header "Available Templates"
|
||||
|
||||
echo "Available templates:"
|
||||
for template in "${!TEMPLATES[@]}"; do
|
||||
echo " • $template - ${TEMPLATES[$template]}"
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
select_template() {
|
||||
if [[ -n "$SELECTED_TEMPLATE" ]]; then
|
||||
if [[ -z "${TEMPLATES[$SELECTED_TEMPLATE]}" ]]; then
|
||||
print_error "Unknown template: $SELECTED_TEMPLATE"
|
||||
list_templates
|
||||
exit 1
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
print_header "Select Template"
|
||||
|
||||
local i=1
|
||||
local template_array=()
|
||||
|
||||
for template in "${!TEMPLATES[@]}"; do
|
||||
echo " $i) $template - ${TEMPLATES[$template]}"
|
||||
template_array+=("$template")
|
||||
((i++))
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -p "Select a template (1-${#template_array[@]}): " choice
|
||||
|
||||
if [[ $choice =~ ^[0-9]+$ ]] && [ $choice -ge 1 ] && [ $choice -le ${#template_array[@]} ]; then
|
||||
SELECTED_TEMPLATE="${template_array[$((choice-1))]}"
|
||||
else
|
||||
print_error "Invalid selection"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "Selected template: $SELECTED_TEMPLATE"
|
||||
}
|
||||
|
||||
setup_template() {
|
||||
local template="$1"
|
||||
local template_file="$TEMPLATE_DIR/$template.md"
|
||||
|
||||
if [[ ! -f "$template_file" ]]; then
|
||||
print_error "Template file not found: $template_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_header "Setting up $template"
|
||||
|
||||
# Create project directory
|
||||
local project_dir="$PWD/$template-deployment"
|
||||
if [[ -d "$project_dir" ]]; then
|
||||
print_warning "Directory $project_dir already exists"
|
||||
read -p "Do you want to remove it and continue? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
rm -rf "$project_dir"
|
||||
else
|
||||
print_info "Please choose a different location or remove the existing directory"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p "$project_dir"
|
||||
print_success "Created project directory: $project_dir"
|
||||
|
||||
# Extract docker-compose.yml from template
|
||||
extract_docker_compose "$template_file" "$project_dir"
|
||||
|
||||
# Check for environment variables
|
||||
check_environment_variables "$template_file" "$project_dir"
|
||||
|
||||
# Check for additional setup steps
|
||||
check_setup_requirements "$template_file" "$project_dir"
|
||||
|
||||
print_success "Template setup completed"
|
||||
print_info "Project directory: $project_dir"
|
||||
print_info "Next steps:"
|
||||
echo " 1. cd $project_dir"
|
||||
echo " 2. Review and modify configuration if needed"
|
||||
echo " 3. Run: ${DOCKER_COMPOSE_CMD:-docker-compose} up -d"
|
||||
}
|
||||
|
||||
extract_docker_compose() {
|
||||
local template_file="$1"
|
||||
local project_dir="$2"
|
||||
|
||||
print_info "Extracting docker-compose.yml..."
|
||||
|
||||
# Extract docker-compose.yml from markdown file
|
||||
sed -n '/```yaml/,/```/p' "$template_file" | sed '1d;$d' > "$project_dir/docker-compose.yml"
|
||||
|
||||
if [[ ! -s "$project_dir/docker-compose.yml" ]]; then
|
||||
print_error "Failed to extract docker-compose.yml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "docker-compose.yml extracted"
|
||||
}
|
||||
|
||||
check_environment_variables() {
|
||||
local template_file="$1"
|
||||
local project_dir="$2"
|
||||
|
||||
print_info "Checking for required environment variables..."
|
||||
|
||||
# Extract environment variables section
|
||||
local env_vars=$(sed -n '/## Environment Variables/,/##/p' "$template_file" | grep -E '^- `[^`]+`')
|
||||
|
||||
if [[ -n "$env_vars" ]]; then
|
||||
print_warning "This template requires environment variables:"
|
||||
echo "$env_vars"
|
||||
echo ""
|
||||
|
||||
# Create .env file template
|
||||
local env_file="$project_dir/.env"
|
||||
echo "# Environment variables for $template" > "$env_file"
|
||||
echo "# Please update these values before starting the services" >> "$env_file"
|
||||
echo "" >> "$env_file"
|
||||
|
||||
# Add common environment variables
|
||||
echo "$env_vars" | while read -r line; do
|
||||
if [[ $line =~ -\s*\`([^`]+)\`.* ]]; then
|
||||
local var_name="${BASH_REMATCH[1]}"
|
||||
echo "$var_name=change_me" >> "$env_file"
|
||||
fi
|
||||
done
|
||||
|
||||
print_success "Created .env template file"
|
||||
print_warning "Please edit $env_file with your values before starting"
|
||||
fi
|
||||
}
|
||||
|
||||
check_setup_requirements() {
|
||||
local template_file="$1"
|
||||
local project_dir="$2"
|
||||
|
||||
print_info "Checking setup requirements..."
|
||||
|
||||
# Extract setup guide section
|
||||
local setup_guide=$(sed -n '/## Setup Guide/,/##/p' "$template_file")
|
||||
|
||||
if [[ -n "$setup_guide" ]]; then
|
||||
print_warning "This template has specific setup requirements:"
|
||||
echo "$setup_guide" | head -20
|
||||
echo ""
|
||||
print_info "Please review the full setup guide in $template_file"
|
||||
fi
|
||||
|
||||
# Check for volume requirements
|
||||
local volumes=$(grep -E "^\s*-\s+.*:/" "$project_dir/docker-compose.yml" | grep -v "./")
|
||||
if [[ -n "$volumes" ]]; then
|
||||
print_warning "This template requires host directories:"
|
||||
echo "$volumes"
|
||||
echo ""
|
||||
print_info "Please create these directories or update the paths in docker-compose.yml"
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_template() {
|
||||
local project_dir="$PWD/$SELECTED_TEMPLATE-deployment"
|
||||
|
||||
print_header "Deploying $SELECTED_TEMPLATE"
|
||||
|
||||
if [[ ! -d "$project_dir" ]]; then
|
||||
print_error "Project directory not found: $project_dir"
|
||||
print_info "Please run setup first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Check if .env exists and has default values
|
||||
if [[ -f ".env" ]]; then
|
||||
if grep -q "change_me" .env; then
|
||||
print_warning "Please update the environment variables in .env file"
|
||||
print_info "Current values that need updating:"
|
||||
grep "change_me" .env
|
||||
echo ""
|
||||
read -p "Continue anyway? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
print_info "Starting deployment..."
|
||||
|
||||
# Pull images
|
||||
print_info "Pulling Docker images..."
|
||||
${DOCKER_COMPOSE_CMD:-docker-compose} pull
|
||||
|
||||
# Start services
|
||||
print_info "Starting services..."
|
||||
${DOCKER_COMPOSE_CMD:-docker-compose} up -d
|
||||
|
||||
# Show status
|
||||
print_success "Deployment completed!"
|
||||
${DOCKER_COMPOSE_CMD:-docker-compose} ps
|
||||
|
||||
# Show access information
|
||||
show_access_info "$project_dir"
|
||||
}
|
||||
|
||||
show_access_info() {
|
||||
local project_dir="$1"
|
||||
|
||||
print_header "Access Information"
|
||||
|
||||
# Extract ports from docker-compose.yml
|
||||
local ports=$(grep -E "^\s*-\s*\"[0-9]+:[0-9]+\"" "$project_dir/docker-compose.yml")
|
||||
|
||||
if [[ -n "$ports" ]]; then
|
||||
print_info "Service access URLs:"
|
||||
echo "$ports" | while read -r line; do
|
||||
if [[ $line =~ -\s*\"([0-9]+):([0-9]+)\" ]]; then
|
||||
local host_port="${BASH_REMATCH[1]}"
|
||||
local container_port="${BASH_REMATCH[2]}"
|
||||
echo " • http://localhost:$host_port (container port: $container_port)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
print_info "Useful commands:"
|
||||
echo " • View logs: ${DOCKER_COMPOSE_CMD:-docker-compose} logs -f"
|
||||
echo " • Stop services: ${DOCKER_COMPOSE_CMD:-docker-compose} down"
|
||||
echo " • Restart services: ${DOCKER_COMPOSE_CMD:-docker-compose} restart"
|
||||
echo " • Update services: ${DOCKER_COMPOSE_CMD:-docker-compose} pull && ${DOCKER_COMPOSE_CMD:-docker-compose} up -d"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
echo "Docker Template Setup Script"
|
||||
echo ""
|
||||
echo "Usage: $0 [OPTIONS] [TEMPLATE]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h, --help Show this help message"
|
||||
echo " -l, --list List available templates"
|
||||
echo " -s, --setup Setup template only (don't deploy)"
|
||||
echo " -d, --deploy Deploy template (requires setup first)"
|
||||
echo ""
|
||||
echo "Templates:"
|
||||
list_templates
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Interactive mode"
|
||||
echo " $0 umami # Setup umami template"
|
||||
echo " $0 --list # List all templates"
|
||||
echo " $0 --setup umami # Setup umami only"
|
||||
echo " $0 --deploy umami # Deploy umami (must be setup first)"
|
||||
}
|
||||
|
||||
# Main script logic
|
||||
main() {
|
||||
local action="interactive"
|
||||
local setup_only=false
|
||||
local deploy_only=false
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-l|--list)
|
||||
list_templates
|
||||
exit 0
|
||||
;;
|
||||
-s|--setup)
|
||||
setup_only=true
|
||||
shift
|
||||
;;
|
||||
-d|--deploy)
|
||||
deploy_only=true
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
print_error "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
SELECTED_TEMPLATE="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies
|
||||
|
||||
# Execute based on action
|
||||
if [[ "$deploy_only" == true ]]; then
|
||||
if [[ -z "$SELECTED_TEMPLATE" ]]; then
|
||||
print_error "Template name required for deployment"
|
||||
exit 1
|
||||
fi
|
||||
deploy_template
|
||||
elif [[ "$setup_only" == true ]]; then
|
||||
select_template
|
||||
setup_template "$SELECTED_TEMPLATE"
|
||||
else
|
||||
# Interactive mode
|
||||
select_template
|
||||
setup_template "$SELECTED_TEMPLATE"
|
||||
|
||||
echo ""
|
||||
read -p "Do you want to deploy the template now? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
deploy_template
|
||||
else
|
||||
print_info "Setup completed. You can deploy later by running:"
|
||||
echo " $0 --deploy $SELECTED_TEMPLATE"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Test the auto-deployment system with a simple template
|
||||
echo "🧪 Testing Auto-Deployment System"
|
||||
echo "================================"
|
||||
echo ""
|
||||
|
||||
# Check if we're in the right directory
|
||||
if [[ ! -f "scripts/auto-deploy.sh" ]]; then
|
||||
echo "❌ Error: Please run this script from the project root directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔍 Checking dependencies..."
|
||||
if command -v docker &> /dev/null; then
|
||||
echo "✅ Docker is available"
|
||||
else
|
||||
echo "❌ Docker is not available - this test requires Docker"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🎯 Testing auto-deployment with Glance (simplest template)..."
|
||||
echo ""
|
||||
|
||||
# Make scripts executable
|
||||
chmod +x scripts/auto-deploy.sh
|
||||
chmod +x scripts/quick-deploy.sh
|
||||
|
||||
echo "📋 Available deployment options:"
|
||||
echo "1. Quick Deploy: ./scripts/quick-deploy.sh"
|
||||
echo "2. Direct Deploy: ./scripts/auto-deploy.sh glance"
|
||||
echo "3. List Templates: ./scripts/auto-deploy.sh --list"
|
||||
echo "4. Deploy All: ./scripts/auto-deploy.sh --all"
|
||||
echo ""
|
||||
|
||||
echo "🚀 Let's test the system by listing available templates:"
|
||||
./scripts/auto-deploy.sh --list
|
||||
|
||||
echo ""
|
||||
echo "✅ Auto-deployment system is ready!"
|
||||
echo ""
|
||||
echo "🎯 To use it:"
|
||||
echo " ./scripts/quick-deploy.sh # Interactive menu"
|
||||
echo " ./scripts/auto-deploy.sh glance # Direct deployment"
|
||||
echo ""
|
||||
echo "📖 Full guide: AUTO_DEPLOY_GUIDE.md"
|
||||
Executable
+111
@@ -0,0 +1,111 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
SCRIPT="$ROOT_DIR/start-unified.sh"
|
||||
ENV_FILE="$ROOT_DIR/.env.prod"
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "SKIP: docker command not found, skipping preflight tests"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
backup_file=""
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
backup_file="$(mktemp)"
|
||||
cp "$ENV_FILE" "$backup_file"
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
if [ -n "$backup_file" ] && [ -f "$backup_file" ]; then
|
||||
mv "$backup_file" "$ENV_FILE"
|
||||
else
|
||||
rm -f "$ENV_FILE"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
write_env() {
|
||||
cat > "$ENV_FILE" <<EOT
|
||||
$1
|
||||
EOT
|
||||
}
|
||||
|
||||
expect_fail() {
|
||||
local name="$1"
|
||||
local expected="$2"
|
||||
shift 2
|
||||
|
||||
set +e
|
||||
local output
|
||||
output="$($SCRIPT "$@" 2>&1)"
|
||||
local code=$?
|
||||
set -e
|
||||
|
||||
if [ "$code" -eq 0 ]; then
|
||||
echo "FAIL [$name]: command unexpectedly succeeded"
|
||||
echo "$output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq "$expected" <<<"$output"; then
|
||||
echo "FAIL [$name]: expected error message not found"
|
||||
echo "Expected: $expected"
|
||||
echo "Output:"
|
||||
echo "$output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "PASS [$name]"
|
||||
}
|
||||
|
||||
write_env "DOMAIN=localhost
|
||||
JWT_SECRET=this-is-a-very-strong-production-secret-123
|
||||
BETTER_AUTH_SECRET=this-is-a-very-strong-better-auth-secret-123
|
||||
BETTER_AUTH_INTERNAL_TOKEN=internal-auth-token
|
||||
COOKIE_SECURE=true
|
||||
TRAEFIK_AUTH=admin:\$\$apr1\$\$hash\$\$hashvalue"
|
||||
expect_fail "prod-domain" "DOMAIN must be set to a real domain for production." prod
|
||||
|
||||
write_env "DOMAIN=example.com
|
||||
JWT_SECRET=dev_jwt_secret_key_change_in_production
|
||||
BETTER_AUTH_SECRET=this-is-a-very-strong-better-auth-secret-123
|
||||
BETTER_AUTH_INTERNAL_TOKEN=internal-auth-token
|
||||
COOKIE_SECURE=true
|
||||
TRAEFIK_AUTH=admin:\$\$apr1\$\$hash\$\$hashvalue"
|
||||
expect_fail "prod-jwt" "JWT_SECRET must be set to a strong non-default value in production." prod
|
||||
|
||||
write_env "DOMAIN=example.com
|
||||
JWT_SECRET=strong-secret
|
||||
BETTER_AUTH_SECRET=this-is-a-very-strong-better-auth-secret-123
|
||||
BETTER_AUTH_INTERNAL_TOKEN=internal-auth-token
|
||||
COOKIE_SECURE=true
|
||||
TRAEFIK_AUTH=admin:\$\$apr1\$\$hash\$\$hashvalue"
|
||||
expect_fail "prod-jwt-length" "JWT_SECRET must be at least 32 characters in production." prod
|
||||
|
||||
write_env "DOMAIN=example.com
|
||||
JWT_SECRET=this-is-a-very-strong-production-secret-123
|
||||
BETTER_AUTH_SECRET=this-is-a-very-strong-better-auth-secret-123
|
||||
BETTER_AUTH_INTERNAL_TOKEN=internal-auth-token
|
||||
COOKIE_SECURE=true"
|
||||
expect_fail "prod-traefik-auth" "TRAEFIK_AUTH must be set (basic auth hash) for dashboard protection in production." prod
|
||||
|
||||
write_env "DOMAIN=example.com
|
||||
JWT_SECRET=this-is-a-very-strong-production-secret-123
|
||||
BETTER_AUTH_SECRET=this-is-a-very-strong-better-auth-secret-123
|
||||
BETTER_AUTH_INTERNAL_TOKEN=internal-auth-token
|
||||
COOKIE_SECURE=true
|
||||
TRAEFIK_AUTH=admin:\$\$apr1\$\$hash\$\$hashvalue"
|
||||
expect_fail "prod-agent-auth" "CONTAINR_AGENT_AUTH_TOKEN or CONTAINR_AGENT_AUTH_TOKENS must be set in production." prod
|
||||
|
||||
write_env "DOMAIN=example.com
|
||||
JWT_SECRET=this-is-a-very-strong-production-secret-123
|
||||
BETTER_AUTH_SECRET=this-is-a-very-strong-better-auth-secret-123
|
||||
BETTER_AUTH_INTERNAL_TOKEN=internal-auth-token
|
||||
COOKIE_SECURE=true
|
||||
TRAEFIK_AUTH=admin:\$\$apr1\$\$hash\$\$hashvalue
|
||||
CONTAINR_AGENT_AUTH_TOKEN=agent-secret"
|
||||
expect_fail "cloudflare-token" "CLOUDFLARED_TOKEN must be set." cloudflare
|
||||
|
||||
echo "All start-unified preflight tests passed"
|
||||
Reference in New Issue
Block a user