Introduction: From Development to Production Server on Go
You have written a high-performance web application in Go (Golang). Compilation into a single binary, static typing, built-in networking — all of this gives it an edge over Node.js or Python. But "it works on my machine" is not an argument for production. Advanced deployment of a Go application on a VPS is not just copying files via SSH. It involves setting up a CI/CD pipeline, containerization, reverse proxy, automatic certificate renewal, monitoring, and graceful shutdown.
In this article, we will break down a complete production-ready scenario for a Golang application on Ubuntu 22.04 LTS. You will learn how to set up a Docker build, organize zero-downtime deployment via GitHub Actions, integrate Nginx with SSL, and configure monitoring with Prometheus metrics.
1. VPS Preparation and Environment Setup
Assume you have a VPS (DigitalOcean, Hetzner, Timeweb) with Ubuntu 22.04. First, update the system and install a basic set of tools:
ssh root@your_server_ipapt update && apt upgrade -yapt install -y git curl htop net-tools ufwCreate a user deploy with sudo privileges (no password, SSH key only):
adduser deployusermod -aG sudo deploymkdir /home/deploy/.sshcp ~/.ssh/authorized_keys /home/deploy/.ssh/chown -R deploy:deploy /home/deploy/.sshchmod 700 /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keysConfigure the UFW firewall:
ufw allow OpenSSHufw allow 80/tcpufw allow 443/tcpufw enableImportant: Disable root login in /etc/ssh/sshd_config (PermitRootLogin no) and restart SSH (systemctl restart sshd).
1.1 Installing Docker and Docker Compose
For a Go application, containerization is the de facto standard. Install Docker using the official instructions:
curl -fsSL https://get.docker.com -o get-docker.shsh get-docker.shusermod -aG docker deployCheck the version: docker --version. Next, install Docker Compose v2 (plugin):
apt install -y docker-compose-plugin2. CI/CD Pipeline with GitHub Actions and Docker
Advanced deployment implies automation. We will use GitHub Actions to build the image and send it to the server via SSH, followed by launching a new container.
Project structure in Go:
myapp/├── main.go├── go.mod├── Dockerfile├── docker-compose.yml└── .github/workflows/deploy.ymlDockerfile (Multi-stage build):
FROM golang:1.22-alpine AS builderWORKDIR /appCOPY go.mod go.sum ./RUN go mod downloadCOPY . .RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/myapp .
FROM alpine:latestRUN apk --no-cache add ca-certificates tzdataWORKDIR /root/COPY --from=builder /app/myapp .EXPOSE 8080CMD ["./myapp"]docker-compose.yml (for production):
version: '3.8'services: app: image: ghcr.io/your_username/myapp:latest restart: always ports: - "127.0.0.1:8080:8080" environment: - DB_URL=postgres://user:pass@db:5432/mydb depends_on: - db db: image: postgres:16-alpine restart: always environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass volumes: - pg_data:/var/lib/postgresql/datavolumes: pg_data:GitHub Actions workflow (.github/workflows/deploy.yml):
name: Deploy Go Appon: push: branches: [ main ]jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io