บทความ › เซิร์ฟเวอร์และ DevOps

ย้ายเว็บแล้ว ทำไมบางคนยังเห็นเว็บเก่า เรื่อง DNS cache และ TTL จากเคสจริง

เปลี่ยน DNS ชี้ไป เซิร์ฟเวอร์ ใหม่แล้ว แต่ Google DNS ยังตอบ IP เก่าอยู่สองชั่วโมง ทำไมถึงเป็นแบบนั้น ดูได้ยังไงว่าใครเห็นอะไร และย้ายโดเมนครั้งหน้าให้ไม่ต้องรอ

เริ่มต้น อ่าน 9 นาที 21 ตุลาคม 2569

อ่านจบแล้วจะรู้
  • DNS ไม่ได้ "กระจาย" ไปไหน แค่คนที่ถามไว้ก่อนยังจำคำตอบเก่าอยู่จนกว่า TTL จะหมด
  • เวลารอสูงสุดเท่ากับ TTL ของ record เก่า ไม่ใช่ 48 ชั่วโมง ลด TTL เหลือ 300 วินาที ล่วงหน้าหนึ่งวัน แล้วค่อยย้าย
  • เช็กทีละชั้นด้วย dig หรือ nslookup ถาม nameserver ตัวจริง และถาม 8.8.8.8 แล้วเทียบกัน
  • ขอใบรับรอง TLS หลังจาก DNS สาธารณะเห็น IP ใหม่แล้วเท่านั้น ไม่ใช่หลังจากเครื่องตัวเองเห็น

วันที่ 16 ตุลาคม เราย้ายโดเมนหนึ่ง (mykaset.com) จากโฮสต์เดิมมาขึ้น เซิร์ฟเวอร์ ของเราเอง แก้ A record ที่ DigitalOcean เสร็จ ถาม ns1.digitalocean.com ตรง ๆ ได้ IP ใหม่ทันที แต่ถาม 8.8.8.8 ของ Google ยังได้ IP เก่าอยู่ ประมาณ 2 ชั่วโมง 20 นาที คนที่ใช้ Google DNS จึงยังเห็นเว็บเก่า ขณะที่คนอื่นเห็นเว็บใหม่แล้ว บทความนี้อธิบายว่าทำไม ดูได้ยังไงว่าแต่ละชั้นเห็นอะไร และย้ายครั้งหน้าให้ไม่ต้องรอ

คำสั่งทดสอบบน Windows 11 และ Ubuntu 24.04 บน Ubuntu dig อยู่ในแพ็กเกจ dnsutils (sudo apt install dnsutils) บน Windows ใช้ nslookup หรือ Resolve-DnsName ใน PowerShell

คำถามหนึ่งครั้งเดินทางผ่านอะไรบ้าง

พิมพ์ชื่อเว็บในเบราว์เซอร์ คำถาม “ชื่อนี้ IP อะไร” จะวิ่งผ่านชั้นเหล่านี้ และ ทุกชั้นมี cache ของตัวเอง

ชั้นใครดูแลจำคำตอบไว้ที่ไหน
เบราว์เซอร์Chrome, Firefoxcache ในตัวเบราว์เซอร์
ระบบปฏิบัติการWindows, LinuxDNS client cache
resolverISP, Google 8.8.8.8, Cloudflare 1.1.1.1cache ของ resolver ใช้ร่วมกันกับผู้ใช้หลายล้านคน
authoritative nameserverผู้ให้บริการ DNS ของโดเมน เช่น DigitalOceanไม่มี cache นี่คือต้นทาง

ถ้าชั้นไหนมีคำตอบอยู่แล้วและยังไม่หมดอายุ มันจะตอบเลยโดยไม่ถามชั้นถัดไป เว็บเร็วก็เพราะอย่างนี้ และเว็บเก่าค้างก็เพราะอย่างนี้เหมือนกัน

เบราว์เซอร์ / ระบบปฏิบัติการจำคำตอบไว้ชั่วคราวresolver ของ ISP หรือ 8.8.8.8จำไว้จนครบ TTL ของคำตอบเก่าnameserver ต้นทางของผู้ให้บริการโดเมน เปลี่ยนแล้วทันทีคำตอบใหม่ไปถึงทุกคนเมื่อ TTL เก่าหมดอายุ
ต้นทางเปลี่ยนทันที แต่ชั้นที่จำไว้จะถือคำตอบเก่าจนครบ TTL

TTL คือวันหมดอายุของคำตอบ

