Why Go is an Ideal Candidate for Production, but Deployment Still Decides Everything
\n\nYou wrote a backend in Go. It flies: compilation into a single binary, minimal memory consumption, goroutines that aren't afraid of load. But there's a nuance: even the fastest code is useless if it sits as dead weight on a local machine. Sooner or later, the question arises: how do you roll this marvel of engineering out to production?
\n\nDeploying Go applications is not rocket science, but it's easy to step on a rake here. In this article, we'll break down three main paths: classic VPS, containerization with Docker, and cloud platforms. You'll learn which approach to choose for your task and get ready-made scripts to get started.
\n\nDeploying Go on VPS: A Classic That Never Gets Old
\n\nA Virtual Private Server (VPS) is your personal root. Full control, no platform restrictions, but all responsibility lies with you. For a Go application, this is often the optimal option: the binary weighs 10–20 MB, starts in milliseconds, and doesn't require complex orchestration.
\n\nWhat You Need for Deploying Go on VPS
\n\n- \n
- Server with Linux (Ubuntu 22.04 / Debian 11 — the classics) \n
- SSH access \n
- Go (optional, if compiling on the server) \n
- Systemd for process management \n
- Nginx or Caddy as a reverse proxy \n
Example: Deploying a Go Server via Systemd
\n\nLet's say you have a simple application main.go that listens on port 8080. Compile it on your machine for the target architecture:
GOOS=linux GOARCH=amd64 go build -o app main.go\n\nCopy the binary to the server:
\n\nscp app user@your-server:/opt/app/\n\nCreate a systemd unit at /etc/systemd/system/app.service:
[Unit]\nDescription=Go App\nAfter=network.target\n\n[Service]\nExecStart=/opt/app/app\nWorkingDirectory=/opt/app\nRestart=always\nUser=www-data\nGroup=www-data\nEnvironment=PORT=8080\n\n[Install]\nWantedBy=multi-user.target\n\nStart and enable auto-start:
\n\nsudo systemctl daemon-reload\nsudo systemctl enable --now app\n\nNow your Go application runs as a daemon. Add Nginx for proxying from port 80:
\n\nserver {\n listen 80;\n server_name yourdomain.com;\n\n location / {\n proxy_pass http://127.0.0.1:8080;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n }\n}\n\nVPS Pros: full control, low cost (from $5/month), transparency. Cons: manual updates, no autoscaling, need to configure security yourself.
\n\nDocker for Go: Containerization That Simplifies Life
\n\nIf you work in a team or plan microservices, Docker is your choice. Go and Docker are a perfect pair: multi-stage builds produce images sized 5–15 MB, and static compilation allows you to do without a base image.
\n\nDockerfile for a Go Application
\n\nHere is a minimal but production-ready Dockerfile:
\n\n# Stage 1: build\nFROM golang:1.22-alpine AS builder\nWORKDIR /app\nCOPY go.mod go.sum ./\nRUN go mod download\nCOPY . .\nRUN CGO_ENABLED=0 GOOS=linux go build -o app .\n\n# Stage 2: minimal image\nFROM alpine:latest\nRUN apk --no-cache add ca-certificates\nWORKDIR /root/\nCOPY --from=builder /app/app .\nEXPOSE 8080\nCMD ["./app"]\n\nBuild and run:
\n\ndocker build -t go-app .\ndocker run -d -p 8080:8080 --name go-app go-app\n\nDocker Compose for a Full Setup
\n\nWhen the application needs a database or Redis, use docker-compose.yml:
version: '3.8'\nservices:\n app:\n build: .\n ports:\n - "8080:8080"\n environment:\n - DB_HOST=db\n - DB_PORT=5432\n depends_on:\n - db\n db:\n image: postgres