390 lines
8.3 KiB
Markdown
390 lines
8.3 KiB
Markdown
---
|
|
name: caddy-ssl-termination
|
|
description: 专门用于 Traefik 前置 Caddy 进行 SSL 卸载的架构配置,适用于 K3s 环境。
|
|
---
|
|
|
|
|
|
# Caddy SSL Termination Skill
|
|
|
|
## Architecture Overview
|
|
|
|
**Setup**: Traefik (routing) → Caddy (HTTPS/SSL termination) → HTTP backend
|
|
|
|
- **Caddy**: Handles HTTPS (443) with automatic SSL certificates, forwards to Traefik on HTTP (80)
|
|
- **Traefik**: Routes HTTP traffic to appropriate backend services
|
|
- **Flow**: Internet → Caddy:443 (HTTPS) → Traefik:80 (HTTP) → Backend Pods
|
|
|
|
## Quick Configuration Template
|
|
|
|
### 1. Basic Caddyfile Structure
|
|
|
|
```caddy
|
|
# /etc/caddy/Caddyfile
|
|
|
|
# Domain configuration
|
|
example.com {
|
|
reverse_proxy traefik-service:80
|
|
}
|
|
|
|
# Multiple domains
|
|
app1.example.com {
|
|
reverse_proxy traefik-service:80
|
|
}
|
|
|
|
app2.example.com {
|
|
reverse_proxy traefik-service:80
|
|
}
|
|
|
|
# Wildcard subdomain (requires DNS wildcard)
|
|
*.example.com {
|
|
reverse_proxy traefik-service:80
|
|
}
|
|
```
|
|
|
|
### 2. ConfigMap for Caddyfile
|
|
|
|
```yaml
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: caddy-config
|
|
namespace: default
|
|
data:
|
|
Caddyfile: |
|
|
# Global options
|
|
{
|
|
email your-email@example.com
|
|
# Use Let's Encrypt staging for testing
|
|
# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
|
|
}
|
|
|
|
# Your domains
|
|
example.com {
|
|
reverse_proxy traefik-service:80 {
|
|
header_up Host {host}
|
|
header_up X-Real-IP {remote}
|
|
header_up X-Forwarded-For {remote}
|
|
header_up X-Forwarded-Proto {scheme}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Caddy Deployment
|
|
|
|
```yaml
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: caddy
|
|
namespace: default
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: caddy
|
|
template:tadata:
|
|
labels:
|
|
app: caddy
|
|
spec:
|
|
containers:
|
|
- name: caddy
|
|
image: caddy:latest
|
|
ports:
|
|
- containerPort: 80
|
|
- containerPort: 443
|
|
- containerPort: 2019 # Admin API
|
|
volumeMounts:
|
|
- name: config
|
|
mountPath: /etc/caddy
|
|
- name: data
|
|
mountPath: /data
|
|
- name: config-cache
|
|
mountPath: /config
|
|
volumes:
|
|
- name: config
|
|
configMap:
|
|
name: caddy-config
|
|
- name: data
|
|
persistentVolumeClaim:
|
|
claimName: caddy-data
|
|
- name: config-cache
|
|
emptyDir: {}
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: caddy
|
|
namespace: default
|
|
spec:
|
|
type: LoadBalancer # or NodePort
|
|
ports:
|
|
- name: http
|
|
port: 80
|
|
targetPort: 80
|
|
- name: https
|
|
port: 443
|
|
targetPort: 443
|
|
selector:
|
|
app: caddy
|
|
---
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: caddy-data
|
|
namespace: default
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 1Gi
|
|
```
|
|
|
|
## Common Operations
|
|
|
|
### Reload Configuration
|
|
|
|
After updating the ConfigMap:
|
|
|
|
```bash
|
|
# Method 1: Reload via exec (preserves connections)
|
|
kubectl exec -n default deployment/caddy -- caddy reload --config /etc/caddy/Caddyfile
|
|
|
|
# Method 2: Restart pod (brief downtime)
|
|
kubectl rollout restart deployment/caddy -n default
|
|
|
|
# Method 3: Delete pod (auto-recreates)
|
|
kubectl delete pod -n default -l app=caddy
|
|
```
|
|
|
|
### Update Caddyfile
|
|
|
|
```bash
|
|
# Edit ConfigMap
|
|
kubectl edit configmap caddy-config -n default
|
|
|
|
# Or apply updated file
|
|
kubectl apply -f caddy-configmap.yaml
|
|
|
|
# Then reload
|
|
kubectl exec -n default deployment/caddy -- caddy reload --config /etc/caddy/Caddyfile
|
|
```
|
|
|
|
### View Logs
|
|
|
|
```bash
|
|
# Follow logs
|
|
kubectl logs -n default -f deployment/caddy
|
|
|
|
# Check SSL certificate issues
|
|
kubectl logs -n default deployment/caddy | grep -i "certificate\|acme\|tls"
|
|
```
|
|
|
|
### Check Configuration
|
|
|
|
```bash
|
|
# Validate Caddyfile syntax
|
|
kubectl exec -n default deployment/caddy -- caddy validate --config /etc/caddy/Caddyfile
|
|
|
|
# View current config via API
|
|
kubectl exec -n default deployment/caddy -- curl localhost:2019/config/
|
|
```
|
|
|
|
## Adding New Domain
|
|
|
|
### Step-by-step Process
|
|
|
|
1. **Update DNS**: Point new domain to Caddy's LoadBalancer IP
|
|
```bash
|
|
kubectl get svc caddy -n default -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
|
|
```
|
|
|
|
2. **Update ConfigMap**: Add new domain block
|
|
```bash
|
|
kubectl edit configmap caddy-config -n default
|
|
```
|
|
|
|
Add:
|
|
```caddy
|
|
newapp.example.com {
|
|
reverse_proxy traefik-service:80 {
|
|
header_up Host {host}
|
|
header_up X-Real-IP {remote}
|
|
header_up X-Forwarded-For {remote}
|
|
header_up X-Forwarded-Proto {scheme}
|
|
}
|
|
}
|
|
```
|
|
|
|
3. **Reload Caddy**:
|
|
```bash
|
|
kubectl exec -n default deployment/caddy -- caddy reload --config /etc/caddy/Caddyfile
|
|
```
|
|
|
|
4. **Verify**: Check logs for certificate acquisition
|
|
```bash
|
|
kubectl logs -n default deployment/caddy | tail -20
|
|
```
|
|
|
|
## Traefik Integration
|
|
|
|
### Traefik IngressRoute Example
|
|
|
|
```yaml
|
|
apiVersion: traefik.containo.us/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: myapp
|
|
namespace: default
|
|
spec:
|
|
entryPoints:
|
|
- web # HTTP only, Caddy handles HTTPS
|
|
routes:
|
|
- match: Host(`myapp.example.com`)
|
|
kind: Rule
|
|
services:
|
|
- name: myapp-service
|
|
port: 8080
|
|
```
|
|
|
|
### Important Notes
|
|
|
|
- Traefik should listen on HTTP (80) only
|
|
- Caddy handles all HTTPS/SSL
|
|
- Use `Host()` matcher in Traefik to route by domain
|
|
- Caddy forwards the original `Host` header to Traefik
|
|
|
|
## Troubleshooting
|
|
|
|
### SSL Certificate Issues
|
|
|
|
```bash
|
|
# Check certificate status
|
|
kubectl exec -n default deployment/caddy -- caddy list-certificates
|
|
|
|
# View ACME logs
|
|
kubectl logs -n default deployment/caddy | grep -i acme
|
|
|
|
# Common issues:
|
|
# - Port 80/443 not accessible from internet
|
|
# - DNS not pointing to correct IP
|
|
# - Rate limit hit (use staging CA for testing)
|
|
```
|
|
|
|
### Configuration Errors
|
|
|
|
```bash
|
|
# Test config before reload
|
|
kubectl exec -n default deployment/caddy -- caddy validate --config /etc/caddy/Caddyfile
|
|
|
|
# Check for syntax errors
|
|
kubectl logs -n default deployment/caddy | grep -i error
|
|
```
|
|
|
|
### Connection Issues
|
|
|
|
```bash
|
|
# Test from inside cluster
|
|
kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- curl -v http://traefik-service:80
|
|
|
|
# Check if Caddy can reach Traefik
|
|
kubectl exec -n default deployment/caddy -- curl -v http://traefik-service:80
|
|
```
|
|
|
|
## Advanced Configurations
|
|
|
|
### Custom TLS Settings
|
|
|
|
```caddy
|
|
example.com {
|
|
tls {
|
|
protocols tls1.2 tls1.3
|
|
ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
}
|
|
reverse_proxy traefik-service:80
|
|
}
|
|
```
|
|
|
|
### Rate Limiting
|
|
|
|
```caddy
|
|
example.com {
|
|
rate_limit {
|
|
zone dynamic {
|
|
key {remote_host}
|
|
events 100
|
|
window 1m
|
|
}
|
|
}
|
|
reverse_proxy traefik-service:80
|
|
}
|
|
```
|
|
|
|
### Custom Error Pages
|
|
|
|
```caddy
|
|
example.com {
|
|
handle_errors {
|
|
respond "{err.status_code} {err.status_text}"
|
|
}
|
|
reverse_proxy traefik-service:80
|
|
}
|
|
```
|
|
|
|
### Health Checks
|
|
|
|
```caddy
|
|
example.com {
|
|
reverse_proxy traefik-service:80 {
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
}
|
|
}
|
|
```
|
|
|
|
## Quick Reference Commands
|
|
|
|
```bash
|
|
# Get Caddy pod name
|
|
kubectl get pods -n default -l app=caddy
|
|
|
|
# Reload config
|
|
kubectl exec -n default deployment/caddy -- caddy reload --config /etc/caddy/Caddyfile
|
|
|
|
# View current config
|
|
kubectl exec -n default deployment/caddy -- cat /etc/caddy/Caddyfile
|
|
|
|
# Check certificates
|
|
kubectl exec -n default deployment/caddy -- caddy list-certificates
|
|
|
|
# Restart Caddy
|
|
kubectl rollout restart deployment/caddy -n default
|
|
|
|
# Watch logs
|
|
kubectl logs -n default -f deployment/caddy
|
|
|
|
# Get LoadBalancer IP
|
|
kubectl get svc caddy -n default -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
|
|
```
|
|
|
|
## Checklist for New Service
|
|
|
|
- [ ] DNS A/AAAA record points to Caddy LoadBalancer IP
|
|
- [ ] Domain added to Caddy ConfigMap
|
|
- [ ] Caddy reloaded successfully
|
|
- [ ] Traefik IngressRoute created (HTTP only)
|
|
- [ ] Backend service accessible from Traefik
|
|
- [ ] SSL certificate acquired (check logs)
|
|
- [ ] HTTPS access working from browser
|
|
- [ ] HTTP redirects to HTTPS (Caddy default behavior)
|
|
|
|
## Notes
|
|
|
|
- Caddy automatically obtains and renews SSL certificates
|
|
- Certificates stored in `/data` volume (must be persistent)
|
|
- Reload is graceful - no connection drops
|
|
- Caddy handles HTTP→HTTPS redirect automatically
|
|
- Use staging CA for testing to avoid rate limits
|
|
- Wildcard certificates require DNS challenge (more complex setup)
|