mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-07-29 14:03:50 +00:00
small fix, don't worry about it
This commit is contained in:
+135
-134
@@ -1,172 +1,170 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Unified Docker Compose Management Script
|
||||
# Usage: ./start-unified.sh [dev|prod|cloudflare|stop|logs|status|clean]
|
||||
set -euo pipefail
|
||||
|
||||
set -e
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCAL_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
||||
SELFHOSTED_COMPOSE_FILE="$ROOT_DIR/infra/docker-compose.yml"
|
||||
LOCAL_ENV_FILE="$ROOT_DIR/.env"
|
||||
PROD_ENV_FILE="$ROOT_DIR/.env.prod"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
info() {
|
||||
printf '[INFO] %s\n' "$1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
success() {
|
||||
printf '[OK] %s\n' "$1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
error() {
|
||||
printf '[ERROR] %s\n' "$1" >&2
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
docker_compose() {
|
||||
docker compose "$@"
|
||||
}
|
||||
|
||||
# Check if docker-compose.yml exists
|
||||
if [ ! -f "docker-compose.yml" ]; then
|
||||
print_error "docker-compose.yml not found!"
|
||||
exit 1
|
||||
fi
|
||||
ensure_file() {
|
||||
local file_path="$1"
|
||||
local message="$2"
|
||||
if [[ ! -f "$file_path" ]]; then
|
||||
error "$message"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
load_env() {
|
||||
local env_file="$1"
|
||||
ensure_file "$env_file" "Environment file not found: $env_file"
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$env_file"
|
||||
set +a
|
||||
}
|
||||
|
||||
require_prod_prerequisites() {
|
||||
load_env "$PROD_ENV_FILE"
|
||||
|
||||
if [[ -z "${DOMAIN:-}" || "${DOMAIN:-}" == "localhost" ]]; then
|
||||
error "DOMAIN must be set to a real domain for production."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${JWT_SECRET:-}" || "${JWT_SECRET:-}" == "dev_jwt_secret_key_change_in_production" || "${JWT_SECRET:-}" == "your-secret-key-change-in-production" ]]; then
|
||||
error "JWT_SECRET must be set to a strong non-default value in production."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if (( ${#JWT_SECRET} < 32 )); then
|
||||
error "JWT_SECRET must be at least 32 characters in production."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${BETTER_AUTH_SECRET:-}" || "${BETTER_AUTH_SECRET:-}" == "PLACEHOLDER_BETTER_AUTH_SECRET_CHANGE_ME_32CHARS_MIN" || ${#BETTER_AUTH_SECRET} -lt 32 ]]; then
|
||||
error "BETTER_AUTH_SECRET must be set to a strong non-placeholder value in production."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${BETTER_AUTH_INTERNAL_TOKEN:-}" || "${BETTER_AUTH_INTERNAL_TOKEN:-}" == "PLACEHOLDER_INTERNAL_AUTH_TOKEN" ]]; then
|
||||
error "BETTER_AUTH_INTERNAL_TOKEN must be set in production."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${COOKIE_SECURE:-false}" != "true" ]]; then
|
||||
error "COOKIE_SECURE must be true in production."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${TRAEFIK_AUTH:-}" ]]; then
|
||||
error "TRAEFIK_AUTH must be set (basic auth hash) for dashboard protection in production."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${CONTAINR_AGENT_AUTH_TOKEN:-}" && -z "${CONTAINR_AGENT_AUTH_TOKENS:-}" ]]; then
|
||||
error "CONTAINR_AGENT_AUTH_TOKEN or CONTAINR_AGENT_AUTH_TOKENS must be set in production."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to show help
|
||||
show_help() {
|
||||
echo "Usage: $0 [COMMAND]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " dev - Start development environment with hot reload"
|
||||
echo " prod - Start production environment"
|
||||
echo " cloudflare- Start production with Cloudflare tunnel"
|
||||
echo " stop - Stop all services"
|
||||
echo " logs - Show logs for all services"
|
||||
echo " status - Show status of all services"
|
||||
echo " clean - Remove all containers, volumes, and images"
|
||||
echo " help - Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 dev # Start development mode"
|
||||
echo " $0 prod # Start production mode"
|
||||
echo " $0 cloudflare # Start with Cloudflare tunnel"
|
||||
echo " $0 logs # View logs"
|
||||
cat <<'EOF'
|
||||
Usage: ./start-unified.sh <command>
|
||||
|
||||
Commands:
|
||||
dev Start the full local stack from docker-compose.yml
|
||||
prod Start the self-hosted production stack from infra/docker-compose.yml
|
||||
cloudflare Start the self-hosted production stack with the cloudflared profile
|
||||
stop Stop both local and self-hosted compose stacks
|
||||
logs Show logs for the local stack
|
||||
status Show compose status for both stacks
|
||||
config Validate both compose files
|
||||
clean Stop both stacks and remove volumes
|
||||
help Show this help message
|
||||
EOF
|
||||
}
|
||||
|
||||
# Function to start development environment
|
||||
start_dev() {
|
||||
print_status "Starting development environment..."
|
||||
|
||||
# Set development environment variables
|
||||
export ENVIRONMENT=development
|
||||
export LOG_LEVEL=DEBUG
|
||||
export DOMAIN=localhost
|
||||
export ACME_EMAIL=admin@localhost
|
||||
export DEV_MODE=./internal # Enable development volumes
|
||||
export VITE_API_URL=http://api.localhost
|
||||
export CORS_ALLOWED_ORIGINS=http://localhost,http://localhost:3000
|
||||
|
||||
# Stop existing containers
|
||||
docker compose down 2>/dev/null || true
|
||||
|
||||
# Start services
|
||||
docker compose up -d --build
|
||||
|
||||
print_success "Development environment started!"
|
||||
print_status "Frontend: http://localhost"
|
||||
print_status "API: http://api.localhost"
|
||||
print_status "Traefik Dashboard: http://localhost:8080"
|
||||
print_status "Traefik Auth: admin/admin"
|
||||
ensure_file "$LOCAL_ENV_FILE" "Missing $LOCAL_ENV_FILE. Copy .env.example to .env first."
|
||||
info "Starting local full stack with $LOCAL_COMPOSE_FILE"
|
||||
docker_compose --env-file "$LOCAL_ENV_FILE" -f "$LOCAL_COMPOSE_FILE" up -d --build
|
||||
success "Local stack is starting."
|
||||
}
|
||||
|
||||
# Function to start production environment
|
||||
start_prod() {
|
||||
print_status "Starting production environment..."
|
||||
|
||||
# Check if required environment variables are set
|
||||
if [ -z "$DOMAIN" ] || [ "$DOMAIN" = "localhost" ]; then
|
||||
print_error "Please set DOMAIN environment variable for production!"
|
||||
print_status "Example: export DOMAIN=yourdomain.com"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Unset development mode
|
||||
unset DEV_MODE
|
||||
|
||||
# Stop existing containers
|
||||
docker compose down 2>/dev/null || true
|
||||
|
||||
# Start services
|
||||
docker compose up -d --build
|
||||
|
||||
print_success "Production environment started!"
|
||||
print_status "Frontend: https://$DOMAIN"
|
||||
print_status "API: https://api.$DOMAIN"
|
||||
print_status "Traefik Dashboard: https://traefik.$DOMAIN"
|
||||
require_prod_prerequisites
|
||||
info "Starting self-hosted production stack with $SELFHOSTED_COMPOSE_FILE"
|
||||
docker_compose --env-file "$PROD_ENV_FILE" -f "$SELFHOSTED_COMPOSE_FILE" up -d --build
|
||||
success "Self-hosted production stack is starting."
|
||||
}
|
||||
|
||||
# Function to start with Cloudflare tunnel
|
||||
start_cloudflare() {
|
||||
print_status "Starting production environment with Cloudflare tunnel..."
|
||||
|
||||
# Check if Cloudflare token is set
|
||||
if [ -z "$CLOUDFLARED_TOKEN" ]; then
|
||||
print_error "Please set CLOUDFLARED_TOKEN environment variable!"
|
||||
print_status "Get token from: https://dash.cloudflare.com/argotunnel"
|
||||
require_prod_prerequisites
|
||||
if [[ -z "${CLOUDFLARED_TOKEN:-}" ]]; then
|
||||
error "CLOUDFLARED_TOKEN must be set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Unset development mode
|
||||
unset DEV_MODE
|
||||
|
||||
# Stop existing containers
|
||||
docker compose down 2>/dev/null || true
|
||||
|
||||
# Start services with cloudflared profile
|
||||
docker compose --profile cloudflared up -d --build
|
||||
|
||||
print_success "Production with Cloudflare tunnel started!"
|
||||
print_warning "Note: Cloudflare tunnel will expose your services publicly"
|
||||
print_status "Check Cloudflare dashboard for your tunnel URL"
|
||||
|
||||
info "Starting self-hosted production stack with Cloudflare tunnel"
|
||||
docker_compose --env-file "$PROD_ENV_FILE" -f "$SELFHOSTED_COMPOSE_FILE" --profile cloudflared up -d --build
|
||||
success "Cloudflare-enabled production stack is starting."
|
||||
}
|
||||
|
||||
# Function to stop services
|
||||
stop_services() {
|
||||
print_status "Stopping all services..."
|
||||
docker compose down
|
||||
print_success "All services stopped!"
|
||||
stop_all() {
|
||||
info "Stopping compose stacks"
|
||||
docker_compose --env-file "$LOCAL_ENV_FILE" -f "$LOCAL_COMPOSE_FILE" down --remove-orphans 2>/dev/null || true
|
||||
docker_compose --env-file "$PROD_ENV_FILE" -f "$SELFHOSTED_COMPOSE_FILE" --profile cloudflared down --remove-orphans 2>/dev/null || true
|
||||
success "Compose stacks stopped."
|
||||
}
|
||||
|
||||
# Function to show logs
|
||||
show_logs() {
|
||||
docker compose logs -f
|
||||
ensure_file "$LOCAL_ENV_FILE" "Missing $LOCAL_ENV_FILE. Copy .env.example to .env first."
|
||||
docker_compose --env-file "$LOCAL_ENV_FILE" -f "$LOCAL_COMPOSE_FILE" logs -f
|
||||
}
|
||||
|
||||
# Function to show status
|
||||
show_status() {
|
||||
print_status "Service status:"
|
||||
docker compose ps
|
||||
info "Local stack"
|
||||
docker_compose --env-file "$LOCAL_ENV_FILE" -f "$LOCAL_COMPOSE_FILE" ps 2>/dev/null || true
|
||||
info "Self-hosted production stack"
|
||||
docker_compose --env-file "$PROD_ENV_FILE" -f "$SELFHOSTED_COMPOSE_FILE" ps 2>/dev/null || true
|
||||
}
|
||||
|
||||
show_config() {
|
||||
ensure_file "$LOCAL_ENV_FILE" "Missing $LOCAL_ENV_FILE. Copy .env.example to .env first."
|
||||
ensure_file "$PROD_ENV_FILE" "Missing $PROD_ENV_FILE. Copy .env.production.example to .env.prod first."
|
||||
info "Validating local compose file"
|
||||
docker_compose --env-file "$LOCAL_ENV_FILE" -f "$LOCAL_COMPOSE_FILE" config -q
|
||||
info "Validating self-hosted production compose file"
|
||||
docker_compose --env-file "$PROD_ENV_FILE" -f "$SELFHOSTED_COMPOSE_FILE" config -q
|
||||
success "Compose configuration is valid."
|
||||
}
|
||||
|
||||
# Function to clean everything
|
||||
clean_all() {
|
||||
print_warning "This will remove ALL containers, volumes, and images!"
|
||||
read -p "Are you sure? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_status "Removing containers, volumes, and images..."
|
||||
docker compose down -v --rmi all
|
||||
docker system prune -f
|
||||
print_success "Cleanup complete!"
|
||||
else
|
||||
print_status "Cleanup cancelled."
|
||||
fi
|
||||
info "Removing local and self-hosted compose stacks with volumes"
|
||||
docker_compose --env-file "$LOCAL_ENV_FILE" -f "$LOCAL_COMPOSE_FILE" down -v --remove-orphans 2>/dev/null || true
|
||||
docker_compose --env-file "$PROD_ENV_FILE" -f "$SELFHOSTED_COMPOSE_FILE" --profile cloudflared down -v --remove-orphans 2>/dev/null || true
|
||||
success "Compose cleanup finished."
|
||||
}
|
||||
|
||||
# Main script logic
|
||||
case "${1:-help}" in
|
||||
dev)
|
||||
start_dev
|
||||
@@ -178,7 +176,7 @@ case "${1:-help}" in
|
||||
start_cloudflare
|
||||
;;
|
||||
stop)
|
||||
stop_services
|
||||
stop_all
|
||||
;;
|
||||
logs)
|
||||
show_logs
|
||||
@@ -186,6 +184,9 @@ case "${1:-help}" in
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
config)
|
||||
show_config
|
||||
;;
|
||||
clean)
|
||||
clean_all
|
||||
;;
|
||||
@@ -193,7 +194,7 @@ case "${1:-help}" in
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
print_error "Unknown command: $1"
|
||||
error "Unknown command: ${1}"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
|
||||
Reference in New Issue
Block a user