headscale-tailscale-replace.../farmq-install-en.ps1
시골약사 4123babcea Fix Magic DNS issue: Enable DNS acceptance in Windows installation scripts
Changed --accept-dns=false to --accept-dns=true in both:
- farmq-install-en.ps1
- farmq-install.ps1

This allows Windows clients to receive Headscale Magic DNS configuration
(100.64.0.1) automatically during installation, enabling proper name resolution
for *.headscale.local domains.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 22:34:18 +09:00

493 lines
17 KiB
PowerShell

# FARMQ Headscale Windows One-Click Installation Script
# Usage: Run in Administrator PowerShell
# iex ((New-Object System.Net.WebClient).DownloadString('https://git.0bin.in/.../farmq-install-en.ps1'))
param(
[switch]$Force,
[string]$HeadscaleServer = "https://head.0bin.in",
[string]$PreAuthKey = "8b3df41d37cb158ea39f41fc32c9af46e761de817ad06038",
[string]$FarmqNetwork = "100.64.0.0/10"
)
# Set console to support Unicode characters
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
if ($PSVersionTable.PSVersion.Major -ge 6) {
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
}
# ================================
# Color Output Functions
# ================================
function Write-Header {
param([string]$Text)
Write-Host ""
Write-Host "============================================" -ForegroundColor Magenta
Write-Host $Text -ForegroundColor White
Write-Host "============================================" -ForegroundColor Magenta
Write-Host ""
}
function Write-Status {
param([string]$Message)
Write-Host ""
Write-Host "[*] $Message" -ForegroundColor Blue
}
function Write-Success {
param([string]$Message)
Write-Host ""
Write-Host "[+] $Message" -ForegroundColor Green
}
function Write-Error {
param([string]$Message)
Write-Host ""
Write-Host "[!] ERROR: $Message" -ForegroundColor Red
}
function Write-Warning {
param([string]$Message)
Write-Host ""
Write-Host "[!] WARNING: $Message" -ForegroundColor Yellow
}
function Write-Info {
param([string]$Message)
Write-Host ""
Write-Host "[i] $Message" -ForegroundColor Cyan
}
# ================================
# System Requirements Check
# ================================
function Test-Requirements {
Write-Status "Checking system requirements..."
# Check administrator privileges
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
if (-NOT $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Error "This script requires administrator privileges."
Write-Info "Please restart using one of these methods:"
Write-Info "1. Windows Key + X -> 'Windows PowerShell (Admin)'"
Write-Info "2. Right-click PowerShell -> 'Run as Administrator'"
Write-Host ""
Read-Host "Press any key to exit..."
exit 1
}
# Check Windows version
$osVersion = [System.Environment]::OSVersion.Version
if ($osVersion.Major -lt 10) {
Write-Warning "Windows 10 or later recommended. Current: Windows $($osVersion.Major).$($osVersion.Minor)"
}
# Check internet connection
try {
Microsoft.PowerShell.Management\Test-Connection "8.8.8.8" -Count 1 -Quiet | Out-Null
}
catch {
Write-Warning "Please check your internet connection."
}
Write-Success "System requirements check completed"
}
# ================================
# Install Tailscale
# ================================
function Install-Tailscale {
Write-Status "Checking Tailscale installation..."
# Check existing installation
$tailscalePath = Get-Command "tailscale" -ErrorAction SilentlyContinue
if ($tailscalePath) {
$version = & tailscale version 2>$null | Select-Object -First 1
Write-Info "Tailscale is already installed."
Write-Info "Current version: $version"
return
}
Write-Info "Installing Tailscale for Windows..."
# Get latest Tailscale version
try {
Write-Status "Getting latest Tailscale version..."
$latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/tailscale/tailscale/releases/latest" -UseBasicParsing
$version = $latestRelease.tag_name.TrimStart('v')
Write-Info "Latest version: $version"
}
catch {
Write-Warning "Failed to get latest version, using fallback"
$version = "1.86.2"
}
# Temporary download path
$tempPath = "$env:TEMP\tailscale-setup-$version.exe"
$downloadUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-$version.exe"
try {
Write-Status "Downloading Tailscale from: $downloadUrl"
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempPath -UseBasicParsing
Write-Status "Installing Tailscale... (please wait)"
Start-Process -FilePath $tempPath -ArgumentList "/S" -Wait
# Refresh PATH environment variable
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
# Verify installation
Start-Sleep -Seconds 3
$tailscaleInstalled = Get-Command "tailscale" -ErrorAction SilentlyContinue
if (-not $tailscaleInstalled) {
# Try direct path
$tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe"
if (Test-Path $tailscaleExe) {
# Add Tailscale to PATH
$currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($currentPath -notlike "*Tailscale*") {
[Environment]::SetEnvironmentVariable("Path", "$currentPath;C:\Program Files\Tailscale", "Machine")
$env:Path = "$env:Path;C:\Program Files\Tailscale"
}
}
}
Remove-Item $tempPath -Force -ErrorAction SilentlyContinue
Write-Success "Tailscale installation completed"
}
catch {
Write-Error "Tailscale installation failed: $($_.Exception.Message)"
throw
}
}
# ================================
# Start Tailscale Service
# ================================
function Start-TailscaleService {
Write-Status "Starting Tailscale service..."
try {
# Start Tailscale service
$service = Get-Service -Name "Tailscale" -ErrorAction SilentlyContinue
if ($service) {
if ($service.Status -ne "Running") {
Start-Service -Name "Tailscale"
Start-Sleep -Seconds 3
}
Write-Success "Tailscale service is running."
} else {
Write-Warning "Tailscale service not found. Attempting manual start..."
}
}
catch {
Write-Warning "Failed to start service: $($_.Exception.Message)"
}
}
# ================================
# Register with Headscale
# ================================
function Register-Headscale {
Write-Status "Registering with Headscale server..."
# Find Tailscale executable path
$tailscaleCmd = Get-Command "tailscale" -ErrorAction SilentlyContinue
if (-not $tailscaleCmd) {
$tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe"
if (Test-Path $tailscaleExe) {
$tailscaleCmd = @{Source = $tailscaleExe}
} else {
Write-Error "Tailscale executable not found."
return $false
}
}
$tailscalePath = $tailscaleCmd.Source
# Check existing connection
try {
$status = & $tailscalePath status 2>$null
if ($LASTEXITCODE -eq 0 -and $status) {
Write-Warning "Already connected to Tailscale/Headscale network."
# Show current connection status
Write-Info "Current connection status:"
$status | Select-Object -First 5 | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
# Check force registration option
if ($Force) {
Write-Warning "Force registration option is enabled."
Write-Info "Disconnecting existing connection and re-registering..."
} else {
$response = Read-Host "Disconnect existing connection and register with FARMQ Headscale? (Y/n)"
if ($response -eq "" -or $response -match "^[Yy]") {
Write-Info "Disconnecting existing connection..."
} else {
Write-Info "Skipping registration."
return $true
}
}
# Disconnect existing connection
try {
& $tailscalePath logout 2>$null
Start-Sleep -Seconds 3
Write-Success "Existing connection disconnected."
}
catch {
Write-Warning "Error during disconnection, but continuing..."
}
}
}
catch {
# Not connected (normal)
}
Write-Info "Headscale Server: $HeadscaleServer"
Write-Info "Pre-auth Key: $($PreAuthKey.Substring(0,8))***************"
# Attempt Headscale registration
Write-Status "Executing registration command..."
try {
$arguments = @(
"up",
"--login-server=$HeadscaleServer",
"--authkey=$PreAuthKey",
"--accept-routes",
"--accept-dns=true"
)
& $tailscalePath $arguments
if ($LASTEXITCODE -eq 0) {
Write-Success "Headscale registration successful!"
return $true
} else {
Write-Error "Automatic registration failed."
Write-Info "Manual registration command:"
Write-Host "tailscale up --login-server=`"$HeadscaleServer`" --authkey=`"$PreAuthKey`""
return $false
}
}
catch {
Write-Error "Registration error: $($_.Exception.Message)"
return $false
}
}
# ================================
# Configure Firewall
# ================================
function Configure-Firewall {
Write-Status "Configuring firewall settings..."
try {
# Add Windows Defender firewall exception
$ruleName = "Tailscale-FARMQ"
$existingRule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
if (-not $existingRule) {
New-NetFirewallRule -DisplayName $ruleName -Direction Inbound -Protocol UDP -LocalPort 41641 -Action Allow -Profile Any | Out-Null
New-NetFirewallRule -DisplayName "$ruleName-Outbound" -Direction Outbound -Protocol UDP -LocalPort 41641 -Action Allow -Profile Any | Out-Null
Write-Info "Windows Defender firewall exceptions added."
}
Write-Success "Firewall configuration completed"
}
catch {
Write-Warning "Firewall configuration error: $($_.Exception.Message)"
Write-Info "Please manually allow Tailscale through Windows firewall."
}
}
# ================================
# Verify Connection
# ================================
function Test-NetworkConnection {
Write-Status "Verifying network connection..."
Start-Sleep -Seconds 5
# Find Tailscale executable path
$tailscaleCmd = Get-Command "tailscale" -ErrorAction SilentlyContinue
if (-not $tailscaleCmd) {
$tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe"
if (Test-Path $tailscaleExe) {
$tailscaleCmd = @{Source = $tailscaleExe}
} else {
Write-Error "Tailscale executable not found."
return
}
}
$tailscalePath = $tailscaleCmd.Source
try {
$status = & $tailscalePath status 2>$null
if ($LASTEXITCODE -ne 0 -or -not $status) {
Write-Error "Tailscale connection issue detected."
return
}
# Get IP addresses
$ipv4 = & $tailscalePath ip -4 2>$null
$ipv6 = & $tailscalePath ip -6 2>$null
Write-Success "Headscale network connection completed!"
Write-Info "Assigned IPv4: $(if($ipv4){$ipv4}else{'N/A'})"
Write-Info "Assigned IPv6: $(if($ipv6){$ipv6}else{'N/A'})"
# Network connectivity test
Write-Status "Testing network connectivity..."
try {
Microsoft.PowerShell.Management\Test-Connection "100.64.0.1" -Count 2 -Quiet | Out-Null
Write-Success "FARMQ network ($FarmqNetwork) connection successful!"
}
catch {
Write-Warning "Network test failed. Please check firewall settings."
}
# Show connected nodes
Write-Info "Network status:"
$status | Select-Object -First 10 | ForEach-Object {
Write-Host " $_" -ForegroundColor Gray
}
}
catch {
Write-Error "Connection verification failed: $($_.Exception.Message)"
}
}
# ================================
# Cleanup
# ================================
function Complete-Installation {
Write-Status "Completing installation..."
# Clean temporary files
Get-ChildItem "$env:TEMP\tailscale*" -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
Write-Success "Cleanup completed"
}
# ================================
# Show Final Information
# ================================
function Show-FinalInfo {
Write-Header "FARMQ Headscale Windows Installation Complete!"
# System information
$computerName = $env:COMPUTERNAME
$tailscaleCmd = Get-Command "tailscale" -ErrorAction SilentlyContinue
if (-not $tailscaleCmd) {
$tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe"
if (Test-Path $tailscaleExe) {
$tailscaleCmd = @{Source = $tailscaleExe}
}
}
if ($tailscaleCmd) {
$tailscaleIP = & $tailscaleCmd.Source ip -4 2>$null
}
$osVersion = [System.Environment]::OSVersion.Version
Write-Host "Installation completed successfully!" -ForegroundColor Green
Write-Host ""
Write-Host "System Information:" -ForegroundColor Cyan
Write-Host " Computer Name: $computerName"
Write-Host " Tailscale IP: $(if($tailscaleIP){$tailscaleIP}else{'N/A'})"
Write-Host " OS: Windows $($osVersion.Major).$($osVersion.Minor)"
Write-Host " Headscale Server: $HeadscaleServer"
Write-Host ""
Write-Host "Useful Commands:" -ForegroundColor Yellow
Write-Host " tailscale status # Check connection status"
Write-Host " tailscale ip # Show assigned IP"
Write-Host " tailscale ping <node> # Test connection to other nodes"
Write-Host " tailscale logout # Disconnect from network"
Write-Host ""
Write-Host "FARMQ Management Pages:" -ForegroundColor Magenta
Write-Host " http://192.168.0.151:5002"
Write-Host " http://192.168.0.151:5002/vms (VM Management)"
Write-Host ""
Write-Host "If you encounter issues, check:" -ForegroundColor White
Write-Host " 1. Windows Firewall settings"
Write-Host " 2. Antivirus software exceptions"
Write-Host " 3. Corporate network policies"
Write-Header "Installation Complete - You can now use FARMQ network!"
}
# ================================
# Main Function
# ================================
function Main {
# Stop on errors
$ErrorActionPreference = "Stop"
Write-Header "FARMQ Headscale Windows One-Click Installation"
try {
# Installation process
Test-Requirements
Install-Tailscale
Start-TailscaleService
$registerSuccess = Register-Headscale
if ($registerSuccess) {
Configure-Firewall
Test-NetworkConnection
Complete-Installation
Show-FinalInfo
} else {
Write-Warning "Registration failed but Tailscale is installed."
Write-Info "Please complete registration manually."
}
}
catch {
Write-Error "Installation error occurred: $($_.Exception.Message)"
Write-Info "If the problem persists, please contact administrator."
Write-Host ""
Read-Host "Press any key to exit..."
exit 1
}
}
# ================================
# Script Execution
# ================================
# Handle parameters
if ($args -contains "--help" -or $args -contains "-h") {
Write-Host "FARMQ Headscale Windows Installation Script"
Write-Host ""
Write-Host "Usage:"
Write-Host " iex ((New-Object System.Net.WebClient).DownloadString('https://git.0bin.in/.../farmq-install-en.ps1'))"
Write-Host ""
Write-Host "Options:"
Write-Host " -Force Force disconnect existing connection and re-register"
Write-Host " -HeadscaleServer Server address (default: https://head.0bin.in)"
Write-Host ""
Write-Host "Examples:"
Write-Host " # Force re-registration"
Write-Host " `$Force = `$true; iex ((New-Object System.Net.WebClient).DownloadString('https://git.0bin.in/.../farmq-install-en.ps1'))"
exit 0
}
# Handle Force parameter from URL or variable
if ($MyInvocation.MyCommand.Path -like "*force=1*" -or (Get-Variable -Name "ForceInstall" -ErrorAction SilentlyContinue)) {
$Force = $true
}
# Execute main function
Main