← Back to gin-gonic/gin

How to Deploy & Use gin-gonic/gin

Gin Web Framework Deployment & Usage Guide

1. Prerequisites

  • Go: Version 1.24 or higher (download)
  • Git: For cloning repositories and managing dependencies
  • Optional: air for hot reload during development (go install github.com/cosmtrek/air@latest)

Verify Go installation:

go version

2. Installation

Initialize a New Project

mkdir my-gin-app && cd my-gin-app
go mod init example.com/my-gin-app

Install Gin

go get -u github.com/gin-gonic/gin

Or simply import in your code and Go modules will auto-fetch:

import "github.com/gin-gonic/gin"

Download Examples (Optional)

git clone https://github.com/gin-gonic/examples.git
cd examples

3. Configuration

Environment Variables

VariableDescriptionDefault
GIN_MODERuntime mode: debug, release, or testdebug
PORTServer port (if using os.Getenv("PORT"))8080

Basic Configuration Setup

package main

import (
    "os"
    "github.com/gin-gonic/gin"
)

func main() {
    // Set mode via environment
    ginMode := os.Getenv("GIN_MODE")
    if ginMode == "" {
        ginMode = gin.DebugMode
    }
    gin.SetMode(ginMode)
    
    r := gin.Default()
    
    // Trust specific CIDRs (security)
    r.SetTrustedProxies([]string{"192.168.1.0/24", "10.0.0.0/8"})
    
    // Or trust all (not recommended for production)
    // r.SetTrustedProxies(nil)
    
    r.GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{"status": "running"})
    })
    
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    r.Run(":" + port)
}

TLS/HTTPS Configuration

// Auto TLS with Let's Encrypt
r.RunAutoTLS(":443")

// Manual TLS
r.RunTLS(":443", "server.crt", "server.key")

HTTP/2 and HTTP/3 Support

// HTTP/2 (enabled by default with TLS)
r.RunTLS(":443", "cert.pem", "key.pem")

// HTTP/3 (QUIC) - requires quic-go
r.RunQUIC(":443", "cert.pem", "key.pem")

4. Build & Run

Development Mode

Run with hot reload (requires air):

air

Standard run:

go run main.go

Production Build

Build optimized binary:

# Set production mode
export GIN_MODE=release

# Build for current platform
go build -o server main.go

# Cross-compile for Linux
GOOS=linux GOARCH=amd64 go build -o server-linux main.go

# Run
./server

Build Flags for Production

# Strip debug symbols, optimize
go build -ldflags="-s -w" -o server main.go

# With CGO disabled (for static linking)
CGO_ENABLED=0 go build -ldflags="-s -w" -o server main.go

5. Deployment

Docker Deployment

Dockerfile (multi-stage build):

# Build stage
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o server .

# Runtime stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/server .
EXPOSE 8080
ENV GIN_MODE=release
CMD ["./server"]

Build and run:

docker build -t my-gin-app .
docker run -p 8080:8080 -e GIN_MODE=release my-gin-app

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gin-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: gin-app
  template:
    metadata:
      labels:
        app: gin-app
    spec:
      containers:
      - name: gin
        image: my-gin-app:latest
        ports:
        - containerPort: 8080
        env:
        - name: GIN_MODE
          value: "release"
        resources:
          limits:
            memory: "256Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: gin-service
spec:
  selector:
    app: gin-app
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

Cloud Platform Deployment

Google Cloud Run:

gcloud run deploy gin-app --source . --platform managed --region us-central1

AWS Lambda (using gin-lambda adapter):

import "github.com/awslabs/aws-lambda-go-api-proxy/gin"

Heroku:

# Create Procfile
echo 'web: bin/server' > Procfile

# Set Go version in go.mod (1.24+)
git push heroku main

Systemd Service (Linux Server)

Create /etc/systemd/system/gin-app.service:

[Unit]
Description=Gin Web Application
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/my-gin-app
ExecStart=/var/www/my-gin-app/server
Environment="GIN_MODE=release"
Environment="PORT=8080"
Restart=on-failure

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl enable gin-app
sudo systemctl start gin-app

6. Troubleshooting

Port Already in Use

Error: bind: address already in use

Solution:

# Find process using port 8080
lsof -i :8080

# Kill process or change port
PORT=3000 go run main.go

CORS Issues

Install middleware:

go get github.com/gin-contrib/cors

Usage:

import "github.com/gin-contrib/cors"

func main() {
    r := gin.Default()
    r.Use(cors.Default())
    // or custom config
    r.Use(cors.New(cors.Config{
        AllowOrigins: []string{"https://example.com"},
        AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
    }))
}

Memory Issues with File Uploads

Default multipart memory is 32MB. Increase if needed:

r.MaxMultipartMemory = 64 << 20 // 64 MiB

Static Files Not Serving

Ensure path is absolute:

r.Static("/assets", "./static")
// Or use embed for production
import "embed"
//go:embed static/*
var staticFS embed.FS
r.StaticFS("/assets", http.FS(staticFS))

"Too Many Open Files" Error

Increase ulimit:

ulimit -n 4096

Or in systemd service:

LimitNOFILE=65535

HTTP/3 Not Working

Ensure certificates are valid and quic-go is properly imported:

go get github.com/quic-go/quic-go

Request Timeout Issues

Set custom timeouts:

srv := &http.Server{
    Addr:         ":8080",
    Handler:      r,
    ReadTimeout:  30 * time.Second,
    WriteTimeout: 30 * time.Second,
}
srv.ListenAndServe()