Add authentik-install.sh
This commit is contained in:
parent
513e55e414
commit
4a8678f2b2
1 changed files with 388 additions and 0 deletions
388
authentik-install.sh
Normal file
388
authentik-install.sh
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script to install Docker and Authentik with verification and redeployment capabilities
|
||||||
|
# Must be run with root privileges
|
||||||
|
|
||||||
|
# Error handling
|
||||||
|
set -e
|
||||||
|
trap 'echo "Error on line $LINENO. Exit code: $?"' ERR
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
INSTALL_DIR="/docker/authentik"
|
||||||
|
COMPOSE_FILE="${INSTALL_DIR}/docker-compose.yml"
|
||||||
|
LOG_FILE="/var/log/authentik-install.log"
|
||||||
|
CONTAINER_NAME="authentik"
|
||||||
|
POSTGRES_PASSWORD=$(openssl rand -base64 32)
|
||||||
|
SECRET_KEY=$(openssl rand -base64 32)
|
||||||
|
ADMIN_PASSWORD=$(openssl rand -base64 12)
|
||||||
|
ADMIN_TOKEN=$(openssl rand -hex 32)
|
||||||
|
ADMIN_EMAIL="admin@example.com" # Default value, can be overridden
|
||||||
|
|
||||||
|
# Utility functions
|
||||||
|
check_port_availability() {
|
||||||
|
local port=$1
|
||||||
|
if lsof -i ":$port" >/dev/null 2>&1; then
|
||||||
|
local process_info=$(lsof -i ":$port" | tail -n 1)
|
||||||
|
local pid=$(echo "$process_info" | awk '{print $2}')
|
||||||
|
local process_name=$(echo "$process_info" | awk '{print $1}')
|
||||||
|
log_message "⚠ Error: Port $port is already in use by process $process_name (PID: $pid)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_required_ports() {
|
||||||
|
local required_ports=(9000 9443)
|
||||||
|
local ports_in_use=()
|
||||||
|
|
||||||
|
for port in "${required_ports[@]}"; do
|
||||||
|
if ! check_port_availability "$port"; then
|
||||||
|
ports_in_use+=($port)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#ports_in_use[@]} -ne 0 ]; then
|
||||||
|
log_message "The following required ports are already in use: ${ports_in_use[*]}"
|
||||||
|
log_message "Please free these ports before proceeding with the installation."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "✓ All required ports are available"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
log_message() {
|
||||||
|
local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
||||||
|
echo "$message"
|
||||||
|
echo "$message" >> "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_container_status() {
|
||||||
|
log_message "Current container status:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_service_status() {
|
||||||
|
local max_attempts=10
|
||||||
|
local attempt=1
|
||||||
|
local delay=30
|
||||||
|
|
||||||
|
while [ $attempt -le $max_attempts ]; do
|
||||||
|
log_message "Checking services (attempt $attempt/$max_attempts)..."
|
||||||
|
|
||||||
|
local all_services_running=true
|
||||||
|
local services=("server" "worker" "postgresql" "redis")
|
||||||
|
local failed_services=()
|
||||||
|
|
||||||
|
# Check each service
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
local container_name="authentik-${service}-1"
|
||||||
|
|
||||||
|
# Check if container exists and is running
|
||||||
|
if ! docker ps -q -f name="$container_name" >/dev/null 2>&1; then
|
||||||
|
failed_services+=("$service")
|
||||||
|
all_services_running=false
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check container status
|
||||||
|
local status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)
|
||||||
|
if [ "$status" != "running" ]; then
|
||||||
|
failed_services+=("$service")
|
||||||
|
all_services_running=false
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$all_services_running" = true ]; then
|
||||||
|
# All containers are running, now check if server is responding
|
||||||
|
log_message "All containers are running, checking web interface..."
|
||||||
|
|
||||||
|
# Give the web interface a few attempts to respond
|
||||||
|
for i in {1..3}; do
|
||||||
|
if curl -sf http://localhost:9000 >/dev/null 2>&1; then
|
||||||
|
log_message "Web interface is responding"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $attempt -lt $max_attempts ]; then
|
||||||
|
if [ ${#failed_services[@]} -ne 0 ]; then
|
||||||
|
log_message "Services still initializing: ${failed_services[*]}"
|
||||||
|
else
|
||||||
|
log_message "Waiting for web interface to become available..."
|
||||||
|
fi
|
||||||
|
sleep $delay
|
||||||
|
fi
|
||||||
|
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#failed_services[@]} -ne 0 ]; then
|
||||||
|
log_message "The following services failed to start: ${failed_services[*]}"
|
||||||
|
else
|
||||||
|
log_message "Web interface failed to respond"
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_installation() {
|
||||||
|
log_message "Verifying Authentik installation..."
|
||||||
|
|
||||||
|
if ! check_service_status; then
|
||||||
|
log_message "Authentik services are not running properly"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "Authentik services are running properly"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_docker_version() {
|
||||||
|
local current_version=$(docker --version | cut -d ' ' -f3 | cut -d ',' -f1)
|
||||||
|
log_message "Current Docker version: $current_version"
|
||||||
|
|
||||||
|
apt-get update >/dev/null 2>&1
|
||||||
|
local available_version=$(apt-cache policy docker-ce | grep Candidate | cut -d ' ' -f4)
|
||||||
|
|
||||||
|
if [ "$current_version" != "$available_version" ]; then
|
||||||
|
log_message "New Docker version available: $available_version"
|
||||||
|
read -p "Do you want to upgrade Docker? (y/N) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
redeploy_service() {
|
||||||
|
log_message "Redeploying Authentik..."
|
||||||
|
|
||||||
|
cd "$INSTALL_DIR"
|
||||||
|
docker compose down
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
local retries=0
|
||||||
|
while ! check_service_status && [ $retries -lt 5 ]; do
|
||||||
|
log_message "Waiting for Authentik to become healthy..."
|
||||||
|
sleep 30
|
||||||
|
retries=$((retries + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $retries -eq 5 ]; then
|
||||||
|
log_message "Failed to redeploy Authentik after 5 attempts"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "Authentik redeployed successfully"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_existing_data() {
|
||||||
|
if [ -d "$INSTALL_DIR" ]; then
|
||||||
|
local backup_dir="${INSTALL_DIR}_backup_$(date +%Y%m%d_%H%M%S)"
|
||||||
|
log_message "Creating backup of existing installation at $backup_dir"
|
||||||
|
cp -r "$INSTALL_DIR" "$backup_dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_existing_installation() {
|
||||||
|
log_message "Checking existing Authentik installation..."
|
||||||
|
|
||||||
|
if [ -f "$COMPOSE_FILE" ]; then
|
||||||
|
log_message "Existing installation found"
|
||||||
|
show_container_status
|
||||||
|
|
||||||
|
if verify_installation; then
|
||||||
|
log_message "✓ Authentik is running correctly"
|
||||||
|
log_message "✓ Authentik is accessible at http://localhost:9000"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log_message "⚠ Service issues detected. Starting recovery process..."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script execution starts here
|
||||||
|
|
||||||
|
# Check if script is run as root
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "Please run as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initialize log file
|
||||||
|
mkdir -p "$(dirname "$LOG_FILE")"
|
||||||
|
touch "$LOG_FILE"
|
||||||
|
log_message "Starting Authentik installation/verification script"
|
||||||
|
|
||||||
|
# Check if Docker is installed
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
log_message "Docker not found. Installing Docker..."
|
||||||
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||||
|
sh get-docker.sh
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y docker-compose-plugin
|
||||||
|
log_message "Docker installed successfully"
|
||||||
|
else
|
||||||
|
log_message "Docker already installed"
|
||||||
|
check_docker_version
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check existing installation or proceed with new installation
|
||||||
|
if check_existing_installation; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
if [ -f "$COMPOSE_FILE" ]; then
|
||||||
|
# Attempt to recover existing installation
|
||||||
|
backup_existing_data
|
||||||
|
|
||||||
|
if ! redeploy_service; then
|
||||||
|
log_message "Failed to redeploy Authentik. Manual intervention may be required."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# New installation
|
||||||
|
log_message "Starting new Authentik installation"
|
||||||
|
|
||||||
|
# Create installation directory
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
cd "$INSTALL_DIR"
|
||||||
|
|
||||||
|
# Check if required ports are available
|
||||||
|
if ! check_required_ports; then
|
||||||
|
log_message "⚠ Port conflict detected. Please resolve the conflicts and run the script again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create docker-compose.yml
|
||||||
|
cat > docker-compose.yml <<EOF
|
||||||
|
version: "3.4"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgresql:
|
||||||
|
image: docker.io/library/postgres:12
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -d authentik -U authentik"]
|
||||||
|
start_period: 20s
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
timeout: 5s
|
||||||
|
volumes:
|
||||||
|
- database:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_USER: authentik
|
||||||
|
POSTGRES_DB: authentik
|
||||||
|
networks:
|
||||||
|
- authentik
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: docker.io/library/redis:alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||||
|
start_period: 20s
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
timeout: 3s
|
||||||
|
networks:
|
||||||
|
- authentik
|
||||||
|
|
||||||
|
server:
|
||||||
|
image: ghcr.io/goauthentik/server:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
AUTHENTIK_SECRET_KEY: ${SECRET_KEY}
|
||||||
|
AUTHENTIK_BOOTSTRAP_PASSWORD: ${ADMIN_PASSWORD}
|
||||||
|
AUTHENTIK_BOOTSTRAP_TOKEN: ${ADMIN_TOKEN}
|
||||||
|
AUTHENTIK_BOOTSTRAP_EMAIL: ${ADMIN_EMAIL}
|
||||||
|
volumes:
|
||||||
|
- ./media:/media
|
||||||
|
- ./custom-templates:/templates
|
||||||
|
ports:
|
||||||
|
- "9000:9000"
|
||||||
|
- "9443:9443"
|
||||||
|
networks:
|
||||||
|
- authentik
|
||||||
|
depends_on:
|
||||||
|
- postgresql
|
||||||
|
- redis
|
||||||
|
|
||||||
|
worker:
|
||||||
|
image: ghcr.io/goauthentik/server:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
command: worker
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
AUTHENTIK_SECRET_KEY: ${SECRET_KEY}
|
||||||
|
volumes:
|
||||||
|
- ./media:/media
|
||||||
|
- ./certs:/certs
|
||||||
|
- ./custom-templates:/templates
|
||||||
|
networks:
|
||||||
|
- authentik
|
||||||
|
depends_on:
|
||||||
|
- postgresql
|
||||||
|
- redis
|
||||||
|
|
||||||
|
networks:
|
||||||
|
authentik:
|
||||||
|
name: authentik
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
database:
|
||||||
|
name: authentik_database
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create required directories
|
||||||
|
mkdir -p media custom-templates certs
|
||||||
|
chmod 777 media custom-templates certs
|
||||||
|
|
||||||
|
# Start services
|
||||||
|
log_message "Starting Authentik services..."
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# Give services time to initialize
|
||||||
|
log_message "Waiting for services to initialize (this may take several minutes)..."
|
||||||
|
log_message "Initial database setup and migrations may take some time on first run..."
|
||||||
|
sleep 60 # Give more initial time for first database setup
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
if verify_installation; then
|
||||||
|
log_message "✓ Installation completed successfully!"
|
||||||
|
show_container_status
|
||||||
|
|
||||||
|
log_message "Important next steps:"
|
||||||
|
log_message "1. Access Authentik at http://localhost:9000"
|
||||||
|
log_message "2. Store these credentials safely:"
|
||||||
|
log_message " Admin Email: ${ADMIN_EMAIL}"
|
||||||
|
log_message " Admin Password: ${ADMIN_PASSWORD}"
|
||||||
|
log_message " Admin API Token: ${ADMIN_TOKEN}"
|
||||||
|
log_message " PostgreSQL Password: ${POSTGRES_PASSWORD}"
|
||||||
|
log_message " Secret Key: ${SECRET_KEY}"
|
||||||
|
log_message "4. Set up a reverse proxy in CloudPanel"
|
||||||
|
log_message "5. Create SSL certificate for your domain"
|
||||||
|
else
|
||||||
|
log_message "Installation completed but services are not running properly"
|
||||||
|
log_message "Please check the logs and try redeploying the services"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
Loading…
Reference in a new issue