ทุก record มีตัวเลข TTL (time to live) เป็นวินาที บอกคนที่ได้คำตอบไปว่าจำได้นานแค่ไหน ตัวอย่างจากเว็บนี้เอง ถาม nameserver ตัวจริง

# Ubuntu 24.04
dig +noall +answer 6amdev.com @ns1.digitalocean.com
# 6amdev.com.   3600   IN   A   157.x.x.x

3600 คือ TTL เต็ม ถาม resolver ที่เคยตอบคำถามนี้ไปแล้ว เลขจะน้อยกว่าเพราะนับถอยหลังอยู่

dig +noall +answer 6amdev.com @8.8.8.8
# 6amdev.com.   2299   IN   A   157.x.x.x    ← เหลืออีก 2299 วินาที ค่อยถามต้นทางใหม่

จุดสำคัญ: TTL ที่คุมเวลารอ คือ TTL ของ record เก่า ที่คนอื่นถามไว้ก่อนเราแก้ ไม่ใช่ค่าที่เราเพิ่งตั้ง resolver ที่จำค่าเก่าไว้จะไม่รู้เลยว่าเราแก้แล้ว จนกว่าตัวนับของมันจะถึงศูนย์

ตัวอย่างตัวเลข: TTL 3600

  • A record เดิม TTL 3600 เราแก้เป็น IP ใหม่ตอน 10:00
  • resolver ก. เพิ่งถามตอน 09:59 มันจะตอบ IP เก่าถึง 10:59 แล้วค่อยถามใหม่ได้ IP ใหม่
  • resolver ข. ถามตอน 09:20 มันจะเปลี่ยนตอน 10:20
  • resolver ค. ไม่เคยถามชื่อนี้ ถามตอน 10:01 ได้ IP ใหม่ทันที

ดังนั้นในกรณีเลวร้ายสุด คำตอบเก่าตัวสุดท้ายหมดอายุ ไม่เกิน 60 นาที หลังแก้ ไม่ใช่ 48 ชั่วโมง ตัวเลข 48 ชั่วโมงที่ได้ยินบ่อยมาจากการเปลี่ยน nameserver ที่ระดับ registrar ซึ่ง TTL ของ NS record มักยาวเป็นวัน และจาก resolver บางแห่งที่ไม่ยอมเคารพ TTL

คนต่างคนเห็นคนละเว็บ ไม่ใช่เพราะ DNS “ยังกระจายไม่ถึง” แต่เพราะแต่ละคนใช้ resolver คนละตัว และแต่ละตัวถามต้นทางครั้งล่าสุดคนละเวลา

เคส mykaset.com เราไม่ได้ลด TTL ก่อน และ record เดิมที่โฮสต์เก่าตั้งไว้ยาว 8.8.8.8 เลยค้างค่าเก่าถึง 2 ชั่วโมงกว่า ขณะที่ resolver อื่นที่ไม่เคยถามชื่อนี้ได้ค่าใหม่ทันที

ทำไมต้องลด TTL ก่อนย้าย ไม่ใช่ตอนย้าย

ถ้าแก้ TTL จาก 3600 เป็น 300 แล้วเปลี่ยน IP ทันทีในนาทีเดียวกัน ไม่ช่วยอะไรเลย เพราะคนที่จำค่าเก่าอยู่ จำพร้อม TTL 3600 ตัวเก่า วิธีที่ถูกคือ

  1. หนึ่งวันก่อนย้าย แก้ TTL ของ record ที่จะเปลี่ยนเหลือ 300 วินาที (IP ยังเป็นตัวเก่า)
  2. รอให้ค่าเก่าหมดอายุทั่วโลก (รอเท่า TTL เดิม ถ้าเดิม 86400 ก็ต้องรอหนึ่งวันจริง ๆ)
  3. วันย้าย เปลี่ยน IP ทุกคนเห็นค่าใหม่ภายใน 5 นาที
  4. เว็บใหม่นิ่งแล้วค่อยปรับ TTL กลับเป็น 3600 เพื่อลดภาระ nameserver

เช็กว่าแต่ละชั้นเห็นอะไร

ถามต้นทางก่อน ถ้าต้นทางยังไม่ใช่ค่าใหม่ แปลว่าเรายังแก้ไม่สำเร็จ ไม่ใช่เรื่อง cache

