Deployment Guide
This guide covers deploying forge applications to production environments.
Pre-Deployment Checklist​
Before deploying, ensure:
- All tests pass
- Migrations are tested
- Environment variables are configured
- Database is backed up
- HTTPS is configured
- Security settings are reviewed and hardened
- Logging is configured
- Monitoring is set up
Configuration​
Environment Variables​
Use environment variables for sensitive configuration:
export FORGE_DATABASE_HOST=db.example.com
export FORGE_DATABASE_NAME=myapp_prod
export FORGE_DATABASE_USER=myapp_user
export FORGE_DATABASE_PASSWORD=secure_password
export FORGE_SECRET_KEY=your-secret-key
export FORGE_DEBUG=false
Production Config​
Create config/production.yaml:
app:
name: "My Application"
env: "production"
debug: false
server:
host: "0.0.0.0"
port: "8080"
read_timeout: 30s
write_timeout: 30s
database:
host: "${FORGE_DATABASE_HOST}"
port: 5432
user: "${FORGE_DATABASE_USER}"
password: "${FORGE_DATABASE_PASSWORD}"
dbname: "${FORGE_DATABASE_NAME}"
sslmode: "require"
max_connections: 25
max_idle_connections: 5
security:
secret_key: "${FORGE_SECRET_KEY}"
csrf_secret_key: "${FORGE_CSRF_SECRET_KEY}"
session_secret: "${FORGE_SESSION_SECRET}"
csrf:
enabled: true
secure: true
session:
secure: true
http_only: true
same_site: "strict"
logging:
level: "info"
format: "json"
output: "stdout"
Building for Production​
Build Binary​
# Build for Linux
GOOS=linux GOARCH=amd64 go build -o myapp ./cmd/server
# Or use Makefile
make build
Optimize Build​
# Build with optimizations
go build -ldflags="-s -w" -o myapp ./cmd/server
# Reduce binary size
strip myapp
Database Setup​
Run Migrations​
# Apply all migrations
forge migrate
# Or manually
./myapp migrate
Verify Database​
# Check migration status
forge migrate status
# Verify connection
psql -h db.example.com -U myapp_user -d myapp_prod -c "SELECT version();"
Deployment Options​
Docker Deployment​
Create Dockerfile:
FROM golang:1.21-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 myapp ./cmd/server
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
COPY --from=builder /app/config ./config
COPY --from=builder /app/migrations ./migrations
EXPOSE 8080
CMD ["./myapp"]
Build and run:
docker build -t myapp:latest .
docker run -d -p 8080:8080 \
-e FORGE_DATABASE_HOST=db.example.com \
-e FORGE_SECRET_KEY=your-secret-key \
myapp:latest
Docker Compose​
Create docker-compose.yml:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- FORGE_DATABASE_HOST=db
- FORGE_DATABASE_NAME=myapp_prod
- FORGE_SECRET_KEY=${FORGE_SECRET_KEY}
depends_on:
- db
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=myapp_prod
- POSTGRES_USER=myapp_user
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:
Deploy:
docker-compose up -d
Systemd Service​
Create /etc/systemd/system/myapp.service:
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/myapp
Restart=always
RestartSec=5
Environment="FORGE_DATABASE_HOST=db.example.com"
Environment="FORGE_SECRET_KEY=your-secret-key"
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp
Kubernetes Deployment​
Create k8s/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
env:
- name: FORGE_DATABASE_HOST
valueFrom:
secretKeyRef:
name: myapp-secrets
key: database-host
- name: FORGE_SECRET_KEY
valueFrom:
secretKeyRef:
name: myapp-secrets
key: secret-key
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Reverse Proxy​
Nginx Configuration​
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
location / {
proxy_pass http://localhost:8080;
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;
}
}
Caddy Configuration​
example.com {
reverse_proxy localhost:8080
}
Monitoring​
Health Checks​
Add health check endpoint:
router.Get("/health", func(w http.ResponseWriter, r *http.Request) {
// Check database connection
if err := db.Ping(); err != nil {
http.Error(w, "Database unavailable", http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
Logging​
Configure structured logging:
logging:
level: "info"
format: "json"
output: "stdout"
fields:
service: "myapp"
environment: "production"
Metrics​
Add Prometheus metrics:
import "github.com/prometheus/client_golang/prometheus"
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total HTTP requests",
},
[]string{"method", "endpoint", "status"},
)
)
Backup and Recovery​
Database Backups​
# Automated backup script
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
pg_dump -h db.example.com -U myapp_user myapp_prod > backup_$DATE.sql
# Restore
psql -h db.example.com -U myapp_user myapp_prod < backup_20240101_120000.sql
Application Backups​
# Backup application files
tar -czf myapp_backup_$(date +%Y%m%d).tar.gz \
/opt/myapp/myapp \
/opt/myapp/config \
/opt/myapp/migrations
Rollback Procedure​
Application Rollback​
# Stop current version
sudo systemctl stop myapp
# Restore previous binary
cp myapp.backup myapp
# Start service
sudo systemctl start myapp
Database Rollback​
# Rollback migrations
forge migrate down 1
# Or restore from backup
psql -h db.example.com -U myapp_user myapp_prod < backup.sql
Performance Tuning​
Database Connection Pool​
database:
max_connections: 25
max_idle_connections: 5
max_lifetime: 5m
Application Settings​
server:
read_timeout: 30s
write_timeout: 30s
idle_timeout: 120s
max_header_bytes: 1048576
Security in Production​
- Use HTTPS only
- Set secure cookies
- Enable CSRF protection
- Use strong secret keys
- Limit database connections
- Enable rate limiting
- Monitor for attacks
- Regular security updates
Troubleshooting​
Check Logs​
# Application logs
sudo journalctl -u myapp -f
# Docker logs
docker logs -f myapp
# Nginx logs
tail -f /var/log/nginx/error.log
Common Issues​
-
Database Connection Errors
- Check database is running
- Verify credentials
- Check network connectivity
-
Migration Failures
- Check migration status
- Verify database permissions
- Review migration SQL
-
Performance Issues
- Check database connection pool
- Review query performance
- Monitor resource usage
Next Steps​
- Security Guide - Production security
- Monitoring - Performance monitoring
- Development Guide - Contributing