Created
June 13, 2025 12:53
-
-
Save lambdafunc/39fcdceca73e8e2c25e89c378e5308e8 to your computer and use it in GitHub Desktop.
ubuntu tailscale exit node setup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Tailscale Exit Node Setup Script for Ubuntu | |
| # This script installs Tailscale, configures it as an exit node, and validates the setup | |
| set -e # Exit on any error | |
| # Colors for output | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' # No Color | |
| # Logging function | |
| 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 if running as root | |
| check_root() { | |
| if [[ $EUID -eq 0 ]]; then | |
| error "This script should not be run as root for security reasons." | |
| error "Please run as a regular user with sudo privileges." | |
| exit 1 | |
| fi | |
| } | |
| # Check if user has sudo privileges | |
| check_sudo() { | |
| if ! sudo -n true 2>/dev/null; then | |
| error "This script requires sudo privileges. Please ensure your user can run sudo commands." | |
| exit 1 | |
| fi | |
| } | |
| # Check Ubuntu version compatibility | |
| check_ubuntu_version() { | |
| if ! command -v lsb_release &> /dev/null; then | |
| error "lsb_release not found. Are you running Ubuntu?" | |
| exit 1 | |
| fi | |
| local version=$(lsb_release -rs) | |
| local major_version=$(echo $version | cut -d. -f1) | |
| if [[ $major_version -lt 18 ]]; then | |
| error "Ubuntu 18.04 or later is required. Current version: $version" | |
| exit 1 | |
| fi | |
| success "Ubuntu version $version detected - compatible" | |
| } | |
| # Update system packages | |
| update_system() { | |
| log "Updating system packages..." | |
| sudo apt update && sudo apt upgrade -y | |
| success "System packages updated" | |
| } | |
| # Install required packages | |
| install_dependencies() { | |
| log "Installing required dependencies..." | |
| sudo apt install -y \ | |
| curl \ | |
| gnupg2 \ | |
| software-properties-common \ | |
| apt-transport-https \ | |
| ca-certificates \ | |
| iptables \ | |
| net-tools \ | |
| dnsutils | |
| success "Dependencies installed" | |
| } | |
| # Install Tailscale | |
| install_tailscale() { | |
| log "Installing Tailscale..." | |
| # Add Tailscale's package signing key and repository | |
| curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(lsb_release -cs).noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null | |
| curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(lsb_release -cs).tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list | |
| # Update package list and install Tailscale | |
| sudo apt update | |
| sudo apt install -y tailscale | |
| success "Tailscale installed successfully" | |
| } | |
| # Enable IP forwarding | |
| enable_ip_forwarding() { | |
| log "Enabling IP forwarding..." | |
| # Enable IP forwarding for current session | |
| sudo sysctl -w net.ipv4.ip_forward=1 | |
| sudo sysctl -w net.ipv6.conf.all.forwarding=1 | |
| # Make IP forwarding persistent across reboots | |
| echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf | |
| echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf | |
| # Remove duplicates from sysctl.conf | |
| sudo sort -u /etc/sysctl.conf -o /etc/sysctl.conf | |
| success "IP forwarding enabled" | |
| } | |
| # Start Tailscale service | |
| start_tailscale() { | |
| log "Starting and enabling Tailscale service..." | |
| sudo systemctl enable --now tailscaled | |
| success "Tailscale service started and enabled" | |
| } | |
| # Authenticate with Tailscale | |
| authenticate_tailscale() { | |
| log "Starting Tailscale authentication..." | |
| warning "You will need to complete authentication in your browser." | |
| warning "Please follow the URL that will be displayed." | |
| # Start Tailscale with exit node advertisement | |
| sudo tailscale up --advertise-exit-node | |
| success "Tailscale authentication completed" | |
| } | |
| # Configure firewall (UFW) if enabled | |
| configure_firewall() { | |
| if sudo ufw status | grep -q "Status: active"; then | |
| log "Configuring UFW firewall for Tailscale..." | |
| # Allow Tailscale traffic | |
| sudo ufw allow in on tailscale0 | |
| sudo ufw allow out on tailscale0 | |
| # Allow Tailscale UDP port | |
| sudo ufw allow 41641/udp | |
| success "Firewall configured for Tailscale" | |
| else | |
| log "UFW firewall is not active, skipping firewall configuration" | |
| fi | |
| } | |
| # Test Tailscale connectivity | |
| test_connectivity() { | |
| log "Testing Tailscale connectivity..." | |
| # Wait a moment for Tailscale to fully initialize | |
| sleep 5 | |
| # Check if Tailscale is running | |
| if ! sudo tailscale status &>/dev/null; then | |
| error "Tailscale is not running properly" | |
| return 1 | |
| fi | |
| # Get Tailscale status | |
| local status=$(sudo tailscale status) | |
| if [[ -z "$status" ]]; then | |
| error "Unable to get Tailscale status" | |
| return 1 | |
| fi | |
| success "Tailscale is running and connected" | |
| return 0 | |
| } | |
| # Validate exit node configuration | |
| validate_exit_node() { | |
| log "Validating exit node configuration..." | |
| # Check if exit node is advertised | |
| local status=$(sudo tailscale status --json) | |
| if command -v jq &> /dev/null; then | |
| local exit_node_option=$(echo "$status" | jq -r '.Self.HostName // empty') | |
| if [[ -n "$exit_node_option" ]]; then | |
| success "Exit node is properly advertised" | |
| else | |
| warning "Unable to verify exit node status with jq" | |
| fi | |
| else | |
| # Fallback check without jq | |
| if sudo tailscale status | grep -q "offers exit node"; then | |
| success "Exit node is properly advertised" | |
| else | |
| warning "Exit node status unclear - please check Tailscale admin console" | |
| fi | |
| fi | |
| # Check IP forwarding | |
| local ipv4_forward=$(cat /proc/sys/net/ipv4/ip_forward) | |
| local ipv6_forward=$(cat /proc/sys/net/ipv6/conf/all/forwarding) | |
| if [[ "$ipv4_forward" == "1" ]] && [[ "$ipv6_forward" == "1" ]]; then | |
| success "IP forwarding is properly enabled" | |
| else | |
| error "IP forwarding is not properly configured" | |
| return 1 | |
| fi | |
| } | |
| # Display final status and instructions | |
| display_final_status() { | |
| log "=== Tailscale Exit Node Setup Complete ===" | |
| echo | |
| success "✓ Tailscale installed and configured" | |
| success "✓ Exit node advertised" | |
| success "✓ IP forwarding enabled" | |
| success "✓ System configured for exit node functionality" | |
| echo | |
| warning "IMPORTANT NEXT STEPS:" | |
| warning "1. Go to your Tailscale admin console: https://login.tailscale.com/admin/machines" | |
| warning "2. Find this machine and enable it as an exit node" | |
| warning "3. Other devices can then route traffic through this exit node" | |
| echo | |
| log "Current Tailscale status:" | |
| sudo tailscale status | |
| echo | |
| log "To check logs: sudo journalctl -u tailscaled -f" | |
| log "To restart Tailscale: sudo systemctl restart tailscaled" | |
| log "To check exit node status: sudo tailscale status" | |
| } | |
| # Cleanup function for errors | |
| cleanup() { | |
| if [[ $? -ne 0 ]]; then | |
| error "Script failed. Check the logs above for details." | |
| error "You may need to run: sudo apt remove tailscale && sudo rm -f /etc/apt/sources.list.d/tailscale.list" | |
| fi | |
| } | |
| # Main execution | |
| main() { | |
| trap cleanup EXIT | |
| log "Starting Tailscale Exit Node setup on Ubuntu..." | |
| # Pre-flight checks | |
| check_root | |
| check_sudo | |
| check_ubuntu_version | |
| # Installation steps | |
| update_system | |
| install_dependencies | |
| install_tailscale | |
| enable_ip_forwarding | |
| start_tailscale | |
| # Configuration and authentication | |
| authenticate_tailscale | |
| configure_firewall | |
| # Testing and validation | |
| if test_connectivity && validate_exit_node; then | |
| display_final_status | |
| success "Tailscale exit node setup completed successfully!" | |
| else | |
| error "Setup completed but validation failed. Please check the configuration manually." | |
| exit 1 | |
| fi | |
| } | |
| # Script usage information | |
| usage() { | |
| echo "Usage: $0 [options]" | |
| echo "Options:" | |
| echo " -h, --help Show this help message" | |
| echo " --dry-run Show what would be done without executing" | |
| echo | |
| echo "This script will:" | |
| echo " 1. Install Tailscale on Ubuntu" | |
| echo " 2. Configure the system as a Tailscale exit node" | |
| echo " 3. Enable IP forwarding" | |
| echo " 4. Configure firewall if needed" | |
| echo " 5. Test and validate the setup" | |
| } | |
| # Handle command line arguments | |
| case "${1:-}" in | |
| -h|--help) | |
| usage | |
| exit 0 | |
| ;; | |
| --dry-run) | |
| echo "DRY RUN MODE - Commands that would be executed:" | |
| echo "sudo apt update && sudo apt upgrade -y" | |
| echo "sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates iptables net-tools dnsutils" | |
| echo "curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/\$(lsb_release -cs).noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg" | |
| echo "sudo apt install -y tailscale" | |
| echo "sudo sysctl -w net.ipv4.ip_forward=1" | |
| echo "sudo systemctl enable --now tailscaled" | |
| echo "sudo tailscale up --advertise-exit-node" | |
| exit 0 | |
| ;; | |
| "") | |
| main | |
| ;; | |
| *) | |
| error "Unknown option: $1" | |
| usage | |
| exit 1 | |
| ;; | |
| esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment