Deployment Hosting DevOps

Deployment & Hosting Strategies — จาก Code สู่ Production 🚀Deployment & Hosting Strategies — From Code to Production 🚀

DevOps & Vibe Coding 2026 ~30 min read
Deployment — จาก Code สู่ Production
ในบทความนี้
  1. 🐕 Code เขียนเสร็จแล้ว... แล้วจะเอาขึ้นที่ไหน?
  2. 📊 Hosting Options — เปรียบเทียบทุกแบบ
  3. 1️⃣ Static Hosting — Vercel / Netlify / Cloudflare Pages
  4. 2️⃣ PaaS — Railway / Render / Fly.io
  5. 3️⃣ VPS — Virtual Private Server
  6. 4️⃣ Reverse Proxy — Nginx vs Caddy
  7. 5️⃣ SSL/TLS — HTTPS ที่ทุกเว็บต้องมี
  8. 6️⃣ Domain Management — DNS
  9. 7️⃣ CDN — Content Delivery Network
  10. 8️⃣ Deployment Strategies — วิธี Deploy ที่ไม่พัง
  11. 9️⃣ Full Production Setup — จากศูนย์ถึง Production
  12. 🔟 Monitoring — รู้ก่อนที่จะพัง
  13. 🛡️ Security Checklist — ก่อนจะ Go Live
  14. 🗺️ Decision Flowchart — เลือก Hosting ยังไง?
  15. 🔑 Key Takeaways
In this post
  1. 🐕 The Code Is Finished... So Where Does It Go?
  2. 📊 Hosting Options — Every Kind Compared
  3. 1️⃣ Static Hosting — Vercel / Netlify / Cloudflare Pages
  4. 2️⃣ PaaS — Railway / Render / Fly.io
  5. 3️⃣ VPS — Virtual Private Server
  6. 4️⃣ Reverse Proxy — Nginx vs Caddy
  7. 5️⃣ SSL/TLS — The HTTPS Every Site Must Have
  8. 6️⃣ Domain Management — DNS
  9. 7️⃣ CDN — Content Delivery Network
  10. 8️⃣ Deployment Strategies — Shipping Without Breaking Things
  11. 9️⃣ Full Production Setup — From Zero to Production
  12. 🔟 Monitoring — Know Before It Breaks
  13. 🛡️ Security Checklist — Before You Go Live
  14. 🗺️ Decision Flowchart — How Do You Pick a Host?
  15. 🔑 Key Takeaways

🐕 Code เขียนเสร็จแล้ว... แล้วจะเอาขึ้นที่ไหน?

ตัวอย่าง code:

Developer ที่เริ่มต้น:

"เว็บเสร็จแล้ว! ทำยังไงให้คนอื่นเข้าได้?"

  • 🤔 ซื้อ server เอง?
  • 🤔 ใช้ Vercel/Netlify?
  • 🤔 เช่า VPS?
  • 🤔 ไป AWS/GCP?
  • 🤔 Domain ยังไง? HTTPS ยังไง?

❌ เลือกผิด = จ่ายแพง, ช้า, พังบ่อย

✅ เลือกถูก = ประหยัด, เร็ว, scale ได้

โพสต์นี้จะพาไปรู้จักทุกทางเลือก

ตั้งแต่ free tier ไปจนถึง enterprise-grade


📊 Hosting Options — เปรียบเทียบทุกแบบ

ตัวอย่าง code:

Hosting Options — เปรียบเทียบทุกแบบ
แบบราคาเริ่มต้นControlScaleดูแลเองเหมาะกับ
Static Host
(Vercel/Netlify)
$0ต่ำอัตโนมัติไม่ต้องStatic/SPA, JAMstack
PaaS
(Railway/Render/Fly.io)
$0-7/moต่ำ-กลางอัตโนมัติน้อยWeb apps, API, MVP
VPS
(DO/Linode/Hetzner)
$4-6/moสูงmanualปานกลางcustom setup
Cloud
(AWS/GCP/Azure)
$0-?????สูงมากอัตโนมัติเยอะEnterprise
Bare Metal$50+/moสูงสุดmanualเยอะมากHigh perf, ML, Gaming
💡 กฎง่ายๆ:
  • Side project / portfolio → Vercel/Netlify (ฟรี)
  • Startup MVP → Railway/Render (ง่าย, ถูก)
  • ต้อง customize เยอะ → VPS (control ดี, ราคาดี)
  • Enterprise / scale → Cloud (AWS/GCP/Azure)
  • ML training / gaming → Bare Metal / GPU Cloud

1️⃣ Static Hosting — Vercel / Netlify / Cloudflare Pages

ทำไมถึงฟรี?

ตัวอย่าง code:

Traditional Hosting:

Request → Server → Process → Render HTML → Response

💸 Server ต้องทำงานตลอด = ต้องจ่ายตลอด

Static Hosting:

Build Time: Framework → HTML/CSS/JS (static files)
Runtime: Request → CDN Edge → ส่ง file กลับเลย

💰 แค่เก็บไฟล์ + ส่งผ่าน CDN = ถูกมาก (ฟรีได้)

Vercel vs Netlify vs Cloudflare Pages

ตารางนี้ช่วยให้เห็นเร็วมากว่าแต่ละแพลตฟอร์มเด่นคนละมุม: Vercel เหมาะกับ Next.js, Netlify ใช้ง่ายสำหรับทีมเล็ก, ส่วน Cloudflare Pages เด่นเรื่อง edge และต้นทุน bandwidth.

รันคำสั่งเหล่านี้เพื่อ deploy:

Vercel vs Netlify vs Cloudflare Pages
VercelNetlifyCF Pages
จุดเด่นNext.js best-in-classง่ายที่สุดเร็วที่สุด
Free BW100 GB/mo100 GB/moUnlimited
Free Builds6000 min/mo300 min/mo500 builds/mo
Serverless✅ Edge+Node✅ Functions✅ Workers
Edge Runtime✅ v8✅ Deno✅ v8
Git IntegrationGitHub/GitLab/BitbucketGitHub/GitLab/BitbucketGitHub/GitLab
Analytics✅ (paid)✅ (paid)✅ (free basic)
Pro Price$20/mo/seat$19/mo/seat$5/mo (paid)
เหมาะกับNext.js projectsมือใหม่/Static sitesspeed + low cost

Deploy บน Vercel — ง่ายแค่ 3 ขั้นตอน

รันคำสั่งเหล่านี้เพื่อ deploy:

# 1. Install CLI
npm i -g vercel

# 2. Deploy (ครั้งแรก)
cd my-next-app
vercel
# → ตอบคำถาม → ได้ preview URL ทันที

# 3. Deploy production
vercel --prod
# → ได้ URL: my-next-app.vercel.app

# หรือ... แค่ push to GitHub
# Vercel auto-deploy ทุก push ให้เลย 🎉

Vercel Project Config (vercel.json)

ตัวอย่าง code:

{
  "framework": "nextjs",
  "buildCommand": "npm run build",
  "outputDirectory": ".next",
  "regions": ["sin1"],
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "no-store" }
      ]
    },
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Frame-Options", "value": "DENY" },
        { "key": "X-Content-Type-Options", "value": "nosniff" }
      ]
    }
  ],
  "rewrites": [
    { "source": "/api/:path*", "destination": "/api/:path*" }
  ],
  "redirects": [
    { "source": "/old-page", "destination": "/new-page", "permanent": true }
  ]
}

2️⃣ PaaS — Railway / Render / Fly.io

เมื่อต้องการ Backend + Database

รันคำสั่งเหล่านี้เพื่อ deploy:

Static Host: HTML/CSS/JS only ❌ ไม่มี backend

PaaS: Full app + DB + Background jobs ✅

PaaS จัดการให้:

  • 🖥️ Server provisioning
  • 📦 Container orchestration
  • 🗄️ Database management
  • 🔐 SSL certificates
  • 📊 Logs & monitoring
  • 🔄 Auto-deploy from Git
  • 📈 Auto-scaling (some)
คุณแค่: push code → มันทำที่เหลือให้หมด

เปรียบเทียบ PaaS ยอดนิยม

ถ้าคุณกำลังเริ่ม MVP ตารางนี้คือจุดตัดสินใจหลัก: ดู free tier, region, และความสะดวกเรื่อง DB/cron ก่อนเลือก เพื่อไม่ต้องย้ายแพลตฟอร์มเร็วเกินไป.

ตัวอย่าง code:

Railway vs Render vs Fly.io
RailwayRenderFly.io
Free Tier$5 credit/month750 hrs/mo (spin down)3 shared VMs free
Starter$5/mo$7/mo$0 + usage
DB included✅ Postgres/MySQL/Redis✅ Postgres/Redis✅ via Supabase
RegionsUS/EU/APUS/EU/SG35 regions
Cron Jobs✅✅ (paid)✅ (machines)
Private Net✅✅✅ WireGuard
เหมาะกับStartup/Prototypeมือใหม่/Simple appGlobal low-latency

Deploy ด้วย Railway

รันคำสั่งเหล่านี้เพื่อ deploy:

# Install CLI
npm i -g @railway/cli

# Login
railway login

# Init project
railway init

# Add Postgres
railway add --database postgres

# Deploy
railway up

# ได้ URL: my-app.up.railway.app 🎉

Fly.io — Deploy ใกล้ user ที่สุด

รันคำสั่งเหล่านี้เพื่อ deploy:

# Install
curl -L https://fly.io/install.sh | sh

# Login
fly auth login

# Launch (สร้าง fly.toml อัตโนมัติ)
fly launch

# Deploy
fly deploy

# Scale ไปหลาย region
fly regions add sin nrt
fly scale count 2

# ดู status
fly status

ตัวอย่าง code:

# fly.toml
app = "my-api"
primary_region = "sin"

[build]
  dockerfile = "Dockerfile"

[env]
  NODE_ENV = "production"
  PORT = "3000"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 1

[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 256

3️⃣ VPS — Virtual Private Server

ทำไมยังมีคนใช้ VPS?

ตัวอย่าง code:

PaaS ง่ายแต่...

  • 💸 แพงขึ้นเรื่อยๆ เมื่อ scale
  • 🔒 Limited customization
  • 📦 Vendor lock-in
  • 🐌 Cold starts (บาง service)

VPS ให้:

  • 💰 ราคาคงที่ ไม่ว่า traffic เท่าไร
  • 🔧 Full root access — ทำอะไรก็ได้
  • 📦 Run อะไรก็ได้ (Docker, custom stack)
  • 📚 เรียนรู้ Linux/DevOps จริงๆ

Trade-off: ต้องดูแล server เอง

(security updates, backup, monitoring)

VPS Providers เทียบราคา (2025)

ส่วนนี้เหมาะกับคนที่อยากคุมระบบเองและ optimize ค่าใช้จ่ายระยะยาว โดยเฉพาะเมื่อ traffic เริ่มนิ่งและต้องการ performance ที่คาดเดาได้.

ตัวอย่าง code:

VPS Providers เทียบราคา (2025)
ProviderRAMvCPUSSDราคา/เดือนจุดเด่น
Hetzner2 GB240 GB€3.79ถูกที่สุด
DigitalOcean1 GB125 GB$6เริ่มง่าย
Linode2 GB150 GB$5community
Vultr1 GB125 GB$5หลาย region
Oracle Cloud1 GB150 GBFREE!Always Free
Contabo4 GB250 GB€4.99specs/ราคา
🔥 Hetzner ถูกที่สุด, Oracle มี Always Free tier

VPS Setup — จากศูนย์ถึง Production

ไฟล์ configuration มีหน้าตาแบบนี้:

# === Step 1: เข้า server ===
ssh root@your-server-ip

# === Step 2: Security basics ===
# สร้าง user ใหม่ (อย่าใช้ root!)
adduser deploy
usermod -aG sudo deploy

# Setup SSH key
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh

# ปิด password login + root login
sudo nano /etc/ssh/sshd_config
# PermitRootLogin no
# PasswordAuthentication no
sudo systemctl restart sshd

# === Step 3: Firewall ===
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

# === Step 4: Install Docker ===
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker deploy

# === Step 5: Deploy with Docker Compose ===

ตัวอย่าง code:

# docker-compose.yml
version: "3.8"

services:
  app:
    image: my-app:latest
    build: .
    restart: unless-stopped
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=securepassword
      - POSTGRES_DB=mydb

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  pgdata:

รันคำสั่งเหล่านี้เพื่อ deploy:

# Deploy!
docker compose up -d

# Update (zero-downtime)
docker compose pull
docker compose up -d --no-deps --build app

4️⃣ Reverse Proxy — Nginx vs Caddy

ทำไมต้องมี Reverse Proxy?

ตัวอย่าง code:

WITHOUT Reverse Proxy

Internet → :3000 → App (exposed directly)

❌ No HTTPS

❌ No load balancing

❌ No static file caching

❌ Single point of failure

WITH Reverse Proxy

Nginx /

Internet → :443 → Caddy → :3000 → App 1
→ :3001 → App 2
(port 80 → :3002 → App 3
→ 443

redirect)

✅ HTTPS (auto)

✅ Load balancing

✅ Static file serving

✅ Rate limiting

✅ Compression (gzip/brotli)

✅ WebSocket support

Nginx vs Caddy

ทั้งสองตัวดีมาก แต่ต่างกันที่จุดโฟกัส: Nginx ยืดหยุ่นสูงสำหรับ production ขนาดใหญ่, Caddy ชนะเรื่อง simplicity และ auto-HTTPS สำหรับทีมที่ต้องการความเร็วในการส่งงาน.

ไฟล์ configuration มีหน้าตาแบบนี้:

Nginx vs Caddy
NginxCaddy
HTTPSต้อง setup certbotAUTO! 🎉
Configซับซ้อนแต่ยืดหยุ่นง่ายมาก
Performanceเร็วมากเร็วใกล้เคียง
Learning Curveสูงต่ำ
Load Balancing✅ advanced✅ basic
เหมาะกับProduction/high trafficเริ่มต้น/auto-SSL

Nginx Config — Full Production Setup

ตัวอย่าง code:

# /etc/nginx/sites-available/myapp

# Redirect HTTP → HTTPS
server {
    listen 80;
    server_name myapp.com www.myapp.com;
    return 301 https://$server_name$request_uri;
}

# Main HTTPS server
server {
    listen 443 ssl http2;
    server_name myapp.com www.myapp.com;

    # SSL (managed by certbot)
    ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;

    # 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; includeSubDomains" always;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript
               text/xml application/xml text/javascript image/svg+xml;

    # Static files (serve directly, bypass app)
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # API / App (proxy to Node.js)
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Rate limiting for API
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # Health check
    location /health {
        access_log off;
        proxy_pass http://localhost:3000/health;
    }
}

# Rate limit zone (ใส่ใน http block)
# limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

Caddy Config — ง่ายกว่าเยอะ!

ตัวอย่าง code:

# Caddyfile — แค่นี้จริงๆ!

myapp.com {
    # HTTPS จัดการให้อัตโนมัติ — ไม่ต้องทำอะไร!

    # Proxy to app
    reverse_proxy localhost:3000

    # Static files
    handle_path /static/* {
        root * /var/www/myapp/static
        file_server {
            precompressed gzip br
        }
    }

    # Compression
    encode gzip zstd

    # Security headers
    header {
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
    }

    # Rate limiting
    rate_limit {
        zone api {
            key {remote_host}
            events 10
            window 1s
        }
    }

    # Logs
    log {
        output file /var/log/caddy/myapp.log
        format json
    }
}

# Multiple sites? แค่เพิ่ม block!
api.myapp.com {
    reverse_proxy localhost:4000
}

staging.myapp.com {
    reverse_proxy localhost:5000
}

ไฟล์ configuration มีหน้าตาแบบนี้:

# Nginx: ต้องทำ 5 ขั้นตอน
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d myapp.com -d www.myapp.com
sudo nginx -t
sudo systemctl reload nginx
# + ตั้ง cron renew certificate

# Caddy: ขั้นตอนเดียว
sudo apt install caddy
sudo nano /etc/caddy/Caddyfile  # ใส่ config ข้างบน
sudo systemctl reload caddy
# HTTPS จัดการให้อัตโนมัติ ✅

5️⃣ SSL/TLS — HTTPS ที่ทุกเว็บต้องมี

SSL/TLS คืออะไร?

ตัวอย่าง code:

HTTP (ไม่มี SSL):

Browser ──── plain text ── → Server

🔓 ใครก็ดักข้อมูลได้ (password, credit card)

HTTPS (มี SSL/TLS):

Browser ──── encrypted 🔒 ── → Server

🔐 เข้ารหัสทุกอย่าง ดักไม่ได้

TLS Handshake (simplified):

1. Client → Server: "สวัสดี, รองรับ cipher เหล่านี้"
2. Server → Client: "เลือก cipher นี้, นี่คือ cert"
3. Client: ตรวจ cert → สร้าง session key
4. ทั้งคู่: ใช้ session key เข้ารหัสข้อมูล ◄─ →

⚡ TLS 1.3: handshake เร็วขึ้น (1-RTT vs 2-RTT)

วิธีได้ SSL Certificate

หัวใจคือทำให้ HTTPS กลายเป็น default ตั้งแต่วันแรก เพราะมีผลทั้งความปลอดภัย, SEO, และความน่าเชื่อถือของระบบโดยตรง.

รันคำสั่งเหล่านี้เพื่อ deploy:

วิธีได้ SSL Certificate
วิธีราคาความยากใช้เมื่อไร
Let's Encryptฟรีง่ายทุกเว็บ (default)
Caddy auto-SSLฟรีง่ายที่สุดใช้ Caddy
Cloudflare SSLฟรีง่ายใช้ CF DNS
Vercel/Netlifyฟรีอัตโนมัติdeploy ที่นั่น
Commercial$10-500/yrmanualenterprise/EV cert

Let's Encrypt + Certbot

รันคำสั่งเหล่านี้เพื่อ deploy:

# Install certbot
sudo apt install certbot python3-certbot-nginx

# Get certificate (ถ้าใช้ Nginx)
sudo certbot --nginx -d myapp.com -d www.myapp.com
# → ตอบคำถาม → ได้ cert อัตโนมัติ!

# Auto-renew (certbot ตั้งให้แล้ว)
sudo certbot renew --dry-run

# Check cert status
sudo certbot certificates

# Manual renew
sudo certbot renew
sudo systemctl reload nginx

6️⃣ Domain Management — DNS

DNS ทำงานยังไง?

ตัวอย่าง code:

Browser: "myapp.com อยู่ไหน?"

Browser ── → DNS Resolver ── → Root Server

(ISP/Google (.com ?)

8.8.8.8)

┌────────▼───────┐

TLD Server

(.com →

ns1.cf.com)

┌────────▼───────┐

◄─────────── Auth Server

IP: 1.2.3.4 (Cloudflare)

myapp.com →

1.2.3.4

Browser → 1.2.3.4 → Your Server → Response 🎉

DNS Record Types

ตาราง DNS นี้ควร bookmark ไว้ใช้งานจริง เพราะปัญหา production จำนวนมากมักเริ่มจากการตั้งค่า A/CNAME/TXT ผิดเพียงจุดเดียว.

ตัวอย่าง code:

DNS Record Types
Typeใช้ทำอะไรตัวอย่าง
ADomain → IPv4myapp.com → 1.2.3.4
AAAADomain → IPv6myapp.com → 2001:db8::1
CNAMEAliaswww → myapp.com
MXMail servermail.google.com
TXTSPF/DKIM verifyv=spf1 include:_spf...
NSNameserverns1.cloudflare.com
CAAAllow CA issue certissue letsencrypt.org

ตัวอย่าง DNS Setup — Cloudflare

ตัวอย่าง code:

Cloudflare DNS — myapp.com

Type Name Content TTL Proxy

A @ 1.2.3.4 Auto 🟠 On

A @ 5.6.7.8 Auto 🟠 On

AAAA @ 2001:db8::1 Auto 🟠 On

CNAME www myapp.com Auto 🟠 On

CNAME api api-prod.fly.dev Auto 🟠 On

CNAME blog myblog.vercel.app Auto ⚪ Off

MX @ mx1.google.com Auto N/A

MX @ mx2.google.com Auto N/A

TXT @ v=spf1 include:... Auto N/A

💡 Proxy 🟠 = Traffic ผ่าน Cloudflare (CDN + DDoS protection)

Proxy ⚪ = DNS only (ตรงไป server)

ซื้อ Domain ที่ไหน?

การเลือก registrar ไม่ใช่แค่เรื่องราคาเปิดโดเมนปีแรก แต่ต้องดูค่า renew, UX ตอนจัดการ DNS, และความโปร่งใสเรื่องค่าบริการระยะยาวด้วย.

ตัวอย่าง code:

ซื้อ Domain ที่ไหน?
Registrar.com ราคาจุดเด่น
Cloudflare~$9.77at-cost + free DNS
Namecheap~$9.98UI ดี, WhoisGuard ฟรี
Porkbun~$9.73ถูกที่สุด, UI ดี
Google Domains~$12ย้ายไป Squarespace
GoDaddy~$12-20แพง/upsell เยอะ

7️⃣ CDN — Content Delivery Network

CDN ทำงานยังไง?

ตัวอย่าง code:

WITHOUT CDN:

User in Tokyo ─────── 200ms ──── → Server in US
User in London ────── 150ms ──── → Server in US
User in Bangkok ───── 180ms ──── → Server in US

WITH CDN:

┌──── Edge Tokyo ◄── cached

User in Tokyo ──5ms─┤

  • ── Origin US (if not cached)

┌──── Edge London ◄── cached

User in London ─5ms─┤

  • ── Origin US (if not cached)

┌──── Edge Singapore ◄── cached

User in Bangkok ─10ms┤

  • ── Origin US (if not cached)

⚡ Result: 200ms → 5-10ms (20-40x faster!)

CDN Providers

สำหรับเว็บทั่วไป Cloudflare free plan มักพอแล้ว แต่ถ้าอยู่ใน ecosystem AWS หนัก ๆ การใช้ CloudFront จะบริหารรวมกับระบบเดิมได้ง่ายกว่า.

ตัวอย่าง code:

CDN Providers
ProviderFree TierEdge Nodesจุดเด่น
Cloudflare✅ ฟรี330+ citiesDDoS/WAF/Workers
AWS CloudFront1 TB/mo free600+ edgesAWS ecosystem
Bunny CDN14-day trial123 PoPsถูกมาก
Fastly$50 trial90+ PoPsreal-time purge

Cloudflare Setup (5 นาที)

ตัวอย่าง code:

1. สมัคร cloudflare.com (ฟรี)

2. Add site → ใส่ domain

3. เปลี่ยน nameserver ที่ registrar ไปเป็น:

- ns1.cloudflare.com

- ns2.cloudflare.com

4. รอ propagate (ไม่เกิน 24 ชม, ปกติ < 1 ชม)

5. เปิด features:

  • SSL: Full (Strict)
  • Always Use HTTPS: On
  • Auto Minify: CSS/JS/HTML
  • Brotli: On
  • Cache: Standard
  • Security Level: Medium

ได้ทันที:

✅ CDN (330+ edge nodes)

✅ DDoS protection

✅ Free SSL

✅ DNS management

✅ Page Rules

✅ Web Analytics

Cache Headers — ควบคุมสิ่งที่ cache

ตัวอย่าง code:

# Nginx — Cache Control headers

# Static assets (images, CSS, JS) — cache นาน
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
}

# HTML — ไม่ cache (ให้ได้ content ใหม่เสมอ)
location ~* \.html$ {
    add_header Cache-Control "no-cache, must-revalidate";
}

# API — ไม่ cache เด็ดขาด
location /api/ {
    add_header Cache-Control "no-store, no-cache";
}

ตัวอย่าง code:

Cache-Control Cheatsheet:

  • public, max-age=31536000, immutable → Static assets (1 ปี)
  • public, max-age=3600 → Semi-static (1 ชม)
  • private, max-age=0, must-revalidate → User-specific data
  • no-cache → ต้อง validate ก่อน serve
  • no-store → ห้าม cache เลย (sensitive)
  • stale-while-revalidate=60 → Serve stale + fetch new

8️⃣ Deployment Strategies — วิธี Deploy ที่ไม่พัง

Overview

รันคำสั่งเหล่านี้เพื่อ deploy:

❌ Bad Deploy:

1. FTP upload ไฟล์ใหม่ทับของเก่า

2. เว็บพัง 5 นาที

3. แก้ไม่ได้ → restore backup อีก 10 นาที

4. User โกรธ

✅ Good Deploy:

1. Deploy version ใหม่ข้างๆ version เก่า

2. ค่อยๆ ส่ง traffic ไป version ใหม่

3. มีปัญหา? → rollback ทันที (< 1 นาที)

4. User ไม่รู้เลยว่ามี deploy

Zero-Downtime Deployment = standard ในปี 2025

Rolling Deployment

รันคำสั่งเหล่านี้เพื่อ deploy:

เหมือนเปลี่ยนยางรถ... ทีละล้อ

เริ่มต้น: [v1] [v1] [v1] [v1]  ← 4 instances, all v1

Step 1:  [v2] [v1] [v1] [v1]  ← update 1st instance
         ↑ ตรวจ health check → ✅ ผ่าน → ไปต่อ

Step 2:  [v2] [v2] [v1] [v1]  ← update 2nd instance
         ↑ ตรวจ health check → ✅ ผ่าน → ไปต่อ

Step 3:  [v2] [v2] [v2] [v1]  ← update 3rd instance

Step 4:  [v2] [v2] [v2] [v2]  ← done! 🎉

❌ ถ้า Step 2 fail?
Step 2:  [v2] [v2] [v1] [v1]  ← v2 #2 health check ❌
         → Stop! Rollback v2 #1 and #2 → [v1] [v1] [v1] [v1]

✅ Pros: ง่าย, ใช้ resource เท่าเดิม
❌ Cons: ระหว่าง deploy มี 2 versions วิ่งพร้อมกัน

Blue-Green Deployment

รันคำสั่งเหล่านี้เพื่อ deploy:

มี 2 environments: Blue (production) + Green (staging)

Phase 1: Blue = LIVE ✅

🔵 BLUE 🟢 GREEN

v1 (LIVE) ◄─── (idle)

  • App x3 LB
  • DB

Phase 2: Deploy v2 to Green

🔵 BLUE 🟢 GREEN

v1 (LIVE) ◄─── v2 (testing)

  • App x3 LB ├── App x3
  • DB └── DB

↑ ทดสอบ v2 ใน Green

Phase 3: Switch! (แค่เปลี่ยน LB)

🔵 BLUE 🟢 GREEN

v1 (standby) LB v2 (LIVE) ◄───

  • App x3 ───► ├── App x3
  • DB └── DB
🔄 Rollback? → Switch LB back to Blue (< 30 seconds!)

✅ Pros: Zero-downtime, instant rollback

❌ Cons: ต้องมี 2x resources (แพงกว่า)

Canary Deployment

ตัวอย่าง code:

เหมือนนกขมิ้นในเหมือง — ส่งตัวเล็กไปทดสอบก่อน

Step 1: ส่ง 5% traffic ไป v2

Load Balancer

95% ──── → [v1] [v1] [v1] [v1]
5% ──── → [v2] ← canary

Monitor: error rate, latency, CPU

Step 2: ถ้าไม่มีปัญหา → เพิ่มเป็น 25%
75% ──── → [v1] [v1] [v1]
25% ──── → [v2] [v2]
Step 3: เพิ่มเป็น 50% → 75% → 100%
100% ──── → [v2] [v2] [v2] [v2]

v1 instances terminated

❌ ถ้า Step 1 มีปัญหา (error spike)?

→ Rollback: ส่ง traffic 100% กลับ v1 ทันที
→ Impact: แค่ 5% ของ users ที่ได้รับผลกระทบ!

✅ Pros: ลด blast radius, data-driven decisions

❌ Cons: ซับซ้อน, ต้องมี monitoring ดี

เปรียบเทียบ Deployment Strategies

ตารางนี้ช่วยตัดสินใจเชิงความเสี่ยง: ถ้าต้องการปล่อยงานไวใช้ Rolling, ถ้าระบบ critical มากให้ขยับไป Blue-Green หรือ Canary.

รันคำสั่งเหล่านี้เพื่อ deploy:

เปรียบเทียบ Deployment Strategies
RollingBlue-GreenCanaryRecreate
DowntimeZeroZeroZeroมี ❌
Rollbackช้าทันทีเร็วช้า
ResourceN+12NN+1N
Riskปานกลางต่ำต่ำสุดสูง
Complexityต่ำปานกลางสูงต่ำสุด
Use caseทั่วไปต้อง fast rollbackcritical systemsdev/test
💡 ส่วนใหญ่ใช้ Rolling; งาน mission-critical ใช้ Blue-Green หรือ Canary

Kubernetes Rolling Update Config

ไฟล์ configuration มีหน้าตาแบบนี้:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1          # สร้าง pod ใหม่เพิ่มได้ 1 ตัว
      maxUnavailable: 0     # ห้ามมี pod ลดลง (zero-downtime)
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myapp:v2
          ports:
            - containerPort: 3000

          # Health checks — สำคัญมาก!
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 5

          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 15
            periodSeconds: 10

          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "500m"

ไฟล์ configuration มีหน้าตาแบบนี้:

# Deploy
kubectl apply -f deployment.yaml

# ดู rollout status
kubectl rollout status deployment/myapp

# Rollback ถ้ามีปัญหา
kubectl rollout undo deployment/myapp

# ดู history
kubectl rollout history deployment/myapp

9️⃣ Full Production Setup — จากศูนย์ถึง Production

Architecture Overview

รันคำสั่งเหล่านี้เพื่อ deploy:

Production Stack

Cloudflare CDN + DNS + DDoS + WAF

(Free Plan)

┌──────▼───────┐

Caddy Reverse Proxy + Auto-SSL

(or Nginx)

┌──────▼───────────────────────────────────┐

Docker Compose

App Postgres Redis

:3000 :5432 :6379

Monitoring: Uptime Kuma + Grafana

Backup: Automated daily to S3/B2

CI/CD: GitHub Actions → SSH deploy

VPS: Hetzner CPX11 (2 vCPU, 2GB RAM) — €3.79/mo

Domain: Cloudflare Registrar — ~$10/yr

Total: ~$15/month for full production stack! 💰

GitHub Actions — Auto Deploy on Push

รันคำสั่งเหล่านี้เพื่อ deploy:

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install & Test
        run: |
          npm ci
          npm run lint
          npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: Deploy to VPS
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: deploy
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /home/deploy/myapp
            git pull origin main
            docker compose pull
            docker compose up -d --build --no-deps app
            docker image prune -f

      - name: Health Check
        run: |
          sleep 10
          curl -f https://myapp.com/health || exit 1

      - name: Notify on Failure
        if: failure()
        run: |
          curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
            -H 'Content-type: application/json' \
            -d '{"text":"❌ Deploy failed! Check GitHub Actions."}'

Automated Backups

รันคำสั่งเหล่านี้เพื่อ deploy:

#!/bin/bash
# backup.sh — run daily via cron

set -euo pipefail

BACKUP_DIR="/home/deploy/backups"
DATE=$(date +%Y-%m-%d_%H%M)
RETENTION_DAYS=7

# Backup PostgreSQL
docker exec postgres pg_dump -U user mydb | gzip > "$BACKUP_DIR/db_${DATE}.sql.gz"

# Backup app data
tar czf "$BACKUP_DIR/data_${DATE}.tar.gz" /home/deploy/myapp/data/

# Upload to Backblaze B2 (cheap!)
rclone copy "$BACKUP_DIR/db_${DATE}.sql.gz" b2:my-backups/db/
rclone copy "$BACKUP_DIR/data_${DATE}.tar.gz" b2:my-backups/data/

# Cleanup old backups
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete

echo "✅ Backup completed: $DATE"

รันคำสั่งเหล่านี้เพื่อ deploy:

# Cron job (daily at 3 AM)
crontab -e
0 3 * * * /home/deploy/backup.sh >> /var/log/backup.log 2>&1

🔟 Monitoring — รู้ก่อนที่จะพัง

Uptime Monitoring

ตัวอย่าง code:

# Uptime Kuma — self-hosted uptime monitor
# (ฟรี, สวย, alert ได้)

docker run -d \
  --name uptime-kuma \
  --restart unless-stopped \
  -p 3001:3001 \
  -v uptime-kuma:/app/data \
  louislam/uptime-kuma:1

# → เข้า http://your-server:3001
# → เพิ่ม monitors:
#   - HTTPS: myapp.com (check every 60s)
#   - TCP: db server port 5432
#   - Docker container health
# → ตั้ง alert: Telegram, Slack, Discord, Email

Simple Health Check Endpoint

ไฟล์ configuration มีหน้าตาแบบนี้:

// Express.js health check
app.get('/health', async (req, res) => {
  const health = {
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    checks: {}
  };

  // Check database
  try {
    await db.query('SELECT 1');
    health.checks.database = 'ok';
  } catch (err) {
    health.status = 'degraded';
    health.checks.database = 'error';
  }

  // Check Redis
  try {
    await redis.ping();
    health.checks.redis = 'ok';
  } catch (err) {
    health.status = 'degraded';
    health.checks.redis = 'error';
  }

  // Check disk space
  const diskFree = getDiskFreePercent();
  health.checks.disk = diskFree > 10 ? 'ok' : 'warning';

  const statusCode = health.status === 'ok' ? 200 : 503;
  res.status(statusCode).json(health);
});

🛡️ Security Checklist — ก่อนจะ Go Live

ไฟล์ configuration มีหน้าตาแบบนี้:

Production Security Checklist ✅

🔐 SSL/TLS

  • [ ] HTTPS everywhere (redirect HTTP → HTTPS)
  • [ ] TLS 1.2+ only (disable TLS 1.0/1.1)
  • [ ] HSTS header enabled
  • [ ] Certificate auto-renewal working

🔒 Server

  • [ ] SSH key only (no password login)
  • [ ] Non-root user for app
  • [ ] Firewall enabled (only 22, 80, 443)
  • [ ] Unattended security updates
  • [ ] Fail2ban installed

🛡️ Application

  • [ ] Environment variables for secrets
  • [ ] CORS configured properly
  • [ ] Rate limiting on API
  • [ ] Input validation & sanitization
  • [ ] Security headers (X-Frame, CSP, etc.)
  • [ ] Dependencies updated (npm audit)

📊 Monitoring

  • [ ] Uptime monitoring active
  • [ ] Error tracking (Sentry)
  • [ ] Log rotation configured
  • [ ] Alerts configured (Telegram/Slack)

💾 Backup

  • [ ] Daily automated backups
  • [ ] Backups stored off-server
  • [ ] Restore tested recently
  • [ ] Backup monitoring (alert on failure)

🗺️ Decision Flowchart — เลือก Hosting ยังไง?

ตัวอย่าง code:

เริ่มต้น: มี project อะไร?

  • Static site / SPA / Next.js?
  • ใช้ Next.js → Vercel (free)
  • Static HTML → Cloudflare Pages (free, fastest)
  • อื่นๆ → Netlify (free, easiest)
  • Full-stack app + DB?
  • MVP / prototype?

└── Railway or Render (ง่ายที่สุด)

  • ต้อง customize?

└── VPS + Docker Compose

  • ต้อง scale globally?

└── Fly.io (multi-region)

  • Enterprise?
  • AWS/GCP/Azure + Kubernetes
  • API only?
  • Lightweight → Cloudflare Workers / Vercel Edge
  • Node/Python → Railway or Fly.io
  • Complex → VPS or Cloud
  • ML / GPU workloads?
  • Inference → Modal, Replicate, RunPod
  • Training → Lambda Labs, Vast.ai
  • Enterprise → AWS SageMaker, GCP Vertex

🔑 Key Takeaways

แนวคิดสำคัญของบทนี้คือ “เลือกให้เหมาะกับ stage ของโปรเจกต์” มากกว่าการไล่ใช้ของใหญ่ตั้งแต่วันแรก แล้วค่อยยกระดับ architecture ตามภาระงานจริง.

  1. เริ่มจากง่ายไปยาก — Vercel/Netlify → PaaS → VPS → Cloud
  2. HTTPS ฟรีทุกที่ — Let's Encrypt, Caddy auto-SSL, Cloudflare
  3. Cloudflare = must-have — CDN + DNS + DDoS ฟรี
  4. Caddy ง่ายกว่า Nginx — สำหรับ project ที่ไม่ต้อง fine-tune มาก
  5. Zero-downtime deploy เป็น standard — Rolling update เป็นค่า default
  6. Canary deploy สำหรับ critical systems — ลด blast radius
  7. Blue-Green สำหรับ instant rollback — แต่ต้องมี 2x resources
  8. VPS + Docker Compose + Caddy = sweet spot — $5-15/mo ได้ production-grade
  9. Automate everything — CI/CD, backups, monitoring, SSL renewal
  10. Monitor before you deploy — ถ้าไม่ monitor = ไม่รู้ว่าพัง

📌 This is #21 in our DevOps & Full-Stack series

📚 Series ทั้งหมด:

  1. Git Branching — แตก branch ยังไงให้เป็นระบบ
  2. CI/CD Pipeline — จาก commit ถึง production
  3. Docker vs VMs — Container คืออะไร ทำไมต้องใช้
  4. API Lifecycle — Request เดินทางยังไง
  5. Kubernetes — จัดการ container ระดับ production
  6. Networking — DNS, TCP, Load Balancer, Firewall
  7. Infrastructure as Code — Terraform & Ansible
  8. Monitoring & Observability — Logs, Metrics, Traces
  9. Linux & Shell Essentials — พื้นฐานที่ DevOps ต้องรู้
  10. DevSecOps & Security — Shift Left, OWASP, Secrets
  11. Testing Strategies — Pyramid, TDD, Load, Chaos
  12. GitOps & ArgoCD — Git-driven Deployments
  13. Cloud Architecture — AWS, GCP, Azure Fundamentals
  14. SRE — Site Reliability Engineering
  15. GitHub Actions Workflow — Advanced CI/CD
  16. Automated Testing — Unit, Integration, E2E
  17. Database Design & SQL — Normalization, Indexing, Query Optimization
  18. Authentication & Authorization — JWT, OAuth, RBAC
  19. Web Architecture & Design Patterns — Monolith vs Microservices
  20. Frontend Performance & Modern Frameworks
  21. Deployment & Hosting Strategies — Vercel to Bare Metal ← 📍 อยู่ตรงนี้

🐕 The Code Is Finished... So Where Does It Go?

Sample code:

The developer just starting out:

"The site is done! How do I let other people reach it?"

  • 🤔 Buy my own server?
  • 🤔 Use Vercel/Netlify?
  • 🤔 Rent a VPS?
  • 🤔 Go to AWS/GCP?
  • 🤔 What about the domain? What about HTTPS?

❌ Choose wrong = expensive, slow, breaks often

✅ Choose right = cheap, fast, scales

This post walks through every option

from the free tier all the way to enterprise-grade


📊 Hosting Options — Every Kind Compared

Sample code:

Hosting Options — Every Kind Compared
KindStarting priceControlScaleYou maintain itBest for
Static Host
(Vercel/Netlify)
$0LowAutomaticNoStatic/SPA, JAMstack
PaaS
(Railway/Render/Fly.io)
$0-7/moLow-mediumAutomaticA littleWeb apps, API, MVP
VPS
(DO/Linode/Hetzner)
$4-6/moHighmanualModeratecustom setup
Cloud
(AWS/GCP/Azure)
$0-?????Very highAutomaticA lotEnterprise
Bare Metal$50+/moHighestmanualA great dealHigh perf, ML, Gaming
💡 Simple rules:
  • Side project / portfolio → Vercel/Netlify (free)
  • Startup MVP → Railway/Render (easy, cheap)
  • Lots of customization → VPS (good control, good price)
  • Enterprise / scale → Cloud (AWS/GCP/Azure)
  • ML training / gaming → Bare Metal / GPU Cloud

1️⃣ Static Hosting — Vercel / Netlify / Cloudflare Pages

Why Is It Free?

Sample code:

Traditional Hosting:

Request → Server → Process → Render HTML → Response

💸 The server has to run all the time = you pay all the time

Static Hosting:

Build Time: Framework → HTML/CSS/JS (static files)
Runtime: Request → CDN Edge → send the file straight back

💰 Just storing files + serving them over a CDN = very cheap (free is possible)

Vercel vs Netlify vs Cloudflare Pages

This table makes it very quick to see that each platform is strong in a different direction: Vercel suits Next.js, Netlify is the easy one for small teams, and Cloudflare Pages leads on edge presence and bandwidth cost.

Run these commands to deploy:

Vercel vs Netlify vs Cloudflare Pages
VercelNetlifyCF Pages
StrengthNext.js best-in-classEasiestFastest
Free BW100 GB/mo100 GB/moUnlimited
Free Builds6000 min/mo300 min/mo500 builds/mo
Serverless✅ Edge+Node✅ Functions✅ Workers
Edge Runtime✅ v8✅ Deno✅ v8
Git IntegrationGitHub/GitLab/BitbucketGitHub/GitLab/BitbucketGitHub/GitLab
Analytics✅ (paid)✅ (paid)✅ (free basic)
Pro Price$20/mo/seat$19/mo/seat$5/mo (paid)
Best forNext.js projectsBeginners/Static sitesspeed + low cost

Deploying on Vercel — Just Three Steps

Run these commands to deploy:

# 1. Install CLI
npm i -g vercel

# 2. Deploy (first time)
cd my-next-app
vercel
# → answer the prompts → a preview URL straight away

# 3. Deploy production
vercel --prod
# → you get the URL: my-next-app.vercel.app

# Or... just push to GitHub
# Vercel auto-deploys on every push for you 🎉

Vercel Project Config (vercel.json)

Sample code:

{
  "framework": "nextjs",
  "buildCommand": "npm run build",
  "outputDirectory": ".next",
  "regions": ["sin1"],
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "no-store" }
      ]
    },
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Frame-Options", "value": "DENY" },
        { "key": "X-Content-Type-Options", "value": "nosniff" }
      ]
    }
  ],
  "rewrites": [
    { "source": "/api/:path*", "destination": "/api/:path*" }
  ],
  "redirects": [
    { "source": "/old-page", "destination": "/new-page", "permanent": true }
  ]
}

2️⃣ PaaS — Railway / Render / Fly.io

When You Need a Backend + Database

Run these commands to deploy:

Static Host: HTML/CSS/JS only ❌ no backend

PaaS: Full app + DB + Background jobs ✅

PaaS handles all of this for you:

  • 🖥️ Server provisioning
  • 📦 Container orchestration
  • 🗄️ Database management
  • 🔐 SSL certificates
  • 📊 Logs & monitoring
  • 🔄 Auto-deploy from Git
  • 📈 Auto-scaling (some)
You just: push code → it does everything else

The Popular PaaS Platforms Compared

If you are starting an MVP, this table is the main decision point: look at the free tier, the regions, and how convenient DB and cron are before you choose, so you do not have to change platforms too soon.

Sample code:

Railway vs Render vs Fly.io
RailwayRenderFly.io
Free Tier$5 credit/month750 hrs/mo (spin down)3 shared VMs free
Starter$5/mo$7/mo$0 + usage
DB included✅ Postgres/MySQL/Redis✅ Postgres/Redis✅ via Supabase
RegionsUS/EU/APUS/EU/SG35 regions
Cron Jobs✅✅ (paid)✅ (machines)
Private Net✅✅✅ WireGuard
Best forStartup/PrototypeBeginners/Simple appGlobal low-latency

Deploying with Railway

Run these commands to deploy:

# Install CLI
npm i -g @railway/cli

# Login
railway login

# Init project
railway init

# Add Postgres
railway add --database postgres

# Deploy
railway up

# You get the URL: my-app.up.railway.app 🎉

Fly.io — Deploy as Close to the User as Possible

Run these commands to deploy:

# Install
curl -L https://fly.io/install.sh | sh

# Login
fly auth login

# Launch (creates fly.toml automatically)
fly launch

# Deploy
fly deploy

# Scale out to several regions
fly regions add sin nrt
fly scale count 2

# Check status
fly status

Sample code:

# fly.toml
app = "my-api"
primary_region = "sin"

[build]
  dockerfile = "Dockerfile"

[env]
  NODE_ENV = "production"
  PORT = "3000"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 1

[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 256

3️⃣ VPS — Virtual Private Server

Why Do People Still Use a VPS?

Sample code:

PaaS is easy, but...

  • 💸 Steadily more expensive as you scale
  • 🔒 Limited customization
  • 📦 Vendor lock-in
  • 🐌 Cold starts (on some services)

A VPS gives you:

  • 💰 A fixed price no matter how much traffic
  • 🔧 Full root access — do whatever you like
  • 📦 Run anything (Docker, custom stack)
  • 📚 Learn Linux/DevOps for real

Trade-off: you maintain the server yourself

(security updates, backup, monitoring)

VPS Providers Compared on Price (2025)

This section is for anyone who wants to run the system themselves and optimize cost over the long run — especially once traffic has settled and predictable performance matters.

Sample code:

VPS Providers Compared on Price (2025)
ProviderRAMvCPUSSDPrice/monthStrength
Hetzner2 GB240 GB€3.79Cheapest
DigitalOcean1 GB125 GB$6Easy to start
Linode2 GB150 GB$5community
Vultr1 GB125 GB$5Many regions
Oracle Cloud1 GB150 GBFREE!Always Free
Contabo4 GB250 GB€4.99specs/price
🔥 Hetzner is the cheapest; Oracle has an Always Free tier

VPS Setup — From Zero to Production

The configuration file looks like this:

# === Step 1: get into the server ===
ssh root@your-server-ip

# === Step 2: Security basics ===
# Create a new user (do not use root!)
adduser deploy
usermod -aG sudo deploy

# Setup SSH key
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh

# Turn off password login + root login
sudo nano /etc/ssh/sshd_config
# PermitRootLogin no
# PasswordAuthentication no
sudo systemctl restart sshd

# === Step 3: Firewall ===
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

# === Step 4: Install Docker ===
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker deploy

# === Step 5: Deploy with Docker Compose ===

Sample code:

# docker-compose.yml
version: "3.8"

services:
  app:
    image: my-app:latest
    build: .
    restart: unless-stopped
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=securepassword
      - POSTGRES_DB=mydb

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  pgdata:

Run these commands to deploy:

# Deploy!
docker compose up -d

# Update (zero-downtime)
docker compose pull
docker compose up -d --no-deps --build app

4️⃣ Reverse Proxy — Nginx vs Caddy

Why Do You Need a Reverse Proxy?

Sample code:

WITHOUT Reverse Proxy

Internet → :3000 → App (exposed directly)

❌ No HTTPS

❌ No load balancing

❌ No static file caching

❌ Single point of failure

WITH Reverse Proxy

Nginx /

Internet → :443 → Caddy → :3000 → App 1
→ :3001 → App 2
(port 80 → :3002 → App 3
→ 443

redirect)

✅ HTTPS (auto)

✅ Load balancing

✅ Static file serving

✅ Rate limiting

✅ Compression (gzip/brotli)

✅ WebSocket support

Nginx vs Caddy

Both are excellent, but they focus differently: Nginx is highly flexible for large production estates, while Caddy wins on simplicity and auto-HTTPS for teams that need to ship quickly.

The configuration file looks like this:

Nginx vs Caddy
NginxCaddy
HTTPSYou must set up certbotAUTO! 🎉
ConfigComplex but flexibleVery easy
PerformanceVery fastNearly as fast
Learning CurveSteepGentle
Load Balancing✅ advanced✅ basic
Best forProduction/high trafficGetting started/auto-SSL

Nginx Config — Full Production Setup

Sample code:

# /etc/nginx/sites-available/myapp

# Redirect HTTP → HTTPS
server {
    listen 80;
    server_name myapp.com www.myapp.com;
    return 301 https://$server_name$request_uri;
}

# Main HTTPS server
server {
    listen 443 ssl http2;
    server_name myapp.com www.myapp.com;

    # SSL (managed by certbot)
    ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;

    # 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; includeSubDomains" always;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript
               text/xml application/xml text/javascript image/svg+xml;

    # Static files (serve directly, bypass app)
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # API / App (proxy to Node.js)
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Rate limiting for API
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # Health check
    location /health {
        access_log off;
        proxy_pass http://localhost:3000/health;
    }
}

# Rate limit zone (put this inside the http block)
# limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

Caddy Config — So Much Simpler!

Sample code:

# Caddyfile — this really is all of it!

myapp.com {
    # HTTPS is handled automatically — nothing to do!

    # Proxy to app
    reverse_proxy localhost:3000

    # Static files
    handle_path /static/* {
        root * /var/www/myapp/static
        file_server {
            precompressed gzip br
        }
    }

    # Compression
    encode gzip zstd

    # Security headers
    header {
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
    }

    # Rate limiting
    rate_limit {
        zone api {
            key {remote_host}
            events 10
            window 1s
        }
    }

    # Logs
    log {
        output file /var/log/caddy/myapp.log
        format json
    }
}

# Multiple sites? Just add a block!
api.myapp.com {
    reverse_proxy localhost:4000
}

staging.myapp.com {
    reverse_proxy localhost:5000
}

The configuration file looks like this:

# Nginx: five steps to do
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d myapp.com -d www.myapp.com
sudo nginx -t
sudo systemctl reload nginx
# + set up a cron job to renew the certificate

# Caddy: one step
sudo apt install caddy
sudo nano /etc/caddy/Caddyfile  # paste the config above
sudo systemctl reload caddy
# HTTPS is handled automatically ✅

5️⃣ SSL/TLS — The HTTPS Every Site Must Have

What Are SSL and TLS?

Sample code:

HTTP (no SSL):

Browser ──── plain text ── → Server

🔓 Anyone can intercept the data (password, credit card)

HTTPS (with SSL/TLS):

Browser ──── encrypted 🔒 ── → Server

🔐 Everything is encrypted — interception gets nothing

TLS Handshake (simplified):

1. Client → Server: "Hello, I support these ciphers"
2. Server → Client: "Use this cipher, here is my cert"
3. Client: check the cert → create a session key
4. Both sides: encrypt the data with the session key ◄─ →

⚡ TLS 1.3: a faster handshake (1-RTT vs 2-RTT)

Ways to Get an SSL Certificate

The heart of it is making HTTPS the default from day one, because it bears directly on security, on SEO, and on how trustworthy the system looks.

Run these commands to deploy:

Ways to Get an SSL Certificate
MethodPriceDifficultyWhen to use it
Let's EncryptFreeEasyEvery site (default)
Caddy auto-SSLFreeEasiestYou use Caddy
Cloudflare SSLFreeEasyYou use CF DNS
Vercel/NetlifyFreeAutomaticYou deploy there
Commercial$10-500/yrmanualenterprise/EV cert

Let's Encrypt + Certbot

Run these commands to deploy:

# Install certbot
sudo apt install certbot python3-certbot-nginx

# Get certificate (if you are on Nginx)
sudo certbot --nginx -d myapp.com -d www.myapp.com
# → answer the prompts → the cert arrives automatically!

# Auto-renew (certbot has already set this up)
sudo certbot renew --dry-run

# Check cert status
sudo certbot certificates

# Manual renew
sudo certbot renew
sudo systemctl reload nginx

6️⃣ Domain Management — DNS

How Does DNS Work?

Sample code:

Browser: "Where is myapp.com?"

Browser ── → DNS Resolver ── → Root Server

(ISP/Google (.com ?)

8.8.8.8)

┌────────▼───────┐

TLD Server

(.com →

ns1.cf.com)

┌────────▼───────┐

◄─────────── Auth Server

IP: 1.2.3.4 (Cloudflare)

myapp.com →

1.2.3.4

Browser → 1.2.3.4 → Your Server → Response 🎉

DNS Record Types

Bookmark this DNS table for real work, because a great many production problems begin with a single wrong A, CNAME or TXT record.

Sample code:

DNS Record Types
TypeWhat it doesExample
ADomain → IPv4myapp.com → 1.2.3.4
AAAADomain → IPv6myapp.com → 2001:db8::1
CNAMEAliaswww → myapp.com
MXMail servermail.google.com
TXTSPF/DKIM verifyv=spf1 include:_spf...
NSNameserverns1.cloudflare.com
CAAAllow CA issue certissue letsencrypt.org

A Sample DNS Setup — Cloudflare

Sample code:

Cloudflare DNS — myapp.com

Type Name Content TTL Proxy

A @ 1.2.3.4 Auto 🟠 On

A @ 5.6.7.8 Auto 🟠 On

AAAA @ 2001:db8::1 Auto 🟠 On

CNAME www myapp.com Auto 🟠 On

CNAME api api-prod.fly.dev Auto 🟠 On

CNAME blog myblog.vercel.app Auto ⚪ Off

MX @ mx1.google.com Auto N/A

MX @ mx2.google.com Auto N/A

TXT @ v=spf1 include:... Auto N/A

💡 Proxy 🟠 = Traffic goes through Cloudflare (CDN + DDoS protection)

Proxy ⚪ = DNS only (straight to your server)

Where Should You Buy a Domain?

Choosing a registrar is not only about the first-year price of the domain: look at the renewal cost, at the UX of managing DNS, and at how transparent the fees are over the long run.

Sample code:

Where Should You Buy a Domain?
Registrar.com priceStrength
Cloudflare~$9.77at-cost + free DNS
Namecheap~$9.98Good UI, free WhoisGuard
Porkbun~$9.73Cheapest, good UI
Google Domains~$12Moved to Squarespace
GoDaddy~$12-20Expensive/heavy upsell

7️⃣ CDN — Content Delivery Network

How Does a CDN Work?

Sample code:

WITHOUT CDN:

User in Tokyo ─────── 200ms ──── → Server in US
User in London ────── 150ms ──── → Server in US
User in Bangkok ───── 180ms ──── → Server in US

WITH CDN:

┌──── Edge Tokyo ◄── cached

User in Tokyo ──5ms─┤

  • ── Origin US (if not cached)

┌──── Edge London ◄── cached

User in London ─5ms─┤

  • ── Origin US (if not cached)

┌──── Edge Singapore ◄── cached

User in Bangkok ─10ms┤

  • ── Origin US (if not cached)

⚡ Result: 200ms → 5-10ms (20-40x faster!)

CDN Providers

For an ordinary site the Cloudflare free plan is usually enough, but if you live deep inside the AWS ecosystem, CloudFront is easier to manage alongside what you already have.

Sample code:

CDN Providers
ProviderFree TierEdge NodesStrength
Cloudflare✅ Free330+ citiesDDoS/WAF/Workers
AWS CloudFront1 TB/mo free600+ edgesAWS ecosystem
Bunny CDN14-day trial123 PoPsVery cheap
Fastly$50 trial90+ PoPsreal-time purge

Cloudflare Setup (5 Minutes)

Sample code:

1. Sign up at cloudflare.com (free)

2. Add site → enter your domain

3. Change the nameservers at your registrar to:

- ns1.cloudflare.com

- ns2.cloudflare.com

4. Wait for propagation (24 hrs at most, usually < 1 hr)

5. Turn on features:

  • SSL: Full (Strict)
  • Always Use HTTPS: On
  • Auto Minify: CSS/JS/HTML
  • Brotli: On
  • Cache: Standard
  • Security Level: Medium

What you get immediately:

✅ CDN (330+ edge nodes)

✅ DDoS protection

✅ Free SSL

✅ DNS management

✅ Page Rules

✅ Web Analytics

Cache Headers — Controlling What Gets Cached

Sample code:

# Nginx — Cache Control headers

# Static assets (images, CSS, JS) — cache for a long time
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
}

# HTML — do not cache (always serve fresh content)
location ~* \.html$ {
    add_header Cache-Control "no-cache, must-revalidate";
}

# API — never cache, no exceptions
location /api/ {
    add_header Cache-Control "no-store, no-cache";
}

Sample code:

Cache-Control Cheatsheet:

  • public, max-age=31536000, immutable → Static assets (1 year)
  • public, max-age=3600 → Semi-static (1 hr)
  • private, max-age=0, must-revalidate → User-specific data
  • no-cache → must validate before serving
  • no-store → never cache at all (sensitive)
  • stale-while-revalidate=60 → Serve stale + fetch new

8️⃣ Deployment Strategies — Shipping Without Breaking Things

Overview

Run these commands to deploy:

❌ Bad Deploy:

1. FTP the new files over the old ones

2. The site is down for 5 minutes

3. Cannot fix it → restore the backup, 10 minutes more

4. Users are furious

✅ Good Deploy:

1. Deploy the new version beside the old one

2. Move traffic across to the new version gradually

3. A problem? → roll back at once (< 1 minute)

4. Users never notice a deploy happened

Zero-Downtime Deployment = the standard in 2025

Rolling Deployment

Run these commands to deploy:

Like changing a car's tyres... one wheel at a time

Start:   [v1] [v1] [v1] [v1]  ← 4 instances, all v1

Step 1:  [v2] [v1] [v1] [v1]  ← update 1st instance
         ↑ run the health check → ✅ pass → carry on

Step 2:  [v2] [v2] [v1] [v1]  ← update 2nd instance
         ↑ run the health check → ✅ pass → carry on

Step 3:  [v2] [v2] [v2] [v1]  ← update 3rd instance

Step 4:  [v2] [v2] [v2] [v2]  ← done! 🎉

❌ What if Step 2 fails?
Step 2:  [v2] [v2] [v1] [v1]  ← v2 #2 health check ❌
         → Stop! Rollback v2 #1 and #2 → [v1] [v1] [v1] [v1]

✅ Pros: simple, uses the same resources as before
❌ Cons: during the deploy two versions run side by side

Blue-Green Deployment

Run these commands to deploy:

Two environments: Blue (production) + Green (staging)

Phase 1: Blue = LIVE ✅

🔵 BLUE 🟢 GREEN

v1 (LIVE) ◄─── (idle)

  • App x3 LB
  • DB

Phase 2: Deploy v2 to Green

🔵 BLUE 🟢 GREEN

v1 (LIVE) ◄─── v2 (testing)

  • App x3 LB ├── App x3
  • DB └── DB

↑ test v2 inside Green

Phase 3: Switch! (just repoint the LB)

🔵 BLUE 🟢 GREEN

v1 (standby) LB v2 (LIVE) ◄───

  • App x3 ───► ├── App x3
  • DB └── DB
🔄 Rollback? → Switch LB back to Blue (< 30 seconds!)

✅ Pros: Zero-downtime, instant rollback

❌ Cons: needs 2x the resources (more expensive)

Canary Deployment

Sample code:

Like the canary in the coal mine — send the small one in to test first

Step 1: send 5% of traffic to v2

Load Balancer

95% ──── → [v1] [v1] [v1] [v1]
5% ──── → [v2] ← canary

Monitor: error rate, latency, CPU

Step 2: no problems? → raise it to 25%
75% ──── → [v1] [v1] [v1]
25% ──── → [v2] [v2]
Step 3: raise it to 50% → 75% → 100%
100% ──── → [v2] [v2] [v2] [v2]

v1 instances terminated

❌ What if Step 1 goes wrong (error spike)?

→ Rollback: send 100% of traffic back to v1 at once
→ Impact: only 5% of users were affected!

✅ Pros: a smaller blast radius, data-driven decisions

❌ Cons: complex, and it needs good monitoring

Deployment Strategies Compared

This table helps you make the risk call: if you need to ship fast, use Rolling; if the system is highly critical, move up to Blue-Green or Canary.

Run these commands to deploy:

Deployment Strategies Compared
RollingBlue-GreenCanaryRecreate
DowntimeZeroZeroZeroYes ❌
RollbackSlowInstantFastSlow
ResourceN+12NN+1N
RiskModerateLowLowestHigh
ComplexityLowModerateHighLowest
Use caseGeneralNeed fast rollbackcritical systemsdev/test
💡 Most work uses Rolling; mission-critical work uses Blue-Green or Canary

Kubernetes Rolling Update Config

The configuration file looks like this:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1          # may add 1 new pod above the count
      maxUnavailable: 0     # never let the pod count drop (zero-downtime)
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myapp:v2
          ports:
            - containerPort: 3000

          # Health checks — this matters enormously!
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 5

          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 15
            periodSeconds: 10

          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "500m"

The configuration file looks like this:

# Deploy
kubectl apply -f deployment.yaml

# Watch the rollout status
kubectl rollout status deployment/myapp

# Roll back if something goes wrong
kubectl rollout undo deployment/myapp

# See the history
kubectl rollout history deployment/myapp

9️⃣ Full Production Setup — From Zero to Production

Architecture Overview

Run these commands to deploy:

Production Stack

Cloudflare CDN + DNS + DDoS + WAF

(Free Plan)

┌──────▼───────┐

Caddy Reverse Proxy + Auto-SSL

(or Nginx)

┌──────▼───────────────────────────────────┐

Docker Compose

App Postgres Redis

:3000 :5432 :6379

Monitoring: Uptime Kuma + Grafana

Backup: Automated daily to S3/B2

CI/CD: GitHub Actions → SSH deploy

VPS: Hetzner CPX11 (2 vCPU, 2GB RAM) — €3.79/mo

Domain: Cloudflare Registrar — ~$10/yr

Total: ~$15/month for full production stack! 💰

GitHub Actions — Auto Deploy on Push

Run these commands to deploy:

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install & Test
        run: |
          npm ci
          npm run lint
          npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: Deploy to VPS
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: deploy
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /home/deploy/myapp
            git pull origin main
            docker compose pull
            docker compose up -d --build --no-deps app
            docker image prune -f

      - name: Health Check
        run: |
          sleep 10
          curl -f https://myapp.com/health || exit 1

      - name: Notify on Failure
        if: failure()
        run: |
          curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
            -H 'Content-type: application/json' \
            -d '{"text":"❌ Deploy failed! Check GitHub Actions."}'

Automated Backups

Run these commands to deploy:

#!/bin/bash
# backup.sh — run daily via cron

set -euo pipefail

BACKUP_DIR="/home/deploy/backups"
DATE=$(date +%Y-%m-%d_%H%M)
RETENTION_DAYS=7

# Backup PostgreSQL
docker exec postgres pg_dump -U user mydb | gzip > "$BACKUP_DIR/db_${DATE}.sql.gz"

# Backup app data
tar czf "$BACKUP_DIR/data_${DATE}.tar.gz" /home/deploy/myapp/data/

# Upload to Backblaze B2 (cheap!)
rclone copy "$BACKUP_DIR/db_${DATE}.sql.gz" b2:my-backups/db/
rclone copy "$BACKUP_DIR/data_${DATE}.tar.gz" b2:my-backups/data/

# Cleanup old backups
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete

echo "✅ Backup completed: $DATE"

Run these commands to deploy:

# Cron job (daily at 3 AM)
crontab -e
0 3 * * * /home/deploy/backup.sh >> /var/log/backup.log 2>&1

🔟 Monitoring — Know Before It Breaks

Uptime Monitoring

Sample code:

# Uptime Kuma — self-hosted uptime monitor
# (free, good-looking, and it can alert you)

docker run -d \
  --name uptime-kuma \
  --restart unless-stopped \
  -p 3001:3001 \
  -v uptime-kuma:/app/data \
  louislam/uptime-kuma:1

# → open http://your-server:3001
# → add monitors:
#   - HTTPS: myapp.com (check every 60s)
#   - TCP: db server port 5432
#   - Docker container health
# → set up alerts: Telegram, Slack, Discord, Email

Simple Health Check Endpoint

The configuration file looks like this:

// Express.js health check
app.get('/health', async (req, res) => {
  const health = {
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    checks: {}
  };

  // Check database
  try {
    await db.query('SELECT 1');
    health.checks.database = 'ok';
  } catch (err) {
    health.status = 'degraded';
    health.checks.database = 'error';
  }

  // Check Redis
  try {
    await redis.ping();
    health.checks.redis = 'ok';
  } catch (err) {
    health.status = 'degraded';
    health.checks.redis = 'error';
  }

  // Check disk space
  const diskFree = getDiskFreePercent();
  health.checks.disk = diskFree > 10 ? 'ok' : 'warning';

  const statusCode = health.status === 'ok' ? 200 : 503;
  res.status(statusCode).json(health);
});

🛡️ Security Checklist — Before You Go Live

The configuration file looks like this:

Production Security Checklist ✅

🔐 SSL/TLS

  • [ ] HTTPS everywhere (redirect HTTP → HTTPS)
  • [ ] TLS 1.2+ only (disable TLS 1.0/1.1)
  • [ ] HSTS header enabled
  • [ ] Certificate auto-renewal working

🔒 Server

  • [ ] SSH key only (no password login)
  • [ ] Non-root user for app
  • [ ] Firewall enabled (only 22, 80, 443)
  • [ ] Unattended security updates
  • [ ] Fail2ban installed

🛡️ Application

  • [ ] Environment variables for secrets
  • [ ] CORS configured properly
  • [ ] Rate limiting on API
  • [ ] Input validation & sanitization
  • [ ] Security headers (X-Frame, CSP, etc.)
  • [ ] Dependencies updated (npm audit)

📊 Monitoring

  • [ ] Uptime monitoring active
  • [ ] Error tracking (Sentry)
  • [ ] Log rotation configured
  • [ ] Alerts configured (Telegram/Slack)

💾 Backup

  • [ ] Daily automated backups
  • [ ] Backups stored off-server
  • [ ] Restore tested recently
  • [ ] Backup monitoring (alert on failure)

🗺️ Decision Flowchart — How Do You Pick a Host?

Sample code:

Start here: what kind of project do you have?

  • Static site / SPA / Next.js?
  • Using Next.js → Vercel (free)
  • Static HTML → Cloudflare Pages (free, fastest)
  • Anything else → Netlify (free, easiest)
  • Full-stack app + DB?
  • MVP / prototype?

└── Railway or Render (the easiest)

  • Need to customize?

└── VPS + Docker Compose

  • Need to scale globally?

└── Fly.io (multi-region)

  • Enterprise?
  • AWS/GCP/Azure + Kubernetes
  • API only?
  • Lightweight → Cloudflare Workers / Vercel Edge
  • Node/Python → Railway or Fly.io
  • Complex → VPS or Cloud
  • ML / GPU workloads?
  • Inference → Modal, Replicate, RunPod
  • Training → Lambda Labs, Vast.ai
  • Enterprise → AWS SageMaker, GCP Vertex

🔑 Key Takeaways

The central idea of this post is to “match the choice to the project's stage” rather than reaching for the biggest thing on day one, then upgrading the architecture as the real workload demands.

  1. Start simple, then work up — Vercel/Netlify → PaaS → VPS → Cloud
  2. HTTPS is free everywhere — Let's Encrypt, Caddy auto-SSL, Cloudflare
  3. Cloudflare = must-have — CDN + DNS + DDoS, free
  4. Caddy is simpler than Nginx — for projects that need little fine-tuning
  5. Zero-downtime deploy is the standard — a rolling update is the default
  6. Canary deploy for critical systems — it shrinks the blast radius
  7. Blue-Green for instant rollback — but it costs 2x the resources
  8. VPS + Docker Compose + Caddy = sweet spot — $5-15/mo buys production-grade
  9. Automate everything — CI/CD, backups, monitoring, SSL renewal
  10. Monitor before you deploy — no monitoring = you never learn it broke

📌 This is #21 in our DevOps & Full-Stack series

📚 The full series:

  1. Git Branching — Branching That Stays Organized
  2. CI/CD Pipeline — From Commit to Production
  3. Docker vs VMs — What a Container Is and Why You Need One
  4. API Lifecycle — How a Request Travels
  5. Kubernetes — Managing Containers at Production Scale
  6. Networking — DNS, TCP, Load Balancer, Firewall
  7. Infrastructure as Code — Terraform & Ansible
  8. Monitoring & Observability — Logs, Metrics, Traces
  9. Linux & Shell Essentials — The Basics Every DevOps Engineer Needs
  10. DevSecOps & Security — Shift Left, OWASP, Secrets
  11. Testing Strategies — Pyramid, TDD, Load, Chaos
  12. GitOps & ArgoCD — Git-driven Deployments
  13. Cloud Architecture — AWS, GCP, Azure Fundamentals
  14. SRE — Site Reliability Engineering
  15. GitHub Actions Workflow — Advanced CI/CD
  16. Automated Testing — Unit, Integration, E2E
  17. Database Design & SQL — Normalization, Indexing, Query Optimization
  18. Authentication & Authorization — JWT, OAuth, RBAC
  19. Web Architecture & Design Patterns — Monolith vs Microservices
  20. Frontend Performance & Modern Frameworks
  21. Deployment & Hosting Strategies — Vercel to Bare Metal ← 📍 you are here
← Previous
Frontend Performance & Modern Frameworks — เพิ่มความเร็วและเลือก Framework ที่ใช่
Next →
Vibe Coding in DevOps Process — ใช้ AI ให้เร็วขึ้นแบบไม่พังระบบ