Skip to content

Instantly share code, notes, and snippets.

@lambdafunc
Created June 13, 2025 12:53
Show Gist options
  • Select an option

  • Save lambdafunc/39fcdceca73e8e2c25e89c378e5308e8 to your computer and use it in GitHub Desktop.

Select an option

Save lambdafunc/39fcdceca73e8e2c25e89c378e5308e8 to your computer and use it in GitHub Desktop.
ubuntu tailscale exit node setup
#!/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