Skip to content

Go on Windows: one binary, one service, one proxy

Verified 1 min read

Deploy a Go HTTP server as a Windows service, pass config by environment, handle graceful shutdown, and reverse-proxy it safely.

Tested onStandard / Datacenter · Build 26100.33650 · x64
E1
Build
26100.33650
Edition
Standard / Datacenter
Architecture
x64
Support
Documentation (E1)
Evidence
E1Official documentation
Verified
2026-10-29
Page type
Task

A Go server is a single .exe. There is no runtime to install on the server:

Terminal window
go build -trimpath -ldflags="-s -w" -o C:\apps\api\api.exe .\cmd\api

Run it as a Windows service with WinSW/NSSM, and let IIS/Nginx own 443.

Terminal window
$env:GOOS='windows'; $env:GOARCH='amd64'
go build -trimpath -ldflags="-s -w" -o C:\build\api.exe .\cmd\api

Build on the target architecture; do not ship a binary built for another OS/arch. -trimpath removes local paths; -s -w strips symbols (keep a separate debug build if you need stack traces).

WinSW:

<service>
<id>api</id>
<executable>C:\apps\api\api.exe</executable>
<workingdirectory>C:\apps\api</workingdirectory>
<env name="APP_ENV" value="production"/>
<env name="LISTEN_ADDR" value="127.0.0.1:8080"/>
<logpath>C:\logs\api</logpath>
<onfailure action="restart" delay="10 sec"/>
</service>

The app should read LISTEN_ADDR/config from environment or a file next to the exe. Do not hard-code production secrets in the binary.

Handle SIGTERM/console close and call server.Shutdown(ctx) with a timeout. Windows service stop sends a control event; a Go app that ignores it gets killed after the service timeout and may drop in-flight requests.

location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

The Go app should trust forwarded headers only from the proxy. Bind to localhost; do not expose 8080.

Terminal window
sc.exe qc api
Get-CimInstance Win32_Process -Filter "Name='api.exe'" |
Select-Object ProcessId, ExecutablePath, CommandLine
curl.exe -I http://127.0.0.1:8080/healthz
Get-Content C:\logs\api\api.err.log -Tail 50

Check the binary path, health endpoint and logs. A 502 from the proxy usually means the service is not listening.

E1. The lab did not build or run a Go service; the commands are the deployment pattern to validate on Server 2025.

Sources