Go ist eine kompilierte Sprache, die statisch gelinkte Binaries erzeugt. Go-Webserver sind schnell, ressourcenschonend und einfach zu deployen - ein einzelnes Binary ohne externe Abhängigkeiten.
Go installieren
Offizielle Installation
# Download
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
# Entpacken
sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
# PATH setzen
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
echo 'export GOPATH=$HOME/go' >> ~/.bashrc
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bashrc
source ~/.bashrc
# Prüfen
go versionDebian/Ubuntu
apt install golang-goEinfacher Webserver
main.go
// main.go
package main
import (
"encoding/json"
"log"
"net/http"
"os"
)
type Response struct {
Message string `json:"message"`
Status string `json:"status"`
}
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/", homeHandler)
http.HandleFunc("/health", healthHandler)
http.HandleFunc("/api/data", apiHandler)
log.Printf("Server startet auf Port %s", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(Response{
Message: "Hello from Go!",
Status: "ok",
})
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "healthy"})
}
func apiHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
data := map[string]interface{}{
"items": []string{"item1", "item2", "item3"},
"count": 3,
}
json.NewEncoder(w).Encode(data)
}Mit Router (Chi)
// main.go
package main
import (
"encoding/json"
"log"
"net/http"
"os"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
r := chi.NewRouter()
// Middleware
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.RealIP)
// Routes
r.Get("/", homeHandler)
r.Get("/health", healthHandler)
r.Route("/api", func(r chi.Router) {
r.Get("/users", getUsersHandler)
r.Post("/users", createUserHandler)
r.Get("/users/{id}", getUserHandler)
})
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("Server startet auf :%s", port)
http.ListenAndServe(":"+port, r)
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"message": "Hello"})
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}
func getUsersHandler(w http.ResponseWriter, r *http.Request) {
// Users zurückgeben
}
func createUserHandler(w http.ResponseWriter, r *http.Request) {
// User erstellen
}
func getUserHandler(w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "id")
json.NewEncoder(w).Encode(map[string]string{"id": userID})
}Binary kompilieren
Für Linux
# Auf Linux
go build -o myapp main.go
# Cross-Compile von macOS/Windows
GOOS=linux GOARCH=amd64 go build -o myapp main.goOptimiertes Build
# Mit Optimierungen
CGO_ENABLED=0 GOOS=linux go build \
-ldflags="-w -s" \
-o myapp main.go
# -w: Keine DWARF Debug-Info
# -s: Keine Symbol-TabelleMit Version
VERSION=$(git describe --tags --always)
BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
go build -ldflags="-X main.Version=$VERSION -X main.BuildTime=$BUILD_TIME" -o myapp// In main.go
var (
Version string
BuildTime string
)
func versionHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{
"version": Version,
"build_time": BuildTime,
})
}Deployment
Binary kopieren
# Auf Build-Server
go build -o myapp
# Auf Produktionsserver kopieren
scp myapp user@server:/var/www/myapp/Verzeichnisstruktur
mkdir -p /var/www/myapp
mkdir -p /var/log/myapp
# Binary
cp myapp /var/www/myapp/
# Berechtigungen
chown -R www-data:www-data /var/www/myapp
chmod +x /var/www/myapp/myappSystemd-Service
myapp.service
# /etc/systemd/system/myapp.service
[Unit]
Description=My Go Application
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment=PORT=8080
Environment=GIN_MODE=release
EnvironmentFile=-/var/www/myapp/.env
ExecStart=/var/www/myapp/myapp
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
# Resource Limits
LimitNOFILE=65535
MemoryMax=512M
# Security
NoNewPrivileges=true
PrivateTmp=true
StandardOutput=append:/var/log/myapp/app.log
StandardError=append:/var/log/myapp/error.log
[Install]
WantedBy=multi-user.targetService starten
systemctl daemon-reload
systemctl enable myapp
systemctl start myapp
systemctl status myappNginx Reverse Proxy
# /etc/nginx/sites-available/myapp
upstream goapp {
server 127.0.0.1:8080;
keepalive 64;
}
server {
listen 80;
server_name api.example.de;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.example.de;
ssl_certificate /etc/letsencrypt/live/api.example.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.de/privkey.pem;
access_log /var/log/nginx/myapp-access.log;
error_log /var/log/nginx/myapp-error.log;
location / {
proxy_pass http://goapp;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
location /static/ {
alias /var/www/myapp/static/;
expires 30d;
}
}ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginxUmgebungsvariablen
.env-Datei
# /var/www/myapp/.env
PORT=8080
DATABASE_URL=postgres://user:pass@localhost/myapp
REDIS_URL=redis://localhost:6379
LOG_LEVEL=infoIn Go laden
package main
import (
"os"
"github.com/joho/godotenv"
)
func init() {
godotenv.Load()
}
func main() {
dbURL := os.Getenv("DATABASE_URL")
// ...
}Graceful Shutdown
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
srv := &http.Server{
Addr: ":8080",
Handler: setupRoutes(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
// Server in Goroutine starten
go func() {
log.Println("Server startet auf :8080")
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("Server error: %v", err)
}
}()
// Auf Signal warten
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Server wird heruntergefahren...")
// Graceful Shutdown mit Timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("Shutdown error: %v", err)
}
log.Println("Server beendet")
}Docker
Dockerfile
# Build Stage
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /myapp
# Production Stage
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /myapp .
USER nobody:nobody
EXPOSE 8080
CMD ["./myapp"]docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- PORT=8080
- DATABASE_URL=postgres://user:pass@db/myapp
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:Deployment-Skript
#!/bin/bash
# deploy.sh
set -e
SERVER="user@server"
APP_PATH="/var/www/myapp"
APP_NAME="myapp"
echo "Building..."
CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o ${APP_NAME}
echo "Copying to server..."
scp ${APP_NAME} ${SERVER}:${APP_PATH}/${APP_NAME}.new
echo "Deploying..."
ssh ${SERVER} << EOF
cd ${APP_PATH}
mv ${APP_NAME}.new ${APP_NAME}
sudo systemctl restart ${APP_NAME}
EOF
echo "Done!"
rm ${APP_NAME}Zusammenfassung
| Komponente | Funktion | |------------|----------| | go build | Binary kompilieren | | Systemd | Process Management | | Nginx | Reverse Proxy |
| Flag | Funktion | |------|----------| | -ldflags="-w -s" | Kleineres Binary | | CGO_ENABLED=0 | Statisch gelinkt | | GOOS=linux | Cross-Compile |
| Datei | Funktion | |-------|----------| | /var/www/myapp/myapp | Binary | | /etc/systemd/system/myapp.service | Service | | .env | Umgebungsvariablen |
Fazit
Go-Anwendungen sind extrem einfach zu deployen. Ein einzelnes Binary ohne Abhängigkeiten macht das Deployment unkompliziert. Go-Server sind performant und ressourcenschonend. Graceful Shutdown ermöglicht Zero-Downtime-Deployments. Mit Docker lassen sich Go-Apps containerisieren. Für APIs und Microservices ist Go eine ausgezeichnete Wahl.