#!/bin/bash #═══════════════════════════════════════════════════════════════════════════════ # Professional Tailscale Setup Script # Author: Федя # Description: Complete automated Tailscale setup for Proxmox LXC container # Purpose: Secure access to home network and Docker containers from anywhere # Version: 2.0 #═══════════════════════════════════════════════════════════════════════════════ set -e #═══════════════════════════════════════════════════════════════════════════════ # Configuration #═══════════════════════════════════════════════════════════════════════════════ # Your local network that you want to access remotely LOCAL_NETWORK="10.110.110.0/24" # Parameters (can be set via environment variables) HOSTNAME="${HOSTNAME:-proxmox-vpn}" EXIT_NODE="${EXIT_NODE:-true}" SKIP_STEPS="${SKIP_STEPS:-}" # Logging LOG_FILE="/var/log/tailscale-setup.log" exec > >(tee -a "$LOG_FILE") 2>&1 # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' MAGENTA='\033[0;35m' NC='\033[0m' #═══════════════════════════════════════════════════════════════════════════════ # Helper Functions #═══════════════════════════════════════════════════════════════════════════════ print_header() { echo -e "\n${CYAN}═══════════════════════════════════════════════════════════════${NC}" echo -e "${CYAN}$1${NC}" echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}\n" } 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 "${MAGENTA}➜ $1${NC}" } log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" } check_root() { if [[ $EUID -ne 0 ]]; then print_error "Този скрипт трябва да се изпълни като root!" echo "Използвайте: sudo bash $0" log_message "ERROR: Script run without root privileges" exit 1 fi log_message "Root check passed" } check_os() { print_step "Проверка на операционната система..." if [[ ! -f /etc/debian_version ]] && [[ ! -f /etc/ubuntu-release ]]; then print_error "Този скрипт поддържа само Debian/Ubuntu системи" log_message "ERROR: Unsupported OS detected" exit 1 fi OS_VERSION=$(lsb_release -d | cut -f2) print_success "Поддържана OS: $OS_VERSION" log_message "OS check passed: $OS_VERSION" } check_tun() { print_step "Проверка на TUN устройството..." if [ ! -e /dev/net/tun ]; then print_error "TUN устройството не е налично!" print_warning "В Proxmox: Container Options → Features → TUN (трябва да е активирано)" log_message "ERROR: TUN device not available" exit 1 fi print_success "TUN устройството е налично" log_message "TUN device check passed" } check_existing_routes() { print_step "Проверка за съществуващи routes..." if ip route show table 52 2>/dev/null | grep -q "$LOCAL_NETWORK"; then print_warning "Route за $LOCAL_NETWORK вече съществува" log_message "Existing route found for $LOCAL_NETWORK" return 1 fi print_success "Няма съществуващи routes за $LOCAL_NETWORK" log_message "No existing routes found for $LOCAL_NETWORK" return 0 } should_skip_step() { local step=$1 if [[ "$SKIP_STEPS" == *"$step"* ]]; then log_message "Skipping step: $step" return 0 fi return 1 } #═══════════════════════════════════════════════════════════════════════════════ # Main Installation Functions #═══════════════════════════════════════════════════════════════════════════════ install_tailscale() { if should_skip_step "install"; then print_info "Прескачане на инсталацията на Tailscale" return fi print_header "Инсталиране на Tailscale" if command -v tailscale &>/dev/null; then print_info "Tailscale вече е инсталиран" tailscale version log_message "Tailscale already installed" return fi print_step "Добавяне на Tailscale repository..." # Install using official repository (more secure than curl | sh) curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg | \ tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list | \ tee /etc/apt/sources.list.d/tailscale.list >/dev/null print_step "Актуализиране на пакетите и инсталиране на Tailscale..." apt-get update -qq apt-get install -y tailscale if [ $? -eq 0 ]; then print_success "Tailscale е инсталиран успешно!" log_message "Tailscale installed successfully" tailscale version else print_error "Грешка при инсталирането на Tailscale" log_message "ERROR: Tailscale installation failed" exit 1 fi } configure_ip_forwarding() { if should_skip_step "ip_forwarding"; then print_info "Прескачане на IP forwarding конфигурацията" return fi print_header "Конфигуриране на IP forwarding" print_step "Активиране на IP forwarding..." # Enable IPv4 forwarding (only if not already enabled) if ! grep -q "net.ipv4.ip_forward = 1" /etc/sysctl.conf; then echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.conf fi if ! grep -q "net.ipv6.conf.all.forwarding = 1" /etc/sysctl.conf; then echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.conf fi # Apply changes sysctl -p print_success "IP forwarding е активирано" log_message "IP forwarding configured" } setup_tailscale() { if should_skip_step "setup"; then print_info "Прескачане на Tailscale setup" return fi print_header "Конфигуриране на Tailscale" print_info "Конфигурационни параметри:" echo -e " ${CYAN}Hostname:${NC} ${GREEN}$HOSTNAME${NC}" echo -e " ${CYAN}Subnet:${NC} ${GREEN}$LOCAL_NETWORK${NC}" echo -e " ${CYAN}Exit Node:${NC} ${GREEN}$EXIT_NODE${NC}" echo "" print_info "Сега ще се отвори браузър за автентикация в Tailscale" print_info "Ако браузърът не се отвори автоматично, копирай линка от терминала" echo "" print_step "Стартиране на Tailscale като subnet router..." print_warning "Важно: Тази машина ще рутира трафик за целия $LOCAL_NETWORK" echo "" # Build the command based on parameters TS_CMD="tailscale up --advertise-routes=$LOCAL_NETWORK --accept-routes --hostname=$HOSTNAME" if [ "$EXIT_NODE" = "true" ]; then TS_CMD="$TS_CMD --advertise-exit-node" fi log_message "Executing Tailscale setup: $TS_CMD" # Execute Tailscale setup if eval "$TS_CMD"; then print_success "Tailscale е конфигуриран успешно!" log_message "Tailscale setup completed successfully" else print_error "Грешка при конфигурирането на Tailscale" log_message "ERROR: Tailscale setup failed" exit 1 fi } approve_routes() { if should_skip_step "approve"; then print_info "Прескачане на одобрението на routes" return fi print_header "Важна стъпка - одобряване на subnet routes" echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW}ВАЖНО: Трябва да одобриш subnet routes в Tailscale Admin Console!${NC}" echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}\n" print_info "Следвай тези стъпки:" echo -e "${CYAN}1.${NC} Отвори: ${GREEN}https://login.tailscale.com/admin/machines${NC}" echo -e "${CYAN}2.${NC} Намери устройството ${GREEN}$HOSTNAME${NC}" echo -e "${CYAN}3.${NC} Кликни на трите точки ${GREEN}(...)${NC} до името" echo -e "${CYAN}4.${NC} Избери ${GREEN}Edit route settings...${NC}" echo -e "${CYAN}5.${NC} Активирай ${GREEN}$LOCAL_NETWORK${NC} (subnet routes)" if [ "$EXIT_NODE" = "true" ]; then echo -e "${CYAN}6.${NC} Активирай ${GREEN}Use as exit node${NC}" fi echo "" # Check if routes are already approved if check_existing_routes; then print_info "Routes все още не са одобрени. Чакам одобрение..." else print_success "Routes вече са одобрени!" return fi read -p "Натисни Enter след като завършиш одобрението..." # Verify routes were approved if check_existing_routes; then print_warning "Routes все още не са одобрени. Провери в Admin Console." read -p "Натисни Enter, когато routes са одобрени, или Ctrl+C за изход..." fi print_success "Routes са одобрени" log_message "Routes approved in Tailscale admin" } get_tailscale_info() { print_header "Информация за Tailscale мрежата" # Get Tailscale IP TAILSCALE_IP=$(tailscale ip -4) TAILSCALE_IP6=$(tailscale ip -6) echo -e "${CYAN}Tailscale IPv4:${NC} ${GREEN}$TAILSCALE_IP${NC}" echo -e "${CYAN}Tailscale IPv6:${NC} ${GREEN}$TAILSCALE_IP6${NC}" echo -e "${CYAN}Hostname:${NC} ${GREEN}$HOSTNAME${NC}" echo -e "${CYAN}Subnet Routes:${NC} ${GREEN}$LOCAL_NETWORK${NC}" echo -e "${CYAN}Exit Node:${NC} ${GREEN}$EXIT_NODE${NC}" echo "" print_step "Показване на всички устройства в мрежата..." tailscale status log_message "Tailscale info displayed - IP: $TAILSCALE_IP" } create_management_script() { print_header "Създаване на management скрипт" cat > /usr/local/bin/tailscale-info <<'SCRIPT' #!/bin/bash GREEN='\033[0;32m' CYAN='\033[0;36m' YELLOW='\033[1;33m' NC='\033[0m' echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}" echo -e "${CYAN}Tailscale Network Information${NC}" echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}\n" echo -e "${GREEN}Your Tailscale IPs:${NC}" echo -e " IPv4: $(tailscale ip -4)" echo -e " IPv6: $(tailscale ip -6)" echo "" echo -e "${GREEN}Status:${NC}" tailscale status echo "" echo -e "${GREEN}Advertised Routes:${NC}" ip route show table 52 2>/dev/null || echo " No routes found" echo "" echo -e "${YELLOW}Useful commands:${NC}" echo -e " ${CYAN}tailscale status${NC} - Show all devices" echo -e " ${CYAN}tailscale ping ${NC} - Ping another device" echo -e " ${CYAN}tailscale netcheck${NC} - Check connectivity" echo -e " ${CYAN}tailscale up${NC} - Reconnect" echo -e " ${CYAN}tailscale down${NC} - Disconnect" echo -e " ${CYAN}tailscale logout${NC} - Logout" SCRIPT chmod +x /usr/local/bin/tailscale-info print_success "Management скрипт създаден: tailscale-info" log_message "Management script created: /usr/local/bin/tailscale-info" } test_connectivity() { print_header "Тестване на връзката" print_step "Проверка на Tailscale connectivity..." tailscale netcheck echo "" # Test if we can ping ourselves if TAILSCALE_IP=$(tailscale ip -4); then print_step "Тестване на връзка до себе си ($TAILSCALE_IP)..." if ping -c 2 -W 1 "$TAILSCALE_IP" &>/dev/null; then print_success "Успешен ping до собствената Tailscale IP" else print_warning "Неуспешен ping до собствената Tailscale IP" fi fi print_info "Tailscale е готов за употреба!" log_message "Connectivity test completed" } print_final_summary() { print_header "Инсталацията е завършена успешно! 🎉" TAILSCALE_IP=$(tailscale ip -4) echo -e "${GREEN}📊 Конфигурация:${NC}\n" echo -e "${CYAN}Tailscale IP:${NC} ${GREEN}$TAILSCALE_IP${NC}" echo -e "${CYAN}Subnet Router:${NC} ${GREEN}$LOCAL_NETWORK${NC}" echo -e "${CYAN}Hostname:${NC} ${GREEN}$HOSTNAME${NC}" echo -e "${CYAN}Exit Node:${NC} ${GREEN}$EXIT_NODE${NC}" echo -e "${CYAN}Log File:${NC} ${GREEN}$LOG_FILE${NC}\n" echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW}📱 Следващи стъпки:${NC}\n" echo -e "${CYAN}1. На телефона/лаптопа:${NC}" echo -e " • Инсталирай Tailscale app от:" echo -e " - iOS: ${GREEN}App Store${NC}" echo -e " - Android: ${GREEN}Google Play${NC}" echo -e " - Windows/Mac/Linux: ${GREEN}https://tailscale.com/download${NC}" echo -e " • Логни се със ${GREEN}същия акаунт${NC}\n" echo -e "${CYAN}2. Достъп до локалната мрежа:${NC}" echo -e " • От телефона/лаптопа можеш директно да достъпваш:" echo -e " ${GREEN}10.110.110.x${NC} - всички устройства в локалната мрежа" echo -e " ${GREEN}$TAILSCALE_IP${NC} - този Proxmox контейнер\n" echo -e "${CYAN}3. Достъп до Docker контейнери:${NC}" echo -e " • Ако имаш Docker на ${GREEN}10.110.110.x${NC}" echo -e " • Директно отваряш: ${GREEN}http://10.110.110.x:port${NC}\n" if [ "$EXIT_NODE" = "true" ]; then echo -e "${CYAN}4. Exit Node:${NC}" echo -e " • За да използваш като VPN за целия интернет трафик:" echo -e " • В Tailscale app: Settings → ${GREEN}Use exit node → $HOSTNAME${NC}\n" fi echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW}🔧 Полезни команди:${NC}\n" echo -e " ${GREEN}tailscale-info${NC} - Показва информация за мрежата" echo -e " ${GREEN}tailscale status${NC} - Показва всички устройства" echo -e " ${GREEN}tailscale ping ${NC} - Тества връзка до устройство" echo -e " ${GREEN}tailscale netcheck${NC} - Проверява connectivity" echo -e " ${GREEN}tailscale up${NC} - Свързва се отново" echo -e " ${GREEN}tailscale down${NC} - Изключва се от мрежата\n" echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW}💡 Предимства пред OpenVPN:${NC}\n" echo -e " ${GREEN}✓${NC} Не трябва статично IP" echo -e " ${GREEN}✓${NC} Не трябва port forwarding" echo -e " ${GREEN}✓${NC} Автоматично се reconnect-ва" echo -e " ${GREEN}✓${NC} Работи от всяка мрежа (мобилни данни, WiFi)" echo -e " ${GREEN}✓${NC} Peer-to-peer връзки (супер бърз)" echo -e " ${GREEN}✓${NC} Базиран на WireGuard (модерна криптография)" echo -e " ${GREEN}✓${NC} Безплатен за лична употреба (до 100 устройства)\n" echo -e "${YELLOW}═══════════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW}🌐 Web Console:${NC}" echo -e " ${GREEN}https://login.tailscale.com/admin${NC}\n" echo -e "${YELLOW}📝 Лог файл:${NC}" echo -e " ${GREEN}$LOG_FILE${NC}\n" print_success "Готово! Enjoi your secure network! 🚀" log_message "Setup completed successfully - Final IP: $TAILSCALE_IP" } print_usage() { echo -e "${CYAN}Usage:${NC}" echo -e " ${GREEN}sudo bash $0${NC}" echo "" echo -e "${CYAN}Environment variables:${NC}" echo -e " ${GREEN}HOSTNAME${NC} - Tailscale hostname (default: proxmox-vpn)" echo -e " ${GREEN}EXIT_NODE${NC} - Enable exit node (default: true)" echo -e " ${GREEN}SKIP_STEPS${NC} - Skip specific steps (comma-separated)" echo -e " Available: install, ip_forwarding, setup, approve" echo "" echo -e "${CYAN}Examples:${NC}" echo -e " ${GREEN}sudo HOSTNAME=my-server EXIT_NODE=false bash $0${NC}" echo -e " ${GREEN}sudo SKIP_STEPS=install,ip_forwarding bash $0${NC}" echo "" } #═══════════════════════════════════════════════════════════════════════════════ # Main Execution #═══════════════════════════════════════════════════════════════════════════════ main() { print_header "🚀 Tailscale Professional Setup v2.0" # Log start of script log_message "=== Tailscale Setup Script Started ===" log_message "Parameters - HOSTNAME: $HOSTNAME, EXIT_NODE: $EXIT_NODE, SKIP_STEPS: $SKIP_STEPS" # Show usage if help requested if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then print_usage exit 0 fi check_root check_os check_tun install_tailscale configure_ip_forwarding setup_tailscale approve_routes get_tailscale_info create_management_script test_connectivity print_final_summary } # Run main function with all arguments main "$@"