Deployment Guide

Overview

This guide covers deploying Weber applications to production environments. We'll explore various deployment strategies including traditional servers, containers, and cloud platforms.

Pre-Deployment Checklist

  • ✓ Update production configuration (config/prod.json)
  • ✓ Change session secret and API keys
  • ✓ Build frontend assets
  • ✓ Run all tests
  • ✓ Enable HTTPS/TLS
  • ✓ Configure database connections
  • ✓ Set up logging and monitoring
  • ✓ Configure backup strategy
  • ✓ Review security settings

Building for Production

Build Frontend

cd frontend
pnpm run build

Build Backend

# Build binary
go build -o weber main.go

# Or with optimizations
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-s -w' -o weber main.go

# Using Makefile
make build

Build Script

#!/bin/bash
# build.sh

set -e

echo "Building frontend..."
cd frontend
pnpm install
pnpm run build
cd ..

echo "Building backend..."
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o weber main.go

echo "Build complete!"
ls -lh weber

Docker Deployment

Dockerfile

# Multi-stage build
FROM node:18-alpine AS frontend-builder

WORKDIR /app/frontend
COPY frontend/package.json frontend/pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install
COPY frontend/ ./
RUN pnpm run build

# Go builder
FROM golang:1.21-alpine AS backend-builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-s -w' -o weber main.go

# Final image
FROM alpine:latest

RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/

# Copy binary
COPY --from=backend-builder /app/weber .

# Copy templates and static files
COPY --from=backend-builder /app/webroot ./webroot
COPY --from=frontend-builder /app/frontend/dist ./webroot/static

# Copy config
COPY config ./config

EXPOSE 8080

CMD ["./weber"]

Docker Compose

version: '3.8'

services:
  weber:
    build: .
    ports:
      - "8080:8080"
    environment:
      - WEBER_ENV=prod
      - WEBER_DB_HOST=postgres
    depends_on:
      - postgres
      - redis
    restart: unless-stopped
    volumes:
      - ./logs:/root/logs

  postgres:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=weber
      - POSTGRES_USER=weber
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - weber
    restart: unless-stopped

volumes:
  postgres_data:

Build and Run

# Build image
docker build -t weber:latest .

# Run container
docker run -d -p 8080:8080 --name weber weber:latest

# With docker-compose
docker-compose up -d

Traditional Server Deployment

Systemd Service

# /etc/systemd/system/weber.service
[Unit]
Description=Weber Web Application
After=network.target

[Service]
Type=simple
User=weber
Group=weber
WorkingDirectory=/opt/weber
Environment="WEBER_ENV=prod"
ExecStart=/opt/weber/weber
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Deployment Steps

# 1. Build application
make build

# 2. Copy to server
scp weber user@server:/opt/weber/
scp -r webroot user@server:/opt/weber/
scp -r config user@server:/opt/weber/

# 3. SSH to server
ssh user@server

# 4. Set permissions
sudo chown -R weber:weber /opt/weber
sudo chmod +x /opt/weber/weber

# 5. Enable and start service
sudo systemctl enable weber
sudo systemctl start weber

# 6. Check status
sudo systemctl status weber
sudo journalctl -u weber -f

Nginx Configuration

Reverse Proxy

# /etc/nginx/sites-available/weber
upstream weber_backend {
    server localhost:8080;
}

server {
    listen 80;
    server_name example.com www.example.com;
    
    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    # SSL certificates
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    
    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Strict-Transport-Security "max-age=31536000" always;
    
    # Static files
    location /static/ {
        alias /opt/weber/webroot/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    # Proxy to backend
    location / {
        proxy_pass http://weber_backend;
        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;
        
        # Timeouts
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }
    
    # Logging
    access_log /var/log/nginx/weber_access.log;
    error_log /var/log/nginx/weber_error.log;
}

Enable Site

sudo ln -s /etc/nginx/sites-available/weber /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Cloud Platform Deployment

AWS Elastic Beanstalk

# Dockerrun.aws.json
{
    "AWSEBDockerrunVersion": "1",
    "Image": {
        "Name": "your-repo/weber:latest",
        "Update": "true"
    },
    "Ports": [
        {
            "ContainerPort": 8080,
            "HostPort": 80
        }
    ],
    "Environment": [
        {
            "Name": "WEBER_ENV",
            "Value": "prod"
        }
    ]
}

Google Cloud Run

# Deploy to Cloud Run
gcloud run deploy weber \
    --image gcr.io/PROJECT_ID/weber \
    --platform managed \
    --region us-central1 \
    --allow-unauthenticated \
    --set-env-vars WEBER_ENV=prod

Heroku

# Procfile
web: ./weber

# Deploy
heroku create weber-app
heroku config:set WEBER_ENV=prod
git push heroku main

DigitalOcean App Platform

# .do/app.yaml
name: weber
services:
  - name: web
    github:
      repo: your-username/weber
      branch: main
    build_command: make build
    run_command: ./weber
    envs:
      - key: WEBER_ENV
        value: prod
    http_port: 8080

Kubernetes Deployment

Deployment YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: weber
spec:
  replicas: 3
  selector:
    matchLabels:
      app: weber
  template:
    metadata:
      labels:
        app: weber
    spec:
      containers:
      - name: weber
        image: your-repo/weber:latest
        ports:
        - containerPort: 8080
        env:
        - name: WEBER_ENV
          value: "prod"
        resources:
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "256Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: weber
spec:
  selector:
    app: weber
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer

Deploy

kubectl apply -f deployment.yaml
kubectl get pods
kubectl get services

Environment Variables

# Production environment variables
export WEBER_ENV=prod
export WEBER_PORT=8080
export WEBER_DB_HOST=prod-db.example.com
export WEBER_DB_PASSWORD=secret
export WEBER_REDIS_HOST=redis.example.com
export WEBER_SESSION_SECRET=change-this-secret
export WEBER_API_KEY=your-api-key

Monitoring and Logging

Application Logging

# Log to file with rotation
{
    "logging": {
        "level": "info",
        "output": "file",
        "file": "/var/log/weber/app.log",
        "max_size": 100,
        "max_backups": 5,
        "max_age": 30,
        "compress": true
    }
}

Monitoring with Prometheus

// Add metrics endpoint
func MetricsHandler(ctx *app.Context) {
    // Expose Prometheus metrics
    ctx.Text(200, promhttp.Handler())
}

Health Checks

// Health check endpoint
func HealthHandler(ctx *app.Context) {
    ctx.JSON(200, map[string]interface{}{
        "status": "ok",
        "timestamp": time.Now(),
    })
}

// Readiness check
func ReadyHandler(ctx *app.Context) {
    // Check dependencies
    if !checkDatabase() || !checkCache() {
        ctx.JSON(503, map[string]interface{}{
            "status": "not ready",
        })
        return
    }
    
    ctx.JSON(200, map[string]interface{}{
        "status": "ready",
    })
}

Backup Strategy

Database Backup

#!/bin/bash
# backup.sh

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups"

# Backup database
pg_dump -h localhost -U weber weber_db > $BACKUP_DIR/db_$DATE.sql

# Compress
gzip $BACKUP_DIR/db_$DATE.sql

# Delete old backups (keep 30 days)
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +30 -delete

echo "Backup completed: db_$DATE.sql.gz"

Cron Job

# Run backup daily at 2 AM
0 2 * * * /opt/weber/backup.sh

SSL/TLS Configuration

Let's Encrypt

# Install certbot
sudo apt-get install certbot python3-certbot-nginx

# Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com

# Auto-renewal (cron)
0 0 * * * certbot renew --quiet

Performance Optimization

  • Enable caching - Use Redis for session and data caching
  • CDN - Serve static assets through a CDN
  • Compression - Enable gzip/brotli compression
  • Database indexing - Optimize database queries
  • Connection pooling - Configure database connection pool
  • Load balancing - Distribute traffic across multiple instances
  • HTTP/2 - Enable HTTP/2 for better performance

Security Best Practices

  • Use HTTPS/TLS everywhere
  • Keep dependencies updated
  • Use strong secrets and rotate them regularly
  • Implement rate limiting
  • Enable security headers
  • Regular security audits
  • Firewall configuration
  • Database access controls
  • Regular backups
  • Monitor for suspicious activity

Continuous Deployment

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: 1.21
    
    - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
        node-version: 18
    
    - name: Build
      run: |
        cd frontend && pnpm install && pnpm run build
        go build -o weber main.go
    
    - name: Deploy
      run: |
        # Your deployment script
        ./deploy.sh

Rollback Strategy

# Keep previous version
cp weber weber.backup

# Deploy new version
./deploy.sh

# If issues occur, rollback
sudo systemctl stop weber
mv weber.backup weber
sudo systemctl start weber

Troubleshooting

Check Logs

# Application logs
tail -f /var/log/weber/app.log

# Systemd logs
sudo journalctl -u weber -f

# Nginx logs
tail -f /var/log/nginx/weber_error.log

Debug Production Issues

# Check service status
sudo systemctl status weber

# Check connections
sudo netstat -tlnp | grep 8080

# Check process
ps aux | grep weber

# Check disk space
df -h

# Check memory
free -h

Next Steps