123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- #!/bin/bash
- # Startup script for ui-apt-mirror
- # This script handles the deployment and configuration of the apt-mirror container
- 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
- # Configuration
- IMAGE_NAME="ui-apt-mirror"
- CONTAINER_NAME="ui-apt-mirror"
- DIST_DIR="dist"
- # Function to print colored output
- print_status() {
- echo -e "${BLUE}[INFO]${NC} $1"
- }
- print_success() {
- echo -e "${GREEN}[SUCCESS]${NC} $1"
- }
- print_warning() {
- echo -e "${YELLOW}[WARNING]${NC} $1"
- }
- print_error() {
- echo -e "${RED}[ERROR]${NC} $1"
- }
- # Function to detect system architecture
- detect_architecture() {
- print_status "Detecting system architecture..." >&2
-
- local arch=$(uname -m)
- case $arch in
- x86_64)
- echo "amd64"
- ;;
- aarch64|arm64)
- echo "arm64"
- ;;
- *)
- print_error "Unsupported architecture: $arch"
- exit 1
- ;;
- esac
- }
- # Function to calculate optimal threads and connections based on RAM
- calculate_resource_limits() {
- print_status "Calculating optimal resource limits based on available RAM..."
-
- # Get total RAM in KB and convert to MB (fix for ARM64/OpenWrt)
- local total_ram_kb=$(free | awk 'NR==2{print $2}')
- local total_ram_mb=$((total_ram_kb / 1024))
-
- print_status "Total RAM detected: ${total_ram_mb}MB"
-
- # Calculate threads: 1 thread per 700MB RAM
- local calculated_threads=$((total_ram_mb / 700))
-
- # Ensure minimum of 1 thread and maximum of 8 threads
- if [ $calculated_threads -lt 1 ]; then
- calculated_threads=1
- elif [ $calculated_threads -gt 8 ]; then
- calculated_threads=8
- fi
-
- # Calculate connections: 6 connections per 700MB RAM
- local calculated_connections=$((6 * (total_ram_mb / 700)))
-
- # Ensure minimum of 6 connections and maximum of 48 connections
- if [ $calculated_connections -lt 6 ]; then
- calculated_connections=6
- elif [ $calculated_connections -gt 48 ]; then
- calculated_connections=48
- fi
-
- print_success "Calculated optimal settings:"
- print_success " - Threads: $calculated_threads (1 per 700MB RAM)"
- print_success " - Connections: $calculated_connections (6 per 700MB RAM)"
-
- # Set global variables
- OPTIMAL_THREADS=$calculated_threads
- OPTIMAL_CONNECTIONS=$calculated_connections
- }
- # Function to validate dist directory
- validate_dist() {
- local arch=$1
- local tar_file="${DIST_DIR}/${IMAGE_NAME}-${arch}.tar.gz"
-
- print_status "Validating distribution files..."
-
- if [ ! -d "$DIST_DIR" ]; then
- print_error "Distribution directory '$DIST_DIR' not found."
- print_error "Please run ./build.sh first to build the images."
- exit 1
- fi
-
- if [ ! -f "$tar_file" ]; then
- print_error "Image file '$tar_file' not found."
- print_error "Please run ./build.sh first to build the images."
- exit 1
- fi
-
- print_success "Found image file: $tar_file"
- }
- # Function to get user configuration
- get_user_config() {
- print_status "Getting user configuration..."
-
- # Default values
- local default_domain="mirror.intra"
- local default_sync_freq="14400"
- local default_admin_pass="admin"
-
- # Get custom domain
- echo ""
- read -p "Enter your custom domain (default: $default_domain): " custom_domain
- custom_domain=${custom_domain:-$default_domain}
-
- # Get sync frequency
- echo ""
- echo "Sync frequency options:"
- echo " 1. Every 4 hours"
- echo " 2. Every 12 hours"
- echo " 3. Every 24 hours"
- read -p "Select sync frequency (1-3, default: 1): " sync_choice
- sync_choice=${sync_choice:-1}
-
- # Convert choice to seconds
- case $sync_choice in
- 1)
- sync_freq="14400"
- ;;
- 2)
- sync_freq="43200"
- ;;
- 3)
- sync_freq="86400"
- ;;
- *)
- print_error "Invalid choice. Using default (Every 4 hours)."
- sync_freq="14400"
- ;;
- esac
-
- # Get admin password
- echo ""
- read -s -p "Enter admin password (default: $default_admin_pass): " admin_pass
- echo ""
- admin_pass=${admin_pass:-$default_admin_pass}
-
- # Detect host timezone
- local host_timezone=$(timedatectl show --property=Timezone --value 2>/dev/null || echo "UTC")
- echo ""
- read -p "Enter timezone (default: $host_timezone): " custom_timezone
- custom_timezone=${custom_timezone:-$host_timezone}
-
- # Set global variables for use in other functions
- MIRROR_DOMAIN="$custom_domain"
- ADMIN_DOMAIN="admin.$custom_domain"
- FILES_DOMAIN="files.$custom_domain"
- SYNC_FREQUENCY="$sync_freq"
- ADMIN_PASSWORD="$admin_pass"
- HOST_TIMEZONE="$custom_timezone"
-
- print_success "Configuration completed."
- }
- # Function to generate nginx htpasswd file
- generate_htpasswd() {
- local admin_pass=$1
-
- print_status "Generating nginx htpasswd file..."
-
- # Create nginx conf directory if it doesn't exist
- mkdir -p data/conf/nginx
-
- # Generate password hash and create htpasswd file
- local pass_hash=$(openssl passwd -apr1 "$admin_pass")
- echo "admin:$pass_hash" > data/conf/nginx/.htpasswd
-
- print_success "htpasswd file generated successfully."
- }
- # Function to generate docker-compose.yml from template
- generate_docker_compose() {
- local domain=$1
- local sync_freq=$2
- local timezone=$3
-
- print_status "Generating docker-compose.yml from template..."
-
- # Remove existing docker-compose.yml if it exists
- if [ -f "docker-compose.yml" ]; then
- print_status "Removing existing docker-compose.yml..."
- rm docker-compose.yml
- fi
-
- # Copy source template
- cp docker-compose.src.yml docker-compose.yml
-
- # Replace environment variable references with actual values
- sed -i "s/\${SYNC_FREQUENCY:-3600}/$sync_freq/g" docker-compose.yml
- sed -i "s/\${MIRROR_DOMAIN:-mirror.intra}/$domain/g" docker-compose.yml
- sed -i "s/\${ADMIN_DOMAIN:-admin.mirror.intra}/admin.$domain/g" docker-compose.yml
- sed -i "s/\${FILES_DOMAIN:-files.mirror.intra}/files.$domain/g" docker-compose.yml
-
- # Escape timezone for sed (replace / with \/)
- local escaped_timezone=$(echo "$timezone" | sed 's/\//\\\//g')
- sed -i "s/\${TZ:-UTC}/$escaped_timezone/g" docker-compose.yml
-
- print_success "docker-compose.yml generated successfully."
- }
- # Function to clean up previous installation
- cleanup_previous() {
- print_status "Cleaning up previous installation..."
-
- # Stop and remove existing container
- if docker ps -a --format "table {{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then
- print_status "Stopping existing container..."
- docker stop "$CONTAINER_NAME" 2>/dev/null || true
- print_status "Removing existing container..."
- docker rm "$CONTAINER_NAME" 2>/dev/null || true
- fi
-
- # Remove existing images
- if docker images --format "table {{.Repository}}" | grep -q "^${IMAGE_NAME}$"; then
- print_status "Removing existing images..."
- docker rmi "$IMAGE_NAME:latest" 2>/dev/null || true
- fi
-
- print_success "Cleanup completed."
- }
- # Function to create data directories
- create_data_dirs() {
- print_status "Creating data directories..."
-
- mkdir -p data/{data/apt-mirror,data/files,logs/apt-mirror,logs/nginx,conf/apt-mirror,conf/nginx/sites-available}
-
- # Set proper permissions
- chmod 755 data/
- chmod 755 data/*
-
- print_success "Data directories created."
- }
- # Function to generate apt-mirror2 configuration
- generate_mirror_config() {
- local domain=$1
-
- print_status "Generating apt-mirror2 configuration..."
-
- cat > data/conf/apt-mirror/mirror.list << EOF
- # apt-mirror2 configuration for $domain
- # Generated on $(date)
- # Set base_path to the directory where you want to store the mirror
- set base_path /var/spool/apt-mirror
- # Set mirror_path to the directory where you want to store the mirror
- set mirror_path \$base_path/mirror
- # Set skel_path to the directory where you want to store the skeleton
- set skel_path \$base_path/skel
- # Set var_path to the directory where you want to store the variable data
- set var_path \$base_path/var
- # Set cleanscript to the script that cleans the mirror
- set cleanscript \$var_path/clean.sh
- # Set defaultarch to the default architecture
- set defaultarch amd64
- # Set postmirror_script to the script that runs after mirroring
- set postmirror_script \$var_path/postmirror.sh
- # Set run_postmirror to 1 to run the postmirror script
- set run_postmirror 0
- # Set nthreads to the number of threads to use (calculated based on RAM)
- set nthreads $OPTIMAL_THREADS
- # Set _tilde to 1 to download tilde files
- set _tilde 0
- # Set timeout for downloads (in seconds)
- set _timeout 300
- # Set retry count for failed downloads
- set _retry 3
- # Set download speed limit (in bytes per second, 0 = unlimited)
- set _limit_rate 4194304
- # Set user agent for downloads
- set _user_agent "apt-mirror2/14"
- # Set number of connections per host (calculated based on RAM)
- set _max_connections $OPTIMAL_CONNECTIONS
- set release_files_retries 15
- # Ubuntu 24.04 (Noble Numbat) repositories - AMD64 architecture
- deb http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
- deb http://archive.ubuntu.com/ubuntu noble-updates main restricted universe multiverse
- deb http://archive.ubuntu.com/ubuntu noble-security main restricted universe multiverse
- deb http://archive.ubuntu.com/ubuntu noble-backports main restricted universe multiverse
- # Debian 12 (Bookworm) repositories - AMD64 and ARM64 architectures
- deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
- deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
- deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
- deb http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware
- deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
- deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
- deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
- deb-src http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware
- # Clean up old packages
- clean http://archive.ubuntu.com/ubuntu
- clean http://deb.debian.org/debian
- clean http://security.debian.org/debian-security
- EOF
-
- print_success "apt-mirror2 configuration generated with $OPTIMAL_THREADS threads and $OPTIMAL_CONNECTIONS connections."
- }
- # Function to show status
- show_status() {
- print_status "Container status:"
- docker ps --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
-
- echo ""
- print_status "Resource Configuration:"
- echo " Threads: $OPTIMAL_THREADS (1 per 700MB RAM)"
- echo " Connections: $OPTIMAL_CONNECTIONS (6 per 700MB RAM)"
-
- echo ""
- print_status "Access URLs:"
- if [ -f "docker-compose.yml" ]; then
- # Extract values from generated docker-compose.yml
- local mirror_domain=$(grep "MIRROR_DOMAIN" docker-compose.yml | sed 's/.*MIRROR_DOMAIN: //')
- local admin_domain=$(grep "ADMIN_DOMAIN" docker-compose.yml | sed 's/.*ADMIN_DOMAIN: //')
- local files_domain=$(grep "FILES_DOMAIN" docker-compose.yml | sed 's/.*FILES_DOMAIN: //')
-
- echo " Main Repository: http://$mirror_domain"
- echo " Admin Panel: http://$admin_domain (admin/[password])"
- echo " File Repository: http://$files_domain"
- else
- echo " Main Repository: http://mirror.intra"
- echo " Admin Panel: http://admin.mirror.intra (admin/[password])"
- echo " File Repository: http://files.mirror.intra"
- fi
-
- echo ""
- print_status "Logs:"
- echo " docker logs $CONTAINER_NAME"
- echo " docker compose -f docker-compose.yml logs"
- }
- # Function to show usage
- show_usage() {
- echo "Usage: $0 [OPTIONS]"
- echo ""
- echo "Options:"
- echo " --config-only Only generate configuration, don't start container"
- echo " --no-cleanup Skip cleanup of previous installation"
- echo " --help Show this help message"
- echo ""
- echo "This script will:"
- echo " 1. Detect your system architecture"
- echo " 2. Calculate optimal resource limits based on available RAM"
- echo " 3. Validate that required image files exist"
- echo " 4. Get your custom configuration"
- echo " 5. Clean up previous installation"
- echo " 6. Create data directories and generate configurations"
- echo " 7. Call start.sh to load image and start container"
- echo ""
- echo "Resource Calculation:"
- echo " - Threads: 1 per 700MB RAM (min: 1, max: 8)"
- echo " - Connections: 6 per 700MB RAM (min: 6, max: 48)"
- echo ""
- echo "Prerequisites:"
- echo " - Docker installed and running"
- echo " - Built images in dist/ directory (run ./build.sh first)"
- echo " - openssl for password hashing"
- }
- # Function to update nginx configuration files with custom domain
- update_nginx_configs() {
- local domain=$1
-
- print_status "Updating nginx configuration files with domain: $domain..."
-
- # Create nginx sites-available directory if it doesn't exist
- mkdir -p data/conf/nginx/sites-available
-
- # Replace domain in all nginx config files
- for config_file in data/conf/nginx/sites-available/*.conf; do
- if [ -f "$config_file" ]; then
- # Replace mirror.intra with custom domain
- sed -i "s/mirror\.intra/$domain/g" "$config_file"
- # Replace admin.mirror.intra with admin.customdomain
- sed -i "s/admin\.mirror\.intra/admin.$domain/g" "$config_file"
- # Replace files.mirror.intra with files.customdomain
- sed -i "s/files\.mirror\.intra/files.$domain/g" "$config_file"
- fi
- done
-
- print_success "Nginx configuration files updated with domain: $domain"
- }
- # Main execution
- main() {
- local config_only=false
- local no_cleanup=false
-
- # Parse command line arguments
- while [[ $# -gt 0 ]]; do
- case $1 in
- --config-only)
- config_only=true
- shift
- ;;
- --no-cleanup)
- no_cleanup=true
- shift
- ;;
- --help)
- show_usage
- exit 0
- ;;
- *)
- print_error "Unknown option: $1"
- show_usage
- exit 1
- ;;
- esac
- done
-
- print_status "Starting ui-apt-mirror deployment..."
-
- # Detect architecture
- local arch=$(detect_architecture)
- print_success "Detected architecture: $arch"
-
- # Calculate optimal resource limits
- calculate_resource_limits
-
- # Validate dist directory
- validate_dist "$arch"
-
- # Get user configuration
- get_user_config
-
- # Generate nginx htpasswd file
- generate_htpasswd "$ADMIN_PASSWORD"
-
- if [ "$config_only" = true ]; then
- print_success "Configuration completed. Run without --config-only to start the container."
- exit 0
- fi
-
- # Clean up previous installation
- if [ "$no_cleanup" = false ]; then
- cleanup_previous
- fi
-
- # Create data directories
- create_data_dirs
-
- # Generate apt-mirror configuration
- generate_mirror_config "$MIRROR_DOMAIN"
-
- # Generate docker-compose.yml
- generate_docker_compose "$MIRROR_DOMAIN" "$SYNC_FREQUENCY" "$HOST_TIMEZONE"
-
- # Update nginx configuration files with custom domain
- update_nginx_configs "$MIRROR_DOMAIN"
-
- # Start container using start.sh
- print_status "Starting container..."
- ./start.sh
-
- # Show status
- show_status
-
- print_success "Deployment completed successfully!"
- }
- # Run main function with all arguments
- main "$@"
|