Cloudflare สำหรับเว็บไซต์ที่สร้างด้วย Vibe Coding
สถานะการวิจัย: 9 กันยายน 2026 · ข้อเท็จจริงทางเทคนิคในเอกสารนี้มาจากเอกสารทางการ Cloudflare ที่เปิดอ่านในวันนี้ ส่วนคำว่า ข้อเสนอแนะในการสอน คือการเลือกเนื้อหาสำหรับหน่วยเรียน 2 วัน / 8 ชั่วโมงและคลังศึกษาต่อ ไม่ใช่ข้อกำหนดของ Cloudflare
คำตอบสั้นสำหรับหลักสูตรนี้
สำหรับเว็บไซต์บริษัท หน้ารวมสินค้า และตัวอย่างแอนิเมชัน GSAP ให้เริ่มด้วย Cloudflare Worker + Workers Static Assets เป็นจุด deploy เดียว: build frontend ไปที่ dist/, ให้ Worker เสิร์ฟไฟล์เหล่านั้น และให้ route /api/* เรียก API เดียวกันได้ เมื่อมีข้อมูลเชิงสัมพันธ์จึง bind D1; เมื่อมีรูปสินค้า เอกสาร หรือไฟล์ผู้ใช้จึง bind R2; และก่อนรับฟอร์ม/การจองให้ใช้ Turnstile แล้วตรวจ token ใน Worker ฝั่ง server เสมอ. นี่ลดจำนวน deployment, domain, CORS และจุดที่ผู้เรียนต้อง debug ในโปรเจกต์แรก
Cloudflare ระบุว่า Workers Static Assets เป็นวิธีที่แนะนำสำหรับ static site, SPA และ full-stack app ใหม่; Pages ยังใช้งานได้ แต่ฟีเจอร์และการปรับปรุงใหม่มุ่งไปที่ Workers มากกว่า. ดังนั้นบทเรียนให้รู้จัก Pages เพื่ออ่านโปรเจกต์เก่าและการ deploy ที่มีอยู่ แต่ไม่ใช้ Pages เป็นค่าเริ่มต้นของงานใหม่ (Workers best practices).
ขอบเขตของ starter repository นี้
ข้อเสนอข้างต้นเป็นสถาปัตยกรรมเป้าหมายของหลักสูตร; starter ที่ใช้สอนตอนนี้มี Worker Static Assets + ASSETS binding + D1 binding เท่านั้น และ DEMO_MODE: "true". Repository ของผู้สอนอาจมี D1 resource ID ของ demo ที่ deploy แล้ว แต่ source package ที่แจกผู้เรียนแทนค่านั้นด้วย placeholder; ผู้เรียนต้องสร้าง D1 ของตนเองและใส่ ID ของตนตาม บทเรียน 08. ไม่มี R2 binding, named staging environment หรือ frontend Turnstile widget ที่ production-ready ใน starter. เส้นทางที่รันได้จริงคือ npm run db:local → npm run dev → smoke /api/health และ /api/catalog → npm run deploy:check; อย่าอ้างว่า R2/staging/production deploy สำเร็จจนกว่าจะเพิ่ม resource, config, secret และ evidence ตามบทเรียนนั้น.
ขอบเขตและรูปแบบเว็บไซต์ตัวอย่าง
| ตัวอย่าง | ของที่ deploy | ข้อมูล | ความปลอดภัยขั้นต่ำ | สิ่งที่พิสูจน์ได้ |
|---|---|---|---|---|
| เว็บไซต์บริษัท | Static Assets + /api/contact |
D1 สำหรับข้อความติดต่อ (ถ้าต้องเก็บ) | Turnstile + validation ฝั่ง Worker | ฟอร์มส่งสำเร็จและไม่มี secret ใน browser |
| แค็ตตาล็อก/โชว์สินค้า GSAP | Static Assets + /api/catalog |
starter ส่ง catalogue demo; production อาจใช้ D1 และ R2 สำหรับภาพ | validate input; cache read-only อย่างระวัง | ภาพและ animation โหลดได้ พร้อมเคารพ prefers-reduced-motion |
| เว็บไซต์เช่าอุปกรณ์ | Static Assets + API | D1: อุปกรณ์, ลูกค้า, ช่วงเวลา, คำขอจอง; R2: รูป/เอกสาร | Turnstile, prepared SQL, validation, rate limit ตามความเสี่ยง | ไม่เกิดการจองซ้ำในกรณีแข่งกัน และมี audit log ที่ปลอดภัย |
| back office ของทีม | Worker ที่ป้องกันด้วย Access | D1/R2 ตามงาน | Cloudflare Access/IdP และ policy แบบ deny-by-default | คนที่ไม่ตรง policy เข้าไม่ได้ |
ข้อเสนอแนะในการสอน: อย่าเริ่มด้วย e-commerce ที่รับชำระเงินจริง หรือระบบบัญชีผู้ใช้เต็มรูปแบบ. ให้เริ่ม “catalogue + enquiry/reservation request” ก่อน แล้วอธิบายว่าการเก็บเงิน, อีเมล, ภาษี, สต็อก และการยืนยันตัวตนเป็น integration แยกที่ต้องออกแบบและทดสอบเพิ่ม.
แผนภาพสถาปัตยกรรมเริ่มต้น
เปิดแผนภาพ Cloudflare deployment แบบเต็มหน้า เพื่อดู topology ที่ starter มีจริง ส่วน R2, Access และ Turnstile เป็น production extensions ที่ตั้งใจตัดออกจากภาพเพื่อลดความหนาแน่นและอธิบายในตารางขอบเขตด้านบน
Static Assets อยู่ในไฟล์ config ผ่าน assets.directory. เว็บไซต์ล้วน ๆ ไม่ต้องมี Worker script; full-stack เพิ่ม main และใช้ ASSETS binding เพื่อให้ handler ส่ง static asset ที่ไม่ใช่ /api/* (แนวทางทางการ). ยึด wrangler.jsonc เป็น config ที่อยู่ใน Git, ใช้ compatibility_date ล่าสุดที่ทีมทดสอบแล้ว, และสร้าง type ของ binding หลังปรับ config. อย่า copy วันที่ในตัวอย่างโดยไม่ตรวจสอบวันที่ release/deploy จริง.
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "course-catalogue",
"main": "src/worker.ts",
"compatibility_date": "YYYY-MM-DD",
"assets": {
"directory": "./dist", "binding": "ASSETS",
"run_worker_first": ["/api/*"]
},
"d1_databases": [{
"binding": "DB", "database_name": "course-catalogue",
"database_id": "<created-by-cloudflare>", "migrations_dir": "migrations"
}],
"observability": { "enabled": true, "head_sampling_rate": 0.1 }
}
ตัวอย่างนี้เป็นโครง ไม่ใช่ค่าพร้อม deploy: database_id, route และ secret ต้องมาจากบัญชีของผู้เรียน. R2 เพิ่มได้เฉพาะเมื่อมี media route/authorization/test ที่ใช้จริง. หากเพิ่ม named environment, bindings และ vars ไม่ inherit; ต้องประกาศค่าของ staging/production ให้ครบ (Wrangler environments). ตรวจ schema/คำสั่งของ Wrangler เวอร์ชันที่ติดตั้งก่อน execute (Wrangler).
D1: SQL ที่ปลอดภัย, migration และการแข่งกัน
D1 เหมาะกับข้อมูลสัมพันธ์ขนาดของตัวอย่างนี้: catalogue, availability, booking request และ contact message. ห้ามต่อค่าจาก input เข้า SQL string. ใช้ prepare(...).bind(...): Cloudflare แนะนำ prepared statement เพราะการ bind ช่วย reuse และป้องกัน SQL injection (Prepared statements). ตรวจชนิด/ขอบเขต input ก่อน query และคืน error message ที่ไม่เผย SQL หรือ secret.
const row = await env.DB.prepare(
"SELECT id, name, daily_rate FROM equipment WHERE id = ?"
).bind(equipmentId).first();
ไฟล์ migration คือส่วนหนึ่งของ source code: สร้างไฟล์ลำดับ migrations/0001_initial.sql, commit พร้อม code และใช้ wrangler d1 migrations apply <database> --local ก่อน จากนั้นตรวจ staging แล้วจึง --remote. D1 บันทึก migration ที่ apply แล้วในตาราง d1_migrations; ใช้ database name ในคำสั่ง migration เมื่อเป็นไปได้ เพราะ binding name เปลี่ยนได้ (D1 migrations). คำสั่ง DDL ที่เสี่ยงลบ/แก้ข้อมูลต้องมี backup/restore plan และต้อง rehearsal บน staging ก่อน production.
ใช้ DB.batch([...]) เมื่อต้องการหลาย prepared statements เป็นชุดเดียว: Cloudflare ระบุว่า batch ทำงานตามลำดับ, ไม่พร้อมกัน, และเป็น SQL transaction; หาก statement ใด fail จะ rollback ทั้งชุด (D1Database batch). สำหรับการจอง ให้ schema มี constraint ที่สะท้อนกติกาธุรกิจ และให้การตรวจ availability กับ insert/update อยู่ใน transaction เดียว—อย่าคิดว่า “SELECT ก่อนแล้วค่อย INSERT” สอง request จะแข่งกันไม่ได้.
D1 database หนึ่งตัว single-threaded และ query เข้าเป็นลำดับ; เมื่อ queue เต็มอาจเกิด overloaded. ลด query ที่ยาว, ใช้ index ตาม query ที่วัดจริง, ออกแบบ workload ให้สั้น และ retry เฉพาะ error ที่ transient ด้วย exponential backoff + jitter ตามคำแนะนำ (D1 limits, retry queries). การ retry ต้องไม่ทำให้ “สร้าง booking ซ้ำ”: ใช้ idempotency key หรือ unique request identifier ที่บันทึกและตรวจใน D1.
R2: ไฟล์ไม่ใช่แถวฐานข้อมูล
เก็บ metadata ของสินค้า/ไฟล์ใน D1 และเก็บ bytes ของรูป PDF หรือเอกสารใน R2. Worker binding ให้ Worker เรียก get/put โดยไม่ส่ง API credential ไป browser. เอกสาร R2 เตือนชัดว่า Worker ที่เปิด GET/PUT ทั้งหมดโดยไม่มี authorization จะเปิด bucket ต่อผู้ไม่หวังดี; authorization เป็นหน้าที่ของ application (R2 from Workers).
สำหรับรูปสินค้าสาธารณะ ใช้ key ที่ควบคุมได้และ route read-only หรือ public custom domain ที่ตั้งใจเปิด. สำหรับ upload ของผู้ใช้: ตรวจ authentication/authorization, ขนาด, MIME type และชื่อ key ที่สร้างจาก server; อย่าเชื่อ file name จาก browser. ถ้าต้องการ browser upload ตรง R2 ให้ Worker ออก presigned URL อายุสั้น, จำกัด operation และ Content-Type, และตั้ง CORS เฉพาะ origin ที่อนุญาต. Presigned URL คือ bearer credential—ผู้ได้ URL ใช้งานได้จนหมดอายุ; Cloudflare รองรับ GET/HEAD/PUT/DELETE แต่ไม่รองรับ POST multipart form (R2 presigned URLs).
Turnstile, Access และ secret
Turnstile เป็นชั้นป้องกัน form ไม่ใช่ login system. Browser ส่ง token พร้อม POST, Worker สร้าง request POST https://challenges.cloudflare.com/turnstile/v0/siteverify พร้อม secret และ response, ตรวจ success ก่อนเขียน D1/R2. การตรวจฝั่ง server เป็นข้อบังคับ: token อยู่ 300 วินาทีและใช้ได้ครั้งเดียว; client widget เพียงอย่างเดียวป้องกัน form ไม่ได้ (Server-side validation). เก็บ Turnstile secret ด้วย Workers secret และตรวจ hostname/action ที่คาดหวังเมื่อใช้ค่าเหล่านั้น. อย่า log token, secret หรือข้อมูลฟอร์มที่ละเอียดอ่อน.
Cloudflare Access เหมาะกับ /admin, preview หรือเครื่องมือทีม—not a replacement for customer authorization ภายใน application. Access เป็น identity-aware proxy ที่ตรวจ request ด้วย policy; self-hosted/Worker application ใช้ policy engine และ Access applications เป็น deny-by-default จนผู้ใช้ match Allow policy (Access web apps, application type). หากมี origin ของตนเองที่อาจ bypass Cloudflare ต้อง validate Access token ที่ origin ด้วย; สำหรับ Worker ที่ Cloudflare host ให้ผูก Worker กับ Access app เป็นจุดป้องกันตรงไปตรงมา.
vars ใช้เฉพาะค่าที่ไม่ลับ เช่น environment label; secret ของแอป เช่น Turnstile secret หรือ API token ของบริการที่ Worker เรียก ต้องใช้ Workers Secrets. Local ใช้ .dev.vars หรือ .env (เลือกหนึ่งแบบ) และ ignore ใน Git. ส่วน CLOUDFLARE_API_TOKEN สำหรับ deploy เก็บใน environment ของ CLI/CI ไม่ส่งเข้า Worker runtime. Cloudflare แนะนำไม่เก็บ sensitive data ใน vars; สามารถประกาศ required secret names เพื่อให้ deploy fail หากขาด secret (Workers secrets).
Delivery, operations และต้นทุน
สอนวงจร base ของ starter ก่อน: npm run db:local → npm run dev → test API/การเข้าถึง → npm run deploy:check. จากนั้นจึงเป็น production extension: เพิ่ม config/resource ของ staging → smoke test URL จริง → deploy production. แยก staging และ production, แยก secret และ D1/R2 resource ตามระดับความเสี่ยง. การ deploy static frontend ไม่ยืนยันว่า migration หรือ API ใช้ได้ จึงต้องมี smoke checklist สำหรับ POST, query, upload และ authorization.
เปิด observability.enabled; Workers Logs เก็บ invocation, custom log, error และ uncaught exception และ Cloudflare แนะนำ structured JSON เพื่อ query/filter ได้ดี. เลือก head_sampling_rate เพื่อควบคุมปริมาณข้อมูล โดยเฉพาะ production traffic; metrics มี request/error rate, CPU/wall time และ duration (Workers Logs, Observability). Log event ควรมี requestId, route, status, duration และ error class โดยตัด email, token, cookie, body และ secret ออก.
ก่อน release ที่เสี่ยง: ดู version ที่ active, backup/export D1 ตามแผน, ทำ migration ที่ forward-compatible, และเตรียม rollback code. wrangler rollback เปลี่ยน Worker version ได้ แต่ไม่ย้อน D1/R2 schema/data โดยอัตโนมัติ และ Cloudflare ระบุว่า rollback ใช้ไม่ได้หาก resource ถูกลบหรือแก้ไม่เข้ากันระหว่าง version (Rollbacks). จึงออกแบบ migration แบบ expand → deploy code ที่อ่านได้ทั้งสอง schema → backfill → contract ภายหลัง ไม่ใช่ deploy destructive change พร้อมกัน.
ตัวเลข quota/pricing เปลี่ยนได้ ให้ผู้เรียนเปิดหน้า pricing/limits ของแผนตัวเองก่อนเปิด production. สิ่งที่ต้อง track เป็นตัวชี้วัด ได้แก่ Worker request/CPU/subrequest, D1 rows read/write/storage, R2 storage/Class A/Class B operations และ log volume. ตั้ง CPU limit เพื่อกัน runaway cost/denial-of-wallet ตามคำแนะนำของ Workers pricing และทำ budget/alert ใน account. แหล่งจริงคือ Workers pricing, Workers limits, D1 pricing และ R2 pricing; ไม่ให้ hard-code ตัวเลขในสไลด์เพราะแผนและราคาอาจเปลี่ยน.
ลำดับแนะนำในหน่วยเรียน 8 ชั่วโมง
ขั้นตอนรับรองตัวตนก่อน deploy อยู่ใน Lab Wrangler login และ API token แยก token ที่ CLI/CI ใช้จัดการ Cloudflare ออกจาก secret ที่ application ใช้ขณะรัน: CLOUDFLARE_API_TOKEN เป็น credential ของเครื่องมือ deploy จึงไม่ใส่ใน frontend หรือส่งเป็น Worker runtime secret
กำหนดการ canonical อยู่ที่ คู่มือผู้สอน 2 วัน / 8 ชั่วโมง: วัน 1 ครอบคลุม brief/skills/design/company และวัน 2 เลือก rental/D1, motion/quote overview, deploy boundaries และ capstone vertical slice. Operations เชิงลึกกับ R2 เป็นเนื้อหา optional/self-study หลังเส้นทาง Worker + D1 ไม่ใช่เงื่อนไขของ capstone ทุกคน.
เอกสารนี้เป็นฐานให้บทเรียน 08 Cloudflare deployment และ 09 production operations. นอกเหนือจาก Cloudflare ให้กลับไปใช้ checklist ของหลักสูตรสำหรับ UX, accessibility, legal/privacy, payment provider และ review โค้ดที่ AI สร้าง.