Go on Windows: one binary, one service, one proxy
Deploy a Go HTTP server as a Windows service, pass config by environment, handle graceful shutdown, and reverse-proxy it safely.
- Build
- 26100.33650
- Edition
- Standard / Datacenter
- Architecture
- x64
- Support
- Documentation (E1)
- Evidence
- E1Official documentation
- Verified
- 2026-10-29
- Page type
- Task
The short answer
Section titled “The short answer”A Go server is a single .exe. There is no runtime to install on the server:
go build -trimpath -ldflags="-s -w" -o C:\apps\api\api.exe .\cmd\apiRun it as a Windows service with WinSW/NSSM, and let IIS/Nginx own 443.
Build for the target
Section titled “Build for the target”$env:GOOS='windows'; $env:GOARCH='amd64'go build -trimpath -ldflags="-s -w" -o C:\build\api.exe .\cmd\apiBuild 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).
Service wrapper
Section titled “Service wrapper”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.
Graceful shutdown
Section titled “Graceful shutdown”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.
Reverse proxy
Section titled “Reverse proxy”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.
Verify
Section titled “Verify”sc.exe qc apiGet-CimInstance Win32_Process -Filter "Name='api.exe'" | Select-Object ProcessId, ExecutablePath, CommandLinecurl.exe -I http://127.0.0.1:8080/healthzGet-Content C:\logs\api\api.err.log -Tail 50Check the binary path, health endpoint and logs. A 502 from the proxy usually means the service is not listening.
Lab boundary
Section titled “Lab boundary”E1. The lab did not build or run a Go service; the commands are the deployment pattern to validate on Server 2025.