Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # Version
- VERSION="1.0"
- # Add this near the start of the script
- trap 'echo "Installation interrupted. Cleaning up..."; cleanup_installation; exit 1' INT TERM
- # Logging setup
- LOG_FILE="/var/log/openvpn_lb_installer.log"
- CLEANUP_ON_ERROR=true
- # Clear screen and show logo
- clear
- # ASCII Art Logo
- cat << 'EOF'
- _____ _ _ ____ _ ____
- / ____| | | | | _ \ | | | _ \
- | | | | __ _ _ _ __| | ___| |_) | __ _ __| | | |_) |
- | | | |/ _` | | | |/ _` |/ _ \ _ < / _` |/ _` | | _ <
- | |____| | (_| | |_| | (_| | __/ |_) | (_| | (_| |_ _| |_) |
- \_____|_|\__,_|\__,_|\__,_|\___|____/ \__,_|\__,_(_|_)____/
- OpenVPN Load Balancer Installer v${VERSION}
- Published by Naveed Alam Khan
- Powered by Anthropic's Claude AI
- =============================================================
- EOF
- # Function definitions
- setup_logging() {
- LOG_FILE="/var/log/openvpn_lb_installer.log"
- touch "$LOG_FILE"
- chmod 640 "$LOG_FILE"
- exec 1> >(tee -a "$LOG_FILE")
- exec 2> >(tee -a "$LOG_FILE" >&2)
- echo "$(date): Installation started" > "$LOG_FILE"
- }
- handle_error() {
- local error_code=$1
- local error_msg=$2
- local error_log="/var/log/openvpn_lb_installer_error.log" # Separate error log file
- echo "$(date): ERROR ($error_code) - $error_msg" | tee -a "$LOG_FILE" "$error_log"
- case $error_code in
- 1) echo "Fatal: System requirements not met" ;;
- 2) echo "Fatal: Network configuration failed" ;;
- 3) echo "Fatal: Container creation failed" ;;
- 4) echo "Fatal: OpenVPN configuration failed" ;;
- 5) echo "Fatal: Load balancer configuration failed" ;;
- *) echo "Unknown error occurred" ;;
- esac
- echo "Installation failed. Starting cleanup..."
- cleanup_installation
- exit "$error_code"
- }
- cleanup_installation() {
- echo "Cleaning up failed installation..."
- # Stop services
- systemctl stop keepalived 2>/dev/null
- systemctl disable keepalived 2>/dev/null
- # Remove containers
- for i in $(seq 1 "$NUM_CONTAINERS"); do
- echo "Removing container ovpn${i}..."
- lxc-stop -n "ovpn${i}" 2>/dev/null
- lxc-destroy -n "ovpn${i}" -f 2>/dev/null
- done
- # Remove network configuration
- echo "Removing network configuration..."
- ip link set lxcbr1 down 2>/dev/null
- ip link delete lxcbr1 2>/dev/null
- # Clean up iptables rules
- echo "Cleaning up firewall rules..."
- iptables -t nat -F
- iptables -F FORWARD
- # Remove configuration files
- echo "Removing configuration files..."
- rm -f /etc/keepalived/keepalived.conf
- rm -rf /etc/lxc/dnsmasq.conf
- rm -f /etc/network/if-up.d/iptables-rules
- rm -f /usr/local/bin/setup-iptables.sh
- # Remove systemd services
- echo "Removing systemd services..."
- rm -f /etc/systemd/system/openvpn-iptables.service
- systemctl daemon-reload
- # Optional: Remove logs
- echo "Cleaning up logs..."
- rm -f /var/log/openvpn-lb-installer.log
- rm -f /var/log/openvpn-lb-updates.log
- echo "Cleanup complete. System restored to pre-installation state."
- }
- check_root() {
- if [ "$(id -u)" != "0" ]; then
- handle_error 1 "This script must be run as root"
- fi
- }
- show_terms() {
- clear
- cat << "EOF"
- Terms and Conditions
- 1. This is an open-source installer for:
- - Keepalived IPVS load balancer
- - LXC containers with OpenVPN
- - Ubuntu 22.04 or higher required
- 2. Usage Agreement:
- - This software is provided "as is"
- - No warranty or guarantee is provided
- - For testing and educational purposes only
- - Use at your own risk
- 3. Components installed:
- - LXC containers
- - OpenVPN servers
- - Keepalived with IPVS
- - Required networking tools
- Do you accept these terms? (yes/no):
- EOF
- read -r accept
- if [[ ! "$accept" =~ ^[yY][eE]?[sS]?$ ]]; then
- echo "Terms must be accepted to continue."
- exit 1
- fi
- }
- show_progress() {
- local current=$1
- local total=$2
- local width=50
- local percentage=$((current * 100 / total))
- local completed=$((width * current / total))
- local remaining=$((width - completed))
- printf "\rProgress: ["
- printf "%${completed}s" | tr ' ' '='
- printf "%${remaining}s" | tr ' ' ' '
- printf "] %d%%" "$percentage"
- }
- check_system() {
- echo "Performing system checks..."
- if ! grep -q "Ubuntu" /etc/os-release; then
- handle_error 1 "This installer requires Ubuntu 22.04 or higher"
- fi
- mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
- if [ "$mem_total" -lt 2097152 ]; then
- handle_error 1 "Minimum 2GB RAM required"
- fi
- disk_space=$(df -BG / | awk 'NR==2 {print $4}' | tr -d 'G')
- if [ "$disk_space" -lt 10 ]; then
- handle_error 1 "Minimum 10GB free disk space required"
- fi
- }
- check_apparmor_selinux() {
- # Check if AppArmor is enabled and running
- if [[ $(systemctl is-active apparmor) == "active" ]]; then
- echo "AppArmor is enabled. Stopping and disabling it..."
- systemctl stop apparmor
- systemctl disable apparmor
- fi
- # Check if SELinux is enabled
- if [[ $(getenforce) != "Disabled" ]]; then
- echo "SELinux is enabled. Setting it to Permissive mode..."
- setenforce 0 # Set to Permissive mode
- fi
- }
- get_server_info() {
- clear
- echo "Server Configuration"
- echo "==================="
- read -p "Enter your server's public IPv4 address: " SERVER_IP
- read -p "Number of OpenVPN LXC containers (2-10): " NUM_CONTAINERS
- if [[ ! "$NUM_CONTAINERS" =~ ^[2-9]$|^10$ ]]; then
- handle_error 1 "Number of containers must be between 2 and 10"
- fi
- }
- show_install_menu() {
- clear
- cat << "EOF"
- Installation Options
- ==================
- 1. Express Install (Recommended)
- - Default configurations
- - Automatic IP assignment
- - Standard security settings
- 2. Custom Install
- - Choose container configurations
- - Custom IP ranges
- - Advanced security options
- 3. Expert Install
- - Full manual configuration
- - Custom network topology
- - Advanced load balancing options
- Select an option (1-3):
- EOF
- read -r install_type
- }
- get_certificate_info() {
- clear
- echo "OpenVPN Certificate Configuration"
- echo "================================"
- echo "Please provide the following information for your certificates."
- echo "Press Enter to use the default value shown in brackets."
- echo
- read -p "Country Code (2 letters) [US]: " CERT_COUNTRY
- CERT_COUNTRY=${CERT_COUNTRY:-US}
- read -p "State/Province [California]: " CERT_PROVINCE
- CERT_PROVINCE=${CERT_PROVINCE:-California}
- read -p "City [San Francisco]: " CERT_CITY
- CERT_CITY=${CERT_CITY:-San Francisco}
- read -p "Organization [OpenVPN-LB]: " CERT_ORG
- CERT_ORG=${CERT_ORG:-OpenVPN-LB}
- read -p "Email [admin@example.com]: " CERT_EMAIL
- CERT_EMAIL=${CERT_EMAIL:-admin@example.com}
- # Validate inputs
- if [[ ! $CERT_COUNTRY =~ ^[A-Za-z]{2}$ ]]; then
- handle_error 1 "Invalid country code. Must be exactly 2 letters."
- fi
- if [[ ! $CERT_EMAIL =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
- handle_error 1 "Invalid email address format."
- fi
- }
- install_dependencies() {
- echo "Installing required packages..."
- apt-get update &>/dev/null
- local packages=(lxc keepalived ipvsadm curl wget iptables)
- local total=${#packages[@]}
- local current=0
- for package in "${packages[@]}"; do
- current=$((current + 1))
- show_progress "$current" "$total"
- DEBIAN_FRONTEND=noninteractive apt-get install -y "$package" &>/dev/null
- done
- echo
- }
- setup_networking() {
- echo "Configuring network..."
- local base_port=1194
- local base_ip="10.0.5"
- # Check if bridge exists and remove if necessary
- if ip link show lxcbr1 >/dev/null 2>&1; then
- ip link set lxcbr1 down
- ip link delete lxcbr1
- fi
- # Create bridge network
- ip link add name lxcbr1 type bridge
- ip link set lxcbr1 up
- ip addr add "${base_ip}.254/24" dev lxcbr1
- # Enable IP forwarding
- echo 1 > /proc/sys/net/ipv4/ip_forward
- # Setup NAT (clear existing rules first)
- iptables -t nat -F
- iptables -t nat -A POSTROUTING -s "${base_ip}.0/24" ! -d "${base_ip}.0/24" -j MASQUERADE
- iptables -A FORWARD -i lxcbr1 -o eth0 -j ACCEPT
- iptables -A FORWARD -i eth0 -o lxcbr1 -j ACCEPT
- # Wait for network to be ready
- sleep 2
- # Add DNS configuration
- mkdir -p /etc/lxc
- cat > /etc/lxc/default.conf << EOF
- lxc.net.0.type = veth
- lxc.net.0.link = lxcbr1
- lxc.net.0.flags = up
- lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
- EOF
- # Ensure DNS resolving works in containers
- cat > /etc/lxc/dnsmasq.conf << EOF
- dhcp-range=10.0.5.2,10.0.5.253
- dhcp-option=3,10.0.5.254
- dhcp-option=6,1.1.1.1,1.0.0.1
- EOF
- }
- create_containers() {
- local num_containers=$1
- echo "Creating $num_containers OpenVPN containers..."
- local total=$num_containers
- local current=0
- for i in $(seq 1 "$num_containers"); do
- if lxc-info -n "ovpn${i}" >/dev/null 2>&1; then
- echo "Container ovpn${i} already exists. Stopping and deleting it..."
- lxc-stop -n "ovpn${i}" 2>/dev/null
- lxc-destroy -n "ovpn${i}" 2>/dev/null
- fi
- done
- for i in $(seq 1 "$num_containers"); do
- current=$((current + 1))
- show_progress "$current" "$total"
- # Remove existing container if any
- lxc-stop -n "ovpn${i}" 2>/dev/null
- lxc-destroy -n "ovpn${i}" 2>/dev/null
- # Create new container
- lxc-create -n "ovpn${i}" -t download -- -d ubuntu -r jammy -a amd64 &>/dev/null
- # Configure container
- configure_container "ovpn${i}" "$i"
- # Start container and wait for it to be ready
- lxc-start -n "ovpn${i}"
- sleep 30 # Give more time for container to initialize
- # Check container state
- lxc-info -n "ovpn${i}" -s | grep -q "RUNNING" || handle_error 2 "Container ovpn${i} failed to start"
- # Add this line here (for debugging):
- lxc-attach -n "ovpn${i}" -- bash -c 'echo $RESOLV_CONF'
- # Check if resolv.conf exists
- if [ ! -f "/var/lib/lxc/ovpn${i}/rootfs/etc/resolv.conf" ]; then
- handle_error 2 "resolv.conf not found in container ovpn${i}"
- fi
- # Set up DNS in running container
- lxc-attach -n "ovpn${i}" -- bash -c '
- mkdir -p /etc
- touch /etc/resolv.conf
- echo "nameserver 1.1.1.1" > /etc/resolv.conf
- echo "nameserver 1.0.0.1" >> /etc/resolv.conf
- '
- # Test network connectivity
- lxc-attach -n "ovpn${i}" -- ping -c 1 8.8.8.8 || handle_error 2 "Container network setup failed"
- done
- echo
- }
- configure_container() {
- local container=$1
- local index=$2
- local base_ip="10.0.5"
- # Configure container networking
- cat > "/var/lib/lxc/$container/config" << EOF
- lxc.net.0.type = veth
- lxc.net.0.link = lxcbr1
- lxc.net.0.flags = up
- lxc.net.0.ipv4.address = ${base_ip}.${index}/24
- lxc.net.0.ipv4.gateway = ${base_ip}.254
- lxc.net.0.name = eth0
- lxc.start.auto = 1
- lxc.uts.name = $container
- # Common configuration
- lxc.include = /usr/share/lxc/config/ubuntu.common.conf
- lxc.arch = linux64
- lxc.rootfs.path = dir:/var/lib/lxc/$container/rootfs
- # Make it privileged
- lxc.apparmor.profile = unconfined
- lxc.cgroup2.devices.allow = a
- lxc.mount.auto = proc sys cgroup
- # TUN/TAP device
- lxc.mount.entry = /dev/net/tun /var/lib/lxc/$container/rootfs/dev/net/tun none bind,create=file
- EOF
- # Setup DNS in container
- mkdir -p "/var/lib/lxc/$container/rootfs/etc"
- cat > "/var/lib/lxc/$container/rootfs/etc/resolv.conf" << EOF
- nameserver 1.1.1.1
- nameserver 1.0.0.1
- EOF
- }
- setup_openvpn() {
- local container=$1
- local index=$2
- local base_port=1194
- # Install OpenVPN and Easy-RSA
- lxc-attach -n "$container" -- bash -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y openvpn easy-rsa net-tools"
- # Create required directories
- lxc-attach -n "$container" -- bash -c "mkdir -p /etc/openvpn/server"
- # Set up Easy-RSA and generate certificates
- lxc-attach -n "$container" -- bash -c "
- mkdir -p /etc/openvpn/easy-rsa
- cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
- cd /etc/openvpn/easy-rsa
- # Create vars file
- cat > vars << EOF
- set_var EASYRSA_REQ_COUNTRY \"${CERT_COUNTRY}\"
- set_var EASYRSA_REQ_PROVINCE \"${CERT_PROVINCE}\"
- set_var EASYRSA_REQ_CITY \"${CERT_CITY}\"
- set_var EASYRSA_REQ_ORG \"${CERT_ORG}\"
- set_var EASYRSA_REQ_EMAIL \"${CERT_EMAIL}\"
- set_var EASYRSA_REQ_OU \"VPN Service\"
- set_var EASYRSA_REQ_CN \"OpenVPN-Server-${index}\"
- set_var EASYRSA_BATCH \"yes\"
- EOF
- # Initialize PKI and generate certificates
- ./easyrsa init-pki
- ./easyrsa --batch build-ca nopass
- ./easyrsa --batch build-server-full server nopass
- ./easyrsa gen-dh
- openvpn --genkey secret ta.key
- # Copy files to OpenVPN directory
- cp pki/ca.crt /etc/openvpn/server/
- cp pki/issued/server.crt /etc/openvpn/server/
- cp pki/private/server.key /etc/openvpn/server/
- cp pki/dh.pem /etc/openvpn/server/
- cp ta.key /etc/openvpn/server/
- "
- # Configure OpenVPN (Corrected part)
- lxc-attach -n "$container" -- bash -c "cat > /etc/openvpn/server/server.conf << 'EOF'
- port $((base_port + index - 1))
- proto tcp
- dev tun
- topology subnet
- ca /etc/openvpn/server/ca.crt
- cert /etc/openvpn/server/server.crt
- key /etc/openvpn/server/server.key
- dh /etc/openvpn/server/dh.pem
- server 10.$((7 + index)).0.0 255.255.255.0
- push \"redirect-gateway def1 bypass-dhcp\"
- push \"dhcp-option DNS 1.1.1.1\"
- push \"dhcp-option DNS 1.0.0.1\"
- duplicate-cn
- keepalive 10 120
- tls-auth /etc/openvpn/server/ta.key 0
- cipher AES-256-GCM
- auth SHA256
- user nobody
- group nogroup
- persist-key
- persist-tun
- status openvpn-status.log
- verb 4
- log /var/log/openvpn.log
- EOF"
- # Set proper permissions
- lxc-attach -n "$container" -- bash -c "
- chmod 644 /etc/openvpn/server/ca.crt
- chmod 644 /etc/openvpn/server/server.crt
- chmod 600 /etc/openvpn/server/server.key
- chmod 644 /etc/openvpn/server/dh.pem
- chmod 600 /etc/openvpn/server/ta.key
- "
- # Start OpenVPN service
- lxc-attach -n "$container" -- systemctl enable openvpn-server@server
- lxc-attach -n "$container" -- systemctl start openvpn-server@server
- # Wait a moment for the service to start
- sleep 5
- # Verify service is running
- lxc-attach -n "$container" -- systemctl status openvpn-server@server || handle_error 4 "OpenVPN service failed to start in $container"
- }
- setup_keepalived() {
- echo "Configuring load balancer..."
- local num_containers=$1
- cat > /etc/keepalived/keepalived.conf << EOF
- global_defs {
- router_id LVS_MAIN
- }
- virtual_server ${SERVER_IP} 1194 {
- delay_loop 3
- lb_algo rr
- lb_kind NAT
- protocol UDP
- persistence_timeout 50
- EOF
- for i in $(seq 1 "$num_containers"); do
- cat >> /etc/keepalived/keepalived.conf << EOF
- real_server 10.0.5.${i} $((1193 + i)) {
- weight 1
- UDP_CHECK {
- connect_timeout 3
- retry 3
- }
- }
- EOF
- done
- echo "}" >> /etc/keepalived/keepalived.conf
- }
- create_backup() {
- local backup_dir="/opt/openvpn-lb/backups"
- local config_dir="/etc/openvpn-lb"
- local backup_file="$backup_dir/backup-$(date +%Y%m%d-%H%M%S).tar.gz"
- # Create necessary directories
- mkdir -p "$backup_dir"
- mkdir -p "$config_dir"
- echo "Creating backup..."
- tar -czf "$backup_file" \
- /etc/keepalived/keepalived.conf \
- /var/lib/lxc/ovpn* \
- 2>/dev/null
- if [ $? -eq 0 ]; then
- echo "Backup created: $backup_file"
- return 0
- else
- handle_error 6 "Backup creation failed"
- return 1
- fi
- }
- setup_auto_updates() {
- cat > /usr/local/bin/openvpn-lb-update.sh << 'EOF'
- #!/bin/bash
- LOG_FILE="/var/log/openvpn-lb-updates.log"
- echo "Starting update at $(date)" >> "$LOG_FILE"
- # Function to perform updates
- do_update() {
- case $UPDATE_POLICY in
- 1) apt-get update && apt-get install -y --only-upgrade linux-firmware openssl ;;
- 2) apt-get update && apt-get upgrade -y ;;
- 3) apt-get update && apt-get upgrade -y
- apt-get install -y --only-upgrade openvpn keepalived ;;
- 4) apt-get update && apt-get dist-upgrade -y ;;
- esac
- }
- # Perform update
- do_update >> "$LOG_FILE" 2>&1
- # Restart services if needed
- if [ $? -eq 0 ]; then
- systemctl restart keepalived
- for i in $(seq 1 "$NUM_CONTAINERS"); do
- lxc-attach -n "ovpn${i}" -- systemctl restart openvpn-server@server
- done
- fi
- EOF
- chmod +x /usr/local/bin/openvpn-lb-update.sh
- echo "0 3 * * * /usr/local/bin/openvpn-lb-update.sh" > /etc/cron.d/openvpn-lb-updates
- }
- setup_performance_tuning() {
- # Optimize sysctl settings
- cat > /etc/sysctl.d/99-network-tuning.conf << 'EOF'
- # TCP settings
- net.ipv4.tcp_fin_timeout = 30
- net.ipv4.tcp_keepalive_time = 1200
- net.ipv4.tcp_max_syn_backlog = 4096
- net.ipv4.tcp_rmem = 4096 87380 16777216
- net.ipv4.tcp_wmem = 4096 87380 16777216
- # UDP settings
- net.core.rmem_max = 16777216
- net.core.wmem_max = 16777216
- net.core.netdev_max_backlog = 5000
- # Network interface settings
- net.core.somaxconn = 65535
- EOF
- sysctl -p /etc/sysctl.d/99-network-tuning.conf
- # Optimize system limits
- cat > /etc/security/limits.d/openvpn-lb.conf << 'EOF'
- * soft nofile 65535
- * hard nofile 65535
- * soft nproc 65535
- * hard nproc 65535
- EOF
- }
- test_system_requirements() {
- # Check if the system has at least 2 GB of RAM and 10 GB of free disk space.
- if [[ $(free -m | awk '/^Mem:/{print $2}') -lt 2048 ]]; then
- return 1 # Not enough RAM
- fi
- # Get disk space in GB, handling different units (G, M, K)
- local disk_space=$(df -h / | awk '$NF=="/" {print $4}')
- local disk_gb=$(echo "$disk_space" | sed 's/G$//;s/M$/\/1024/;s/K$/\/1024\/1024/')
- disk_gb=$(echo "$disk_gb" | bc -l) # Calculate the value in GB
- if (( $(echo "$disk_gb < 10" | bc -l) )); then
- return 1 # Not enough disk space
- fi
- return 0 # System requirements met
- }
- test_network_config() {
- # Test bridge interface
- ip link show lxcbr1 >/dev/null 2>&1 || return 1
- # Test NAT
- iptables -t nat -C POSTROUTING -s 10.0.5.0/24 ! -d 10.0.5.0/24 -j MASQUERADE >/dev/null 2>&1 || return 1
- return 0
- }
- test_container_setup() {
- local containers_ok=true
- for i in $(seq 1 "$NUM_CONTAINERS"); do
- lxc-info -n "ovpn${i}" -s | grep -q "RUNNING" || containers_ok=false
- done
- $containers_ok
- }
- run_tests() {
- echo "Running system tests..."
- local tests_passed=true
- # Test system requirements
- if ! test_system_requirements; then
- echo "System requirements test failed"
- tests_passed=false
- fi
- # Test network configuration
- if ! test_network_config; then
- echo "Network configuration test failed"
- tests_passed=false
- fi
- # Test container setup
- if ! test_container_setup; then
- echo "Container setup test failed"
- tests_passed=false
- fi
- $tests_passed
- }
- show_status() {
- clear
- cat << "EOF"
- OpenVPN Load Balancer Status
- ===========================
- EOF
- echo "Load Balancer Status:"
- systemctl status keepalived | grep Active
- echo -e "\nContainer Status:"
- lxc-ls -f
- echo -e "\nConnection Statistics:"
- ipvsadm -Ln --stats
- echo -e "\nLast 5 log entries:"
- tail -n 5 "$LOG_FILE"
- }
- # Main installation function
- install_openvpn_lb() {
- clear
- check_root
- setup_logging
- show_terms
- check_apparmor_selinux
- check_system
- get_server_info
- show_install_menu
- # Add certificate info collection here
- if [ "$install_type" = "1" ]; then
- echo "Using default certificate settings..."
- else
- get_certificate_info
- fi
- # Start installation
- install_dependencies
- setup_networking
- create_containers "$NUM_CONTAINERS"
- # Configure each container
- for i in $(seq 1 "$NUM_CONTAINERS"); do
- setup_openvpn "ovpn${i}" "$i"
- done
- setup_keepalived "$NUM_CONTAINERS"
- setup_performance_tuning
- setup_auto_updates
- # Run tests
- run_tests
- # Create initial backup
- create_backup
- # Start services
- systemctl restart keepalived
- # Final status check
- show_status
- # Show completion message
- clear
- cat << "EOF"
- Installation Complete!
- =====================
- Your OpenVPN Load Balancer has been successfully installed.
- Summary:
- - Containers created: ${NUM_CONTAINERS}
- - Load balancer: Active
- - Status: Running
- Management:
- - Load balancer status: systemctl status keepalived
- - Container status: lxc-ls -f
- - Logs: /var/log/openvpn_lb_installer.log
- Thank you for using ClaudePro LB!
- EOF
- }
- # Start the installer
- install_openvpn_lb
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement