a windows service setup script that uses downloaded binary from github.

pull/849/head
CHEN Li 2026-03-14 19:50:00 +08:00
parent bb043572d3
commit 3f45651bf1
1 changed files with 267 additions and 0 deletions

267
install-service.ps1 100644
View File

@ -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 ""