# Ubuntu 24.04: ต้นทาง กับ resolver สาธารณะ
dig +short NS mykaset.com                       # หาว่า nameserver คือใคร
dig +short mykaset.com @ns1.digitalocean.com    # ต้นทาง
dig +short mykaset.com @8.8.8.8                 # Google
dig +short mykaset.com @1.1.1.1                 # Cloudflare
dig +short mykaset.com                          # resolver ที่เครื่องเราใช้จริง
# Windows 11 (PowerShell)
nslookup mykaset.com ns1.digitalocean.com
nslookup mykaset.com 8.8.8.8
Resolve-DnsName mykaset.com -Type A -Server 8.8.8.8   # แสดงคอลัมน์ TTL ที่เหลือด้วย

ถ้าต้นทางถูกแล้ว แต่เครื่องเรายังเห็นเก่า ล้างชั้นที่ใกล้ตัวที่สุดก่อน

ipconfig /flushdns                 # Windows: ล้าง cache ของ OS
sudo resolvectl flush-caches       # Ubuntu 24.04 (systemd-resolved)

Chrome มี cache ของตัวเองอีกชั้น เปิด chrome://net-internals/#dns แล้วกด Clear host cache ถ้าทำครบแล้วยังเห็นเก่า ตัวที่ค้างคือ resolver ซึ่งเราไม่ได้เป็นเจ้าของ ทางเลือกคือรอ เปลี่ยน DNS ของเครื่องไปใช้ตัวอื่นชั่วคราว หรือถ้าตัวที่ค้างคือ Google ใช้เครื่องมือล้างของเขาที่ dns.google/cache ใส่ชื่อโดเมนและชนิด record แล้วกด Flush ครั้งนั้นเรากดล้างแล้ว 8.8.8.8 ตอบค่าใหม่ทันที Cloudflare ก็มีหน้า Purge Cache แบบเดียวกันที่ one.one.one.one/purge-cache ล้างได้เฉพาะ resolver ของเขา คนที่ใช้ DNS ของ ISP ยังต้องรอเหมือนเดิม

certbot ก็ดู DNS สาธารณะ ไม่ใช่เครื่องเรา

ตอนขอใบรับรองด้วย HTTP-01 Let’s Encrypt จะ resolve ชื่อโดเมนจากหลายจุดทั่วโลก (เครื่องหลัก + remote perspectives หลายแห่ง และต้องผ่านเกินกึ่งหนึ่ง) แล้วมาดึงไฟล์ท้าทายที่ http://โดเมน/.well-known/acme-challenge/ ถ้าจุดไหนยังได้ IP เก่า มันจะไปเคาะโฮสต์เก่า ไม่เจอไฟล์ แล้ว challenge ล้ม ซ้ำได้ไม่กี่ครั้งก็ติด rate limit

สคริปต์เพิ่มเว็บของเราจึงเช็กก่อน certbot ทุกครั้ง โดยถาม nameserver ตัวจริง ไม่ใช่ resolver ของเครื่อง

