首次提交:初始化项目
This commit is contained in:
389
.claude/skills/caddy/SKILL.md
Normal file
389
.claude/skills/caddy/SKILL.md
Normal file
@@ -0,0 +1,389 @@
|
||||
---
|
||||
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)
|
||||
Reference in New Issue
Block a user