#!/bin/bash # WireGuard Server Setup with Gluetun (Docker) # Author: Assistant # Date: $(date +%Y-%m-%d) set -e # Colors for better readability RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging functions log() { echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" } error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Check root privileges check_root() { if [[ $EUID -ne 0 ]]; then error "This script must be run as root!" exit 1 fi } # Check operating system check_os() { if [[ ! -f /etc/debian_version ]]; then error "This script is designed for Debian systems!" exit 1 fi success "Debian system detected" } # Check package availability check_packages() { log "Checking installed packages..." local required_packages=("curl" "wget" "apt-transport-https" "ca-certificates" "gnupg" "lsb-release" "net-tools" "iptables") local missing_packages=() for package in "${required_packages[@]}"; do if ! dpkg -l | grep -q "^ii $package "; then missing_packages+=("$package") else success "$package is already installed" fi done # Check Docker if ! command -v docker &> /dev/null; then missing_packages+=("docker") warning "Docker is not installed" else success "Docker is already installed" fi if ! command -v docker-compose &> /dev/null; then missing_packages+=("docker-compose") warning "Docker Compose is not installed" else success "Docker Compose is already installed" fi if [[ ${#missing_packages[@]} -gt 0 ]]; then warning "The following packages need to be installed: ${missing_packages[*]}" return 1 else success "All required packages are already installed" return 0 fi } # Update system update_system() { log "Updating package list..." apt update -q log "Performing system upgrade..." apt upgrade -y -q success "System has been updated" } # Install basic packages install_basic_packages() { log "Installing basic packages..." local packages=("curl" "wget" "apt-transport-https" "ca-certificates" "gnupg" "lsb-release" "net-tools" "iptables" "ufw" "nano") apt install -y "${packages[@]}" success "Basic packages installed" } # Install Docker install_docker() { if command -v docker &> /dev/null; then success "Docker is already installed" return 0 fi log "Installing Docker..." # Remove old Docker versions apt remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true # Add Docker GPG key curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # Add Docker repository echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null # Update package list apt update -q # Install Docker apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Start and enable Docker systemctl enable docker systemctl start docker success "Docker has been installed and started" } # Install Docker Compose install_docker_compose() { if command -v docker-compose &> /dev/null; then success "Docker Compose is already installed" return 0 fi log "Installing Docker Compose..." # Get latest version local compose_version=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4) # Download Docker Compose curl -L "https://github.com/docker/compose/releases/download/${compose_version}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # Make executable chmod +x /usr/local/bin/docker-compose # Create symlink ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose success "Docker Compose has been installed" } # Configure static IP configure_static_ip() { log "Configuring static IP..." # Show available network interfaces echo -e "\n${YELLOW}Available network interfaces:${NC}" ip link show | grep -E "^[0-9]+: " | cut -d: -f2 | tr -d ' ' echo -e "\n${YELLOW}Current IP configuration:${NC}" ip addr show | grep -E "inet [0-9]" | grep -v 127.0.0.1 echo -e "\n" read -p "Would you like to configure a static IP? (y/n): " configure_ip if [[ $configure_ip =~ ^[Yy]$ ]]; then read -p "Interface (e.g. eth0, ens18): " interface read -p "Static IP address (e.g. 192.168.1.100/24): " static_ip read -p "Gateway (e.g. 192.168.1.1): " gateway read -p "DNS server (e.g. 8.8.8.8): " dns_server # Backup current configuration cp /etc/network/interfaces /etc/network/interfaces.backup.$(date +%s) # Create new configuration cat > /etc/network/interfaces << EOF # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback # Static IP configuration auto $interface iface $interface inet static address $static_ip gateway $gateway dns-nameservers $dns_server EOF success "Static IP configuration created" warning "Network will be restarted after script completion" else log "Static IP configuration skipped" fi } # Get WireGuard configuration get_wireguard_config() { log "Getting WireGuard configuration..." echo -e "\n${YELLOW}Please enter your WireGuard configuration data:${NC}" read -p "WireGuard Private Key: " WG_PRIVATE_KEY read -p "WireGuard Public Key: " WG_PUBLIC_KEY read -p "WireGuard Preshared Key (optional, Enter for empty): " WG_PRESHARED_KEY read -p "WireGuard Endpoint (e.g. vpn.example.com:51820): " WG_ENDPOINT read -p "WireGuard Allowed IPs (e.g. 0.0.0.0/0): " WG_ALLOWED_IPS read -p "WireGuard Interface IP - IPv4 only (e.g. 10.0.0.2/32): " WG_INTERFACE_IP # Remove IPv6 addresses from input (Gluetun compatibility) WG_INTERFACE_IP=$(echo "$WG_INTERFACE_IP" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+' | head -1) if [[ -z "$WG_INTERFACE_IP" ]]; then warning "No valid IPv4 address detected. Please use IPv4 only (e.g. 10.0.0.2/32)" read -p "WireGuard Interface IP (IPv4 only): " WG_INTERFACE_IP fi # Validation if [[ -z "$WG_PRIVATE_KEY" ]] || [[ -z "$WG_PUBLIC_KEY" ]] || [[ -z "$WG_ENDPOINT" ]]; then error "Private Key, Public Key and Endpoint are required!" exit 1 fi success "WireGuard configuration captured" } # Setup Gluetun directory and configuration setup_gluetun() { log "Creating Gluetun configuration..." # Create working directory mkdir -p /opt/gluetun cd /opt/gluetun # Create Docker Compose file cat > docker-compose.yml << EOF services: gluetun: image: qmcgaw/gluetun:latest container_name: gluetun-wireguard restart: unless-stopped cap_add: - NET_ADMIN devices: - /dev/net/tun:/dev/net/tun ports: - "8888:8888/tcp" # HTTP proxy - "8388:8388/tcp" # Shadowsocks - "8388:8388/udp" # Shadowsocks environment: - VPN_SERVICE_PROVIDER=custom - VPN_TYPE=wireguard - WIREGUARD_ENDPOINT_IP=${WG_ENDPOINT%:*} - WIREGUARD_ENDPOINT_PORT=${WG_ENDPOINT#*:} - WIREGUARD_PRIVATE_KEY=${WG_PRIVATE_KEY} - WIREGUARD_PUBLIC_KEY=${WG_PUBLIC_KEY} - WIREGUARD_ADDRESSES=${WG_INTERFACE_IP} - WIREGUARD_ALLOWED_IPS=${WG_ALLOWED_IPS:-0.0.0.0/0} - HTTPPROXY=on - HTTPPROXY_LOG=on - HTTPPROXY_LISTENING_ADDRESS=:8888 - SHADOWSOCKS=on - SHADOWSOCKS_LOG=on - SHADOWSOCKS_LISTENING_ADDRESS=:8388 - LOG_LEVEL=info - HEALTH_VPN_DURATION_INITIAL=10s - HEALTH_VPN_DURATION_ADDITION=5s - DOT=off - FIREWALL_OUTBOUND_SUBNETS=192.168.0.0/16,172.16.0.0/12,10.0.0.0/8 EOF # Add preshared key if provided if [[ -n "$WG_PRESHARED_KEY" ]]; then echo " - WIREGUARD_PRESHARED_KEY=${WG_PRESHARED_KEY}" >> docker-compose.yml fi success "Gluetun Docker Compose file created" } # Configure firewall configure_firewall() { log "Configuring UFW firewall..." # Reset and enable UFW ufw --force reset ufw --force enable # Default rules ufw default deny incoming ufw default allow outgoing # Allow SSH ufw allow ssh # Allow proxy ports ufw allow 8888/tcp comment "Gluetun HTTP Proxy" ufw allow 8388 comment "Gluetun SOCKS Proxy" # Allow Docker subnets ufw allow from 172.17.0.0/16 ufw allow from 172.18.0.0/16 success "Firewall configured" } # Start Gluetun start_gluetun() { log "Starting Gluetun container..." cd /opt/gluetun # Stop container if already running docker-compose down 2>/dev/null || true # Update images docker-compose pull # Start container docker-compose up -d success "Gluetun container started" } # Check status check_status() { log "Checking container status..." sleep 5 if docker ps | grep -q gluetun-wireguard; then success "Gluetun container is running" # Show logs echo -e "\n${YELLOW}Container logs (last 20 lines):${NC}" docker logs --tail 20 gluetun-wireguard # Check VPN status echo -e "\n${YELLOW}Checking VPN status...${NC}" sleep 10 # Check IP address via VPN local vpn_ip=$(docker exec gluetun-wireguard wget -qO- https://ipinfo.io/ip 2>/dev/null || echo "Error retrieving IP") echo -e "${GREEN}VPN IP address: ${vpn_ip}${NC}" else error "Gluetun container is not running!" echo -e "\n${RED}Container logs:${NC}" docker logs gluetun-wireguard 2>/dev/null || echo "No logs available" fi } # Create systemd service create_systemd_service() { log "Creating systemd service..." cat > /etc/systemd/system/gluetun.service << EOF [Unit] Description=Gluetun VPN Container Requires=docker.service After=docker.service [Service] Type=oneshot RemainAfterExit=yes WorkingDirectory=/opt/gluetun ExecStart=/usr/local/bin/docker-compose up -d ExecStop=/usr/local/bin/docker-compose down TimeoutStartSec=0 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable gluetun.service success "Systemd service created and enabled" } # Show summary show_summary() { echo -e "\n${GREEN}===========================================${NC}" echo -e "${GREEN} Installation completed successfully!${NC}" echo -e "${GREEN}===========================================${NC}" echo -e "\n${YELLOW}Proxy Settings:${NC}" echo -e "HTTP/HTTPS Proxy: http://$(hostname -I | awk '{print $1}'):8888" echo -e "SOCKS5 Proxy: $(hostname -I | awk '{print $1}'):8388" echo -e "\n${YELLOW}Useful Commands:${NC}" echo -e "Container status: ${BLUE}docker ps${NC}" echo -e "Container logs: ${BLUE}docker logs gluetun-wireguard${NC}" echo -e "Stop container: ${BLUE}systemctl stop gluetun${NC}" echo -e "Start container: ${BLUE}systemctl start gluetun${NC}" echo -e "Restart container: ${BLUE}systemctl restart gluetun${NC}" echo -e "\n${YELLOW}Configuration Files:${NC}" echo -e "Docker Compose: ${BLUE}/opt/gluetun/docker-compose.yml${NC}" echo -e "Systemd Service: ${BLUE}/etc/systemd/system/gluetun.service${NC}" if [[ $configure_ip =~ ^[Yy]$ ]]; then echo -e "\n${YELLOW}Important:${NC} System must be rebooted to activate static IP!" read -p "Would you like to reboot the system now? (y/n): " reboot_now if [[ $reboot_now =~ ^[Yy]$ ]]; then log "Rebooting system..." reboot fi fi } # Main function main() { echo -e "${BLUE}" echo "==============================================" echo " WireGuard Server Setup with Gluetun (Docker)" echo "==============================================" echo -e "${NC}\n" # Validations check_root check_os # System setup if ! check_packages; then update_system install_basic_packages install_docker install_docker_compose fi # Network configuration configure_static_ip # WireGuard setup get_wireguard_config setup_gluetun configure_firewall create_systemd_service start_gluetun # Status and summary check_status show_summary } # Execute script main "$@"