# Ubuntu 24.04: หยุดถ้าต้นทางยังไม่ชี้มาที่เครื่องนี้
MY_IP=$(curl -s https://api.ipify.org)
NS=$(dig +short NS "$DOMAIN" | head -1)
DNS_IP=$(dig +short "$DOMAIN" @"$NS" | tail -1)
[ "$DNS_IP" = "$MY_IP" ] || { echo "DNS ยังชี้ไป $DNS_IP ไม่ใช่ $MY_IP รอก่อน"; exit 1; }

ผ่านด่านนี้แล้วยังควรเช็ก @8.8.8.8 และ @1.1.1.1 อีกครั้งก่อนกดขอจริง เพราะ Let’s Encrypt ก็ไปทาง DNS สาธารณะเหมือนกัน หรือเลี่ยงไปใช้ DNS-01 ที่ไม่ต้องให้ใครมาเคาะ เซิร์ฟเวอร์ ก็ได้

เช็กลิสต์ย้ายโดเมน

  • หนึ่งวันก่อน: ลด TTL ของ A/AAAA และ CNAME ที่จะเปลี่ยนเหลือ 300
  • เซิร์ฟเวอร์ ใหม่พร้อม ทดสอบผ่านไฟล์ hosts หรือ curl --resolve mykaset.com:80:IP_ใหม่ http://mykaset.com/
  • วันย้าย: เปลี่ยน IP ที่ nameserver แล้ว dig @ns1... ยืนยันว่าต้นทางถูก
  • รอจน @8.8.8.8 และ @1.1.1.1 ตอบค่าใหม่ ค้างก็กด flush ที่ dns.google/cache
  • ค่อยรัน certbot (HTTP-01) หรือใช้ DNS-01
  • ปล่อยโฮสต์เก่าไว้อีกอย่างน้อยเท่า TTL เดิม อย่าปิดวันนั้น
  • นิ่งแล้ว ปรับ TTL กลับ 3600

ข้อผิดพลาดที่เจอบ่อย

  • ดูจากเครื่องตัวเองแล้วสรุปว่าเสร็จ เครื่องเราอาจเห็นใหม่แล้วแต่ลูกค้ายังไม่เห็น หรือกลับกัน ถามต้นทางกับ resolver สาธารณะเสมอ
  • ปิดโฮสต์เก่าทันที คนที่ยังได้ IP เก่าจะเจอ error แทนที่จะเจอเว็บเก่า
  • ลืมลบไฟล์ hosts หลังทดสอบ แล้วงงว่าทำไมเห็นไม่เหมือนคนอื่น
  • ลด TTL พร้อมเปลี่ยน IP ในครั้งเดียว ซึ่งไม่ช่วยอะไรตามที่อธิบายข้างบน

แหล่งอ้างอิง

คำถามที่พบบ่อย

ย้ายเว็บแล้วเห็นเว็บเก่า ต้องรอกี่ชั่วโมง

อย่างมากเท่ากับ TTL ของ record เก่า นับจากตอนที่แก้ เช่น TTL 3600 รอไม่เกิน 60 นาที ถ้าอยากรู้ว่าเหลืออีกเท่าไร ถาม resolver ที่ยังตอบค่าเก่าด้วย dig แล้วดูเลข TTL ที่นับถอยหลังในคำตอบ

ทำไมเพื่อนเห็นเว็บใหม่แล้ว แต่เรายังเห็นเว็บเก่า

คนละ resolver กัน resolver ของเพื่อนอาจไม่เคยถามชื่อนี้มาก่อนเลยได้ค่าใหม่ทันที ส่วนของเราถามไว้ก่อนย้ายและยังจำค่าเก่าอยู่ ลองล้าง cache ที่เครื่องก่อน ถ้ายังไม่ได้ก็เป็นที่ resolver ต้องรอหรือเปลี่ยนไปใช้ resolver อื่นชั่วคราว

ไฟล์ hosts ช่วยอะไรได้บ้าง

ใส่ชื่อโดเมนกับ IP ใหม่ในไฟล์ hosts ของเครื่องตัวเอง เบราว์เซอร์จะข้าม DNS ไปเลย ใช้ทดสอบเว็บใหม่ก่อนย้ายได้ดี แต่อย่าลืมลบออก ไม่อย่างนั้นจะเห็นไม่เหมือนคนอื่นไปอีกนาน

คำสั่งและค่าตั้งในบทความทดสอบบนระบบตัวอย่าง ลองบนเครื่องทดสอบก่อนใช้กับระบบจริงเสมอ

อ่านต่อ

#Serverเริ่มต้น

เซิร์ฟเวอร์ ที่บ้าน IP เปลี่ยนบ่อย ทำ DDNS เองด้วย API ของ DNS และ cron

ทำไม IP บ้านถึงเปลี่ยน และสคริปต์ Python สั้น ๆ ที่เช็ก IP ทุก 5 นาที แล้วแก้ A record ผ่าน API ของผู้ให้บริการ DNS ยกตัวอย่าง DigitalOcean พร้อมเรื่อง TTL และ token

อ่าน 13 นาที
#Serverกลาง

Deploy ทีเดียวทั้งก้อน ไม่มีเว็บครึ่ง ๆ และย้อนกลับได้ในคำสั่งเดียว

ก๊อปไฟล์ทับโฟลเดอร์เว็บตรง ๆ ผู้ใช้จะเจอเว็บที่อัปโหลดไปครึ่งเดียว วิธีสลับโฟลเดอร์ที่เว็บนี้ใช้ ช่องว่างเล็ก ๆ ที่ยังเหลือ และแบบ symlink ที่สลับได้ทันที

อ่าน 7 นาที
#Serverกลาง

PostgreSQL 18: ใช้ uuidv7() แทน UUID v4 และเปิด async I/O ให้ถูก

PostgreSQL 18 มี uuidv7() ที่เรียงตามเวลา ทำให้ B-tree index เล็กและร้อนน้อยกว่า v4 และมี async I/O ผ่าน io_method เลือก worker หรือ io_uring พร้อมตัวอย่างคำนวณขนาด index

อ่าน 9 นาที