Why self-host a Go API on a VPS
Unlike Java or Node, a Go application (with the Gin framework) compiles into a single static binary that needs neither an interpreter, nor a runtime, nor a shared library. You can literally drop the binary onto a VPS and run it. This lightness changes everything for self-hosting: a Gin API runs in 15 to 30 MB of RAM and starts in a few milliseconds; the throughput it sustains depends on what your handler does, and is measured against your own workload. On a VPS, you make the most of this efficiency: an entry-level server is enough to serve a load that interpreted languages would require a much bigger machine for. You also avoid the complexity of bulky Docker images: a 10 MB scratch image is enough.
Concrete benefits
- Single static binary: no runtime to install, deployment by a simple file copy
- Tiny memory footprint (15-30 MB) allowing you to saturate a small VPS with requests
scratchordistrolessDocker image of 10-15 MB: near-instant builds and pulls- Startup in milliseconds: redeployments and restarts with no perceptible interruption
- Native concurrency via goroutines: a single vCPU handles thousands of simultaneous connections
- Reduced attack surface: no interpreter or system packages to patch
Hardware and software prerequisites
This is where Go shines: a Gin API without a database fits on a VPS with 1 vCPU and 1 GB of RAM, and stays at ease. With co-located PostgreSQL, aim for 2 GB to be comfortable. You don't even need Go on the server if you compile in CI or by local cross-compilation (GOOS=linux GOARCH=amd64 go build). Install Docker if you containerize, or nothing at all if you launch the binary directly under systemd. Point an api.mydomain.com domain at the VPS IP via an A record. 5 GB of disk is more than enough.
Step-by-step deployment
Cross-compile the binary for Linux
From your workstation, run
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .. TheCGO_ENABLED=0flag guarantees a 100% static binary, indispensable for ascratchimage. You get anappexecutable ready to run on any Linux.Build a minimal Docker image
Write a multi-stage Dockerfile: a
golang:1.22-alpinestage to compile, thenFROM scratchwhich copies only the binary and the CA certificates (COPY --from=builder /etc/ssl/certs ...). The final image weighs about ten MB. Expose port 8080.Configure Gin for production
Switch Gin to release mode with
gin.SetMode(gin.ReleaseMode)or theGIN_MODE=releasevariable to disable the verbose debug logs. Read the port and the secrets from the environment (os.Getenv), never hard-coded in the code.Launch the container
Start with
docker run -d --restart unless-stopped -p 127.0.0.1:8080:8080 -e GIN_MODE=release monapp:latest. By binding on127.0.0.1, you expose Gin only to the local reverse proxy, not directly to the Internet.Place Nginx or Caddy in front
Configure a reverse proxy to
http://127.0.0.1:8080. Caddy is particularly well suited here: with a simplereverse_proxy localhost:8080directive, it automatically provisions the HTTPS certificate without Certbot.Secure with TLS
With Caddy, HTTPS is automatic as soon as the domain points to the VPS. With Nginx, run
certbot --nginx -d api.mydomain.com. Then check the TLS chain withcurl -I https://api.mydomain.com.
Enable Go's pprof profiling behind a protected endpoint: import _ "net/http/pprof" exposed on an internal port only accessible via an SSH tunnel. You get CPU and memory flame graphs in real production without noticeable overhead. Also consider compiling with -ldflags="-s -w" to reduce the binary size by 30% by removing the debug tables.
Deploy Go (Gin) in One Click from the ServOrbit Marketplace
The ServOrbit Marketplace offers a preconfigured Go (Gin) Stack template: Go 1.22+ from the official go.dev binary, Nginx, and PostgreSQL 16 are installed automatically on your VPS from the order form. No SSH session for the base setup — you arrive directly at the step of compiling your project and uploading the binary. The marketplace page contains the exact specifications, use cases, and a first-connection guide.