KVM CDN
Libvirt KVM CDN Configuration VM Provisioning Nginx Cache Reverse Proxy Edge Server GeoDNS Origin SSL Let's Encrypt Static Dynamic Content Delivery
| CDN Type | Technology | Cost | Control | Performance | เหมาะกับ |
|---|---|---|---|---|---|
| DIY (KVM+Nginx) | Self-managed | ต่ำ (VM cost) | เต็มที่ | ดีมาก | Custom needs |
| Cloudflare | Managed | ฟรี-$$$ | ปานกลาง | ดีมาก | ทั่วไป |
| CloudFront | AWS Managed | Pay-per-use | สูง | ดีมาก | AWS ecosystem |
| BunnyCDN | Managed | ถูกมาก | ปานกลาง | ดี | Budget friendly |
| Varnish+KVM | Self-managed | ต่ำ | เต็มที่ | ดีมาก | High traffic |
KVM VM Setup
# === Libvirt KVM — Create Edge Cache VM ===
# Create VM with virt-install
# virt-install \
# --name edge-cache-sgp \
# --ram 4096 \
# --vcpus 2 \
# --disk path=/var/lib/libvirt/images/edge-sgp.qcow2, size=100 \
# --os-variant ubuntu22.04 \
# --network bridge=br0 \
# --graphics none \
# --console pty, target_type=serial \
# --location http://archive.ubuntu.com/ubuntu/dists/jammy/main/installer-amd64/ \
# --extra-args 'console=ttyS0,115200n8 serial'
# virsh commands
# virsh list --all # List all VMs
# virsh start edge-cache-sgp # Start VM
# virsh shutdown edge-cache-sgp # Graceful shutdown
# virsh snapshot-create-as edge-cache-sgp snap1 "Before config"
# virsh snapshot-list edge-cache-sgp
# virsh dominfo edge-cache-sgp # VM info
# Clone VM for other regions
# virt-clone \
# --original edge-cache-sgp \
# --name edge-cache-tok \
# --file /var/lib/libvirt/images/edge-tok.qcow2
# Network — Bridge Configuration
# cat /etc/netplan/01-bridge.yaml
# network:
# version: 2
# ethernets:
# ens3:
# dhcp4: false
# bridges:
# br0:
# interfaces: [ens3]
# addresses: [10.0.1.10/24]
# gateway4: 10.0.1.1
# nameservers:
# addresses: [8.8.8.8, 1.1.1.1]
from dataclasses import dataclass
@dataclass
class EdgeNode:
name: str
region: str
ip: str
vcpu: int
ram_gb: int
disk_gb: int
status: str
nodes = [
EdgeNode("edge-sgp", "Singapore", "103.x.x.10", 2, 4, 100, "Running"),
EdgeNode("edge-tok", "Tokyo", "103.x.x.20", 2, 4, 100, "Running"),
EdgeNode("edge-hkg", "Hong Kong", "103.x.x.30", 2, 4, 100, "Running"),
EdgeNode("edge-bkk", "Bangkok", "103.x.x.40", 4, 8, 200, "Running"),
EdgeNode("origin", "Bangkok DC", "10.0.1.100", 8, 16, 500, "Running"),
]
print("=== CDN Edge Nodes ===")
for n in nodes:
print(f" [{n.name}] Region: {n.region} | IP: {n.ip}")
print(f" CPU: {n.vcpu} | RAM: {n.ram_gb}GB | Disk: {n.disk_gb}GB | {n.status}")
Nginx Cache Config
# === Nginx CDN Cache Configuration ===
# /etc/nginx/nginx.conf
# proxy_cache_path /var/cache/nginx/cdn
# levels=1:2
# keys_zone=cdn_cache:100m
# max_size=50g
# inactive=7d
# use_temp_path=off;
#
# server {
# listen 443 ssl http2;
# server_name cdn.example.com;
#
# ssl_certificate /etc/letsencrypt/live/cdn.example.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/cdn.example.com/privkey.pem;
#
# # Static content — long cache
# location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg|webp|mp4)$ {
# proxy_pass http://origin-server;
# proxy_cache cdn_cache;
# proxy_cache_valid 200 24h;
# proxy_cache_valid 404 1m;
# proxy_cache_key "$scheme$request_method$host$request_uri";
# proxy_cache_use_stale error timeout updating http_500 http_502;
# add_header X-Cache-Status $upstream_cache_status;
# add_header Cache-Control "public, max-age=86400";
# expires 24h;
# }
#
# # Dynamic content — short cache
# location /api/ {
# proxy_pass http://origin-server;
# proxy_cache cdn_cache;
# proxy_cache_valid 200 5m;
# proxy_cache_key "$scheme$request_method$host$request_uri$args";
# add_header X-Cache-Status $upstream_cache_status;
# }
#
# # Purge endpoint
# location /purge/ {
# allow 10.0.0.0/8;
# deny all;
# proxy_cache_purge cdn_cache "$scheme$request_method$host$uri";
# }
#
# # Health check
# location /health {
# return 200 "OK";
# add_header Content-Type text/plain;
# }
# }
@dataclass
class CacheRule:
content_type: str
pattern: str
ttl: str
cache_key: str
stale_serve: bool
rules = [
CacheRule("Images", "*.jpg *.png *.webp *.svg", "24h", "URI only", True),
CacheRule("CSS/JS", "*.css *.js *.woff2", "24h (versioned)", "URI + query", True),
CacheRule("HTML Pages", "*.html", "5m", "URI + cookies", True),
CacheRule("API Response", "/api/*", "5m", "URI + args", False),
CacheRule("Video", "*.mp4 *.webm", "7d", "URI only", True),
CacheRule("No Cache", "/admin/* /auth/*", "0", "N/A", False),
]
print("\n=== Cache Rules ===")
for r in rules:
stale = "Yes" if r.stale_serve else "No"
print(f" [{r.content_type}] Pattern: {r.pattern}")
print(f" TTL: {r.ttl} | Key: {r.cache_key} | Stale: {stale}")
DNS and Operations
# === GeoDNS and CDN Operations ===
# GeoDNS Configuration (PowerDNS / Route53)
# cdn.example.com → Edge by region
# Asia-Pacific → edge-sgp (103.x.x.10)
# Japan → edge-tok (103.x.x.20)
# Thailand → edge-bkk (103.x.x.40)
# Default → edge-sgp
# Health Check Script
# #!/bin/bash
# EDGES=("edge-sgp:103.x.x.10" "edge-tok:103.x.x.20" "edge-bkk:103.x.x.40")
# for edge in ""; do
# name=""
# ip=""
# status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https:///health")
# if [ "$status" != "200" ]; then
# echo "ALERT: $name ($ip) is DOWN (status: $status)"
# # Remove from DNS / send alert
# fi
# done
@dataclass
class CDNMetric:
metric: str
edge_sgp: str
edge_tok: str
edge_bkk: str
origin: str
metrics = [
CDNMetric("Cache Hit Rate", "92%", "89%", "95%", "N/A"),
CDNMetric("Avg Response", "15ms", "18ms", "8ms", "45ms"),
CDNMetric("Bandwidth", "2.5 Gbps", "1.8 Gbps", "4.2 Gbps", "0.8 Gbps"),
CDNMetric("Requests/s", "12,000", "8,500", "18,000", "3,200"),
CDNMetric("Disk Usage", "45/100GB", "38/100GB", "120/200GB", "N/A"),
CDNMetric("Uptime (30d)", "99.99%", "99.98%", "99.99%", "99.95%"),
]
print("CDN Performance:")
for m in metrics:
print(f" [{m.metric}]")
print(f" SGP: {m.edge_sgp} | TOK: {m.edge_tok} | BKK: {m.edge_bkk} | Origin: {m.origin}")
ops_checklist = {
"SSL Renewal": "certbot renew --deploy-hook 'nginx -s reload'",
"Cache Purge": "curl -X PURGE https://cdn/purge/path/to/file",
"Log Rotation": "logrotate /etc/logrotate.d/nginx daily",
"Disk Monitor": "Alert when cache disk > 80%",
"Origin Health": "Health check every 10s, failover to backup",
"Snapshot": "virsh snapshot weekly for each edge VM",
}
print(f"\n\nOperations Checklist:")
for k, v in ops_checklist.items():
print(f" [{k}]: {v}")
เคล็ดลับ
- Cache Key: ใช้ Cache Key ที่เหมาะสม ไม่รวม Cookie สำหรับ Static
- Stale: เปิด Serve Stale เมื่อ Origin Down ป้องกัน Downtime
- Purge: สร้าง Purge API สำหรับล้าง Cache เมื่อ Content เปลี่ยน
- Snapshot: ทำ VM Snapshot ทุกสัปดาห์ก่อน Update
- Monitor: ดู Cache Hit Rate ทุกวัน ควรมากกว่า 85%
Libvirt KVM คืออะไร
API Library Virtualization KVM QEMU virsh virt-manager VM สร้าง ลบ Start Snapshot Live Migration Linux Kernel Hardware Virtualization ฟรี
CDN คืออะไร
Content Delivery Network กระจาย Content Edge Server ลด Latency Static Image CSS JS Video Dynamic Edge Computing Nginx Varnish Cloudflare
สร้าง CDN ด้วย KVM อย่างไร
VM Edge Cache แต่ละ Region Nginx Reverse Proxy Cache TTL Origin Server GeoDNS Route SSL Let's Encrypt Health Check Purge API
ตั้งค่า Nginx Cache อย่างไร
proxy_cache_path Disk proxy_cache_key proxy_cache_valid TTL X-Cache-Status HIT MISS proxy_cache_use_stale Origin Down Cache Size Purge
สรุป
Libvirt KVM CDN Configuration VM Edge Cache Nginx Reverse Proxy GeoDNS Origin SSL Cache Hit Rate Static Dynamic Content Delivery Production
