mirror of https://github.com/go-gost/gost.git
a windows service setup script that uses downloaded binary from github.
parent
bb043572d3
commit
3f45651bf1
|
|
@ -0,0 +1,267 @@
|
|||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs gost as a Windows service.
|
||||
|
||||
.DESCRIPTION
|
||||
Downloads the latest (or specified) gost release from GitHub, installs it to
|
||||
a target directory, and registers it as a Windows service using the native
|
||||
Windows Service Control Manager. gost is built with go-svc and runs as a
|
||||
proper Windows service without any wrapper.
|
||||
|
||||
.PARAMETER Version
|
||||
The release tag to install, e.g. "v3.2.6". Defaults to the latest release.
|
||||
|
||||
.PARAMETER InstallDir
|
||||
Directory where gost.exe and gost.yml are placed.
|
||||
Default: C:\Program Files\gost
|
||||
|
||||
.PARAMETER ConfigFile
|
||||
Path to an existing gost config file to use. If omitted and no config
|
||||
exists in InstallDir, a minimal placeholder is created.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Windows service name. Default: gost
|
||||
|
||||
.PARAMETER DisplayName
|
||||
Windows service display name. Default: GOST Tunnel
|
||||
|
||||
.PARAMETER ExtraArgs
|
||||
Additional arguments passed to gost.exe, e.g. "-L :8080 -D".
|
||||
The -C flag pointing to the config file is always added automatically.
|
||||
|
||||
.PARAMETER StartupType
|
||||
Service start type: Automatic, Manual, or Disabled. Default: Automatic
|
||||
|
||||
.PARAMETER Start
|
||||
Start the service immediately after installation.
|
||||
|
||||
.EXAMPLE
|
||||
# Install latest release with defaults and start immediately
|
||||
.\install-service.ps1 -Start
|
||||
|
||||
.EXAMPLE
|
||||
# Install a specific version with a custom config
|
||||
.\install-service.ps1 -Version v3.2.6 -ConfigFile C:\etc\gost.yml -Start
|
||||
|
||||
.EXAMPLE
|
||||
# Install with inline service definition (no config file)
|
||||
.\install-service.ps1 -ExtraArgs "-L socks5://:1080 -L http://:8080" -Start
|
||||
#>
|
||||
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[string]$Version = "",
|
||||
[string]$InstallDir = "C:\Program Files\gost",
|
||||
[string]$ConfigFile = "",
|
||||
[string]$ServiceName = "gost",
|
||||
[string]$DisplayName = "GOST Tunnel",
|
||||
[string]$ExtraArgs = "",
|
||||
[ValidateSet("Automatic","Manual","Disabled")]
|
||||
[string]$StartupType = "Automatic",
|
||||
[switch]$Start
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function Write-Step([string]$msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
|
||||
function Write-Ok([string]$msg) { Write-Host " OK $msg" -ForegroundColor Green }
|
||||
function Write-Warn([string]$msg) { Write-Host " WARN $msg" -ForegroundColor Yellow }
|
||||
|
||||
function Get-Architecture {
|
||||
switch ($env:PROCESSOR_ARCHITECTURE) {
|
||||
"AMD64" { return "amd64" }
|
||||
"ARM64" { return "arm64" }
|
||||
"x86" { return "386" }
|
||||
default {
|
||||
# Also check PROCESSOR_ARCHITEW6432 for WoW64 processes
|
||||
if ($env:PROCESSOR_ARCHITEW6432 -eq "AMD64") { return "amd64" }
|
||||
throw "Unsupported architecture: $($env:PROCESSOR_ARCHITECTURE)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-LatestVersion {
|
||||
Write-Step "Fetching latest gost release from GitHub..."
|
||||
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/go-gost/gost/releases/latest" `
|
||||
-Headers @{ "User-Agent" = "gost-install-script" }
|
||||
return $release.tag_name
|
||||
}
|
||||
|
||||
function Get-DownloadUrl([string]$tag, [string]$arch) {
|
||||
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/go-gost/gost/releases/tags/$tag" `
|
||||
-Headers @{ "User-Agent" = "gost-install-script" }
|
||||
$pattern = "windows.*$arch"
|
||||
$asset = $release.assets | Where-Object { $_.name -match $pattern } | Select-Object -First 1
|
||||
if (-not $asset) {
|
||||
throw "No Windows/$arch asset found for release $tag. Available: $($release.assets.name -join ', ')"
|
||||
}
|
||||
return $asset.browser_download_url
|
||||
}
|
||||
|
||||
function Install-Binary([string]$url, [string]$destDir) {
|
||||
$zipPath = Join-Path $env:TEMP "gost-install.zip"
|
||||
Write-Step "Downloading $url ..."
|
||||
Invoke-WebRequest -Uri $url -OutFile $zipPath -UseBasicParsing
|
||||
|
||||
Write-Step "Extracting to $destDir ..."
|
||||
if (-not (Test-Path $destDir)) {
|
||||
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
$zip = [System.IO.Compression.ZipFile]::OpenRead($zipPath)
|
||||
try {
|
||||
foreach ($entry in $zip.Entries) {
|
||||
if ($entry.Name -eq "gost.exe") {
|
||||
$dest = Join-Path $destDir "gost.exe"
|
||||
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $dest, $true)
|
||||
Write-Ok "gost.exe extracted to $dest"
|
||||
break
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$zip.Dispose()
|
||||
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
$exePath = Join-Path $destDir "gost.exe"
|
||||
if (-not (Test-Path $exePath)) {
|
||||
throw "gost.exe not found in the downloaded archive."
|
||||
}
|
||||
return $exePath
|
||||
}
|
||||
|
||||
function Ensure-Config([string]$installDir, [string]$userConfig) {
|
||||
$dest = Join-Path $installDir "gost.yml"
|
||||
|
||||
if ($userConfig -ne "") {
|
||||
if (-not (Test-Path $userConfig)) {
|
||||
throw "Config file not found: $userConfig"
|
||||
}
|
||||
if ((Resolve-Path $userConfig).Path -ne (Resolve-Path $dest -ErrorAction SilentlyContinue)?.Path) {
|
||||
Copy-Item $userConfig $dest -Force
|
||||
Write-Ok "Config copied from $userConfig"
|
||||
}
|
||||
return $dest
|
||||
}
|
||||
|
||||
if (Test-Path $dest) {
|
||||
Write-Ok "Using existing config: $dest"
|
||||
return $dest
|
||||
}
|
||||
|
||||
# Create a minimal placeholder config
|
||||
$placeholder = @"
|
||||
# gost configuration file
|
||||
# Documentation: https://gost.run/
|
||||
#
|
||||
# Example: HTTP proxy on port 8080
|
||||
# services:
|
||||
# - name: http-proxy
|
||||
# addr: ":8080"
|
||||
# handler:
|
||||
# type: http
|
||||
# listener:
|
||||
# type: tcp
|
||||
|
||||
log:
|
||||
level: info
|
||||
format: json
|
||||
"@
|
||||
Set-Content -Path $dest -Value $placeholder -Encoding UTF8
|
||||
Write-Warn "A placeholder config was created at $dest"
|
||||
Write-Warn "Edit it before starting the service, or pass -ExtraArgs with -L/-F flags."
|
||||
return $dest
|
||||
}
|
||||
|
||||
function Register-GostService([string]$exePath, [string]$cfgPath, [string]$extraArgs) {
|
||||
$binPath = "`"$exePath`" -C `"$cfgPath`""
|
||||
if ($extraArgs -ne "") {
|
||||
$binPath += " $extraArgs"
|
||||
}
|
||||
|
||||
$existing = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
||||
|
||||
if ($existing) {
|
||||
Write-Step "Service '$ServiceName' already exists — updating..."
|
||||
if ($existing.Status -eq "Running") {
|
||||
Write-Step "Stopping existing service..."
|
||||
Stop-Service -Name $ServiceName -Force
|
||||
$existing.WaitForStatus("Stopped", [TimeSpan]::FromSeconds(30))
|
||||
}
|
||||
# Update the binary path
|
||||
sc.exe config $ServiceName binPath= $binPath | Out-Null
|
||||
sc.exe config $ServiceName start= $(if ($StartupType -eq "Automatic") { "auto" } elseif ($StartupType -eq "Manual") { "demand" } else { "disabled" }) | Out-Null
|
||||
Write-Ok "Service updated."
|
||||
} else {
|
||||
Write-Step "Registering service '$ServiceName'..."
|
||||
$startValue = switch ($StartupType) {
|
||||
"Automatic" { "auto" }
|
||||
"Manual" { "demand" }
|
||||
"Disabled" { "disabled" }
|
||||
}
|
||||
sc.exe create $ServiceName `
|
||||
binPath= $binPath `
|
||||
DisplayName= $DisplayName `
|
||||
start= $startValue | Out-Null
|
||||
|
||||
# Configure failure recovery: restart on first/second failure, reset after 1 day
|
||||
sc.exe failure $ServiceName reset= 86400 actions= restart/5000/restart/10000/restart/30000 | Out-Null
|
||||
Write-Ok "Service registered."
|
||||
}
|
||||
|
||||
# Set description
|
||||
sc.exe description $ServiceName "GOST (GO Simple Tunnel) - secure tunnel service" | Out-Null
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
$arch = Get-Architecture
|
||||
$version = if ($Version -ne "") { $Version } else { Get-LatestVersion }
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " gost Windows Service Installer" -ForegroundColor White
|
||||
Write-Host " ================================" -ForegroundColor White
|
||||
Write-Host " Version : $version"
|
||||
Write-Host " Arch : $version / windows-$arch"
|
||||
Write-Host " Install dir: $InstallDir"
|
||||
Write-Host " Service : $ServiceName ($StartupType)"
|
||||
Write-Host ""
|
||||
|
||||
# 1. Download & install binary
|
||||
$url = Get-DownloadUrl $version $arch
|
||||
$exePath = Install-Binary $url $InstallDir
|
||||
|
||||
# 2. Ensure config exists
|
||||
$cfgPath = Ensure-Config $InstallDir $ConfigFile
|
||||
|
||||
# 3. Register Windows service
|
||||
Register-GostService $exePath $cfgPath $ExtraArgs
|
||||
|
||||
# 4. Optionally start
|
||||
if ($Start) {
|
||||
Write-Step "Starting service '$ServiceName'..."
|
||||
Start-Service -Name $ServiceName
|
||||
$svc = Get-Service -Name $ServiceName
|
||||
$svc.WaitForStatus("Running", [TimeSpan]::FromSeconds(15))
|
||||
Write-Ok "Service is running."
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " Done!" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host " Useful commands:" -ForegroundColor White
|
||||
Write-Host " Start : Start-Service $ServiceName"
|
||||
Write-Host " Stop : Stop-Service $ServiceName"
|
||||
Write-Host " Status : Get-Service $ServiceName"
|
||||
Write-Host " Logs : Get-EventLog -LogName Application -Source $ServiceName -Newest 20"
|
||||
Write-Host " Uninstall: sc.exe delete $ServiceName"
|
||||
Write-Host ""
|
||||
Loading…
Reference in New Issue