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