EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / DirectAdmin / ย้าย DA CentOS 7 → Debian 12 บน Proxmox ตอนที่ 1 — NAT pre-stage
DirectAdmin — ซีรีส์ ย้าย DA CentOS7 -> Debian12 [1]

ย้าย DA CentOS 7 → Debian 12 บน Proxmox ตอนที่ 1 — NAT pre-stage

โดย Ton-Or ·20 พ.ค. 2026·อ่าน 11 นาที
ย้าย DA CentOS 7 → Debian 12 บน Proxmox ตอนที่ 1 — NAT pre-stage

server ตัวหลักของลูกค้ารันบน CentOS 7 มาเกือบสิบปี หมด EOL ไปกลางปี 2024 ผมดองไว้นานพอควรกว่าจะได้ลงมือ ตอนนี้ย้ายเสร็จแล้ว นิ่งดี ใช้งานจริงมาเกือบเดือน เลยมาเล่าวิธีที่ผมใช้

สรุปใน 1 นาที

อาการ/ปัญหา
ย้าย DirectAdmin จาก CentOS 7 ไป Debian 12 แล้วกลัว downtime นาน
ใครควรอ่าน
ผู้ดูแล shared host ที่วางแผนย้าย OS ของเครื่องที่มีลูกค้าใช้งานอยู่
ทางแก้แบบสั้น
สร้าง VM ใหม่บน internal bridge แบบ NAT เตรียมระบบให้เสร็จขณะที่ VM เก่ายังให้บริการ แล้วค่อยสลับเครื่องในจังหวะสั้นๆ
ข้ามไปขั้นตอน

server ตัวหลักของลูกค้าผมรันบน CentOS 7 มาเกือบสิบปี หมด EOL ไปตั้งแต่กลางปี 2024 ดองมานานพอควรครับ มี user อยู่บนเครื่องนี้ 80 กว่าราย รอย้าย OS ใหม่กันทั้งนั้น งานเพิ่งเสร็จไปปลายเดือนที่แล้ว ตอนนี้นิ่งดี ใช้งานจริงมาเกือบเดือนยังไม่มีปัญหา

ซีรีส์นี้ผมจะเล่ากระบวนการย้ายทั้งหมดตั้งแต่ต้นจนจบ ตอนแรกขอเริ่มที่ขั้น NAT pre-stage ก่อน ซึ่งเป็นหัวใจของการลด downtime ครับ

แนวคิด: เตรียม VM ใหม่ก่อน โดยไม่ดับ VM เก่า

หลักการง่ายมากครับ แทนที่จะ shutdown VM เก่าก่อนแล้วค่อยมานั่ง build VM ใหม่ (ซึ่งจะทำให้ลูกค้าค้างเป็นชั่วโมงๆ) ผมเลือกสร้าง VM ใหม่ขึ้นมาบน internal bridge แยกต่างหาก อยู่ใน private subnet ที่ไม่ชนกับ public IP ของเครื่องเก่า

ระหว่างที่ผมเตรียม VM ใหม่อยู่นั้น VM เก่ายัง online ให้บริการลูกค้าตามปกติ ไม่รู้ตัวด้วยซ้ำว่ามีเครื่องใหม่กำลังถูกเตรียมอยู่ข้างๆ พอเตรียมระบบเสร็จเรียบร้อยจนใกล้ครบกระบวนการ ค่อยมา swap NIC ทีหลังในจังหวะสั้นๆ

บอกกันตรงๆ ก่อนเลยครับ — ตอนแรกผมตั้งใจว่าเทคนิคนี้จะทำให้ downtime ของลูกค้าเข้าใกล้ศูนย์ แต่พอลงมือจริงไปเจอกำแพงสองเรื่อง คือ DA Legacy license กับ qcow2 ที่อ่านช้า สุดท้ายเลยจบที่ downtime จริงประมาณ 1 ชั่วโมง รายละเอียดเดี๋ยวเล่าเต็มๆ ตอนท้าย ตรงนี้ขอลงรายละเอียดส่วน prep ก่อน

โครงสร้าง 2-bridge

โครงสร้างเครือข่ายที่ผมวางไว้คือใช้ bridge สองตัวบน Proxmox host ตัวหนึ่งเป็น public อีกตัวเป็น internal ที่มี NAT ออก

ผังเครือข่ายInternet->PVE hostvmbr0 / public IP->NAT MASQvmbr1->VM ใหม่192.168.10.20
vmbr0

public bridge

  • PVE host + VM เก่า ผูกอยู่ที่นี่
  • ใช้ IP จริง 203.0.113.x
  • ลูกค้าเข้าผ่านทางนี้ตามปกติ
vmbr1

internal bridge

  • private 192.168.10.0/24
  • NAT egress ออกทาง vmbr0
  • VM ใหม่อยู่ที่นี่ เตรียมระบบ

จุดสำคัญคือ VM ใหม่ผูกอยู่กับ vmbr1 จึงไม่ชนกับ public IP ของ VM เก่าเลย ทำให้สองเครื่องทำงานคู่ขนานกันได้บน host เดียวกัน

InternetPVE hostvmbr0 public bridge (bridge-ports eno1)VM เก่ายังให้บริการลูกค้าปกติNAT MASQUERADEDNAT พอร์ต ssh เข้า VM ใหม่vmbr1 internal bridge 192.168.10.0/24VM ใหม่ 192.168.10.20bridge-ports none ไม่ผูก NIC จริง
VM เก่าอยู่บน vmbr0 ที่ใช้ IP จริง ส่วน VM ใหม่อยู่บน vmbr1 ที่ไม่ชนกับ IP เดิม ออก internet ผ่าน MASQUERADE และเข้าจากข้างนอกผ่าน DNAT ที่ host ทำให้สองเครื่องวิ่งคู่ขนานกันได้

ตั้งค่า network ฝั่ง PVE — /etc/network/interfaces

ผมกำหนด vmbr0 เป็น bridge ขา public ผูกกับ physical NIC ของ host ส่วน vmbr1 เป็น bridge ลอยๆ ไม่มี physical port แต่ทำหน้าที่เป็น gateway ของ private subnet พร้อม MASQUERADE ออก vmbr0

auto vmbr0
iface vmbr0 inet static
    address 203.0.113.41/29
    gateway 203.0.113.1
    bridge-ports eno1
    bridge-stp off
    bridge-fd 0

auto vmbr1
iface vmbr1 inet static
    address 192.168.10.254/24
    bridge-ports none
    bridge-stp off
    bridge-fd 0
    post-up   iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o vmbr0 -j MASQUERADE
    post-up   iptables -A FORWARD -s 192.168.10.0/24 -j ACCEPT
    post-up   iptables -A FORWARD -d 192.168.10.0/24 -j ACCEPT
    post-down iptables -t nat -D POSTROUTING -s 192.168.10.0/24 -o vmbr0 -j MASQUERADE
    post-down iptables -D FORWARD -s 192.168.10.0/24 -j ACCEPT
    post-down iptables -D FORWARD -d 192.168.10.0/24 -j ACCEPT

bridge-ports none ตรงนี้คือกุญแจสำคัญครับ มันบอกว่า vmbr1 ไม่ต้องผูกกับ NIC จริงตัวไหน เป็น bridge ภายใน host ล้วนๆ ส่วน rule MASQUERADE คือตัวที่ทำให้ทุก packet ที่ออกจาก 192.168.10.0/24 ถูกแปลงต้นทางเป็น IP ของ host แล้ววิ่งออก vmbr0 ได้ — VM ใหม่จึงต่อ internet ได้ตามปกติ ดึง package มาลงได้ แม้จะไม่มี public IP เป็นของตัวเอง

เสร็จแล้ว ifup vmbr1 ขึ้นมา แล้วตรวจว่า bridge ขึ้นจริงและ rule NAT ติด

ifup vmbr1
ip a show vmbr1
iptables -t nat -L POSTROUTING -n | grep MASQ

ถ้าเห็น address 192.168.10.254 บน vmbr1 และเห็นบรรทัด MASQUERADE ใน chain POSTROUTING ก็แปลว่าฝั่ง network พร้อมแล้ว

SSH access เข้า VM ใหม่ผ่าน PVE

ทีนี้ VM ใหม่อยู่ใน private subnet เราจะ ssh ตรงจากข้างนอกไม่ได้ ต้องทำ DNAT forward ผ่าน host เข้าไป ผมเลือกใช้ port หนึ่งบน host (สมมติเรียกว่า <fwd-port>) ชี้เข้า port 22 ของ VM ใหม่

iptables -t nat -A PREROUTING -p tcp --dport <fwd-port> -j DNAT --to 192.168.10.20:22
iptables -A FORWARD -p tcp -d 192.168.10.20 --dport 22 -j ACCEPT
netfilter-persistent save

netfilter-persistent save สำคัญครับ ไม่งั้น rule หายตอน reboot จากนั้นทดสอบจาก workstation

ssh -p <fwd-port> [email protected]

ถ้าทุกอย่างถูก เราจะทะลุผ่าน NAT forward เข้าไปถึง shell ของ VM ใหม่ในเครื่องเดียว ทั้งที่มันยังไม่มี IP จริงเป็นของตัวเอง

สร้าง VM ใหม่บน vmbr1

ขั้นถัดมาคือสร้างตัว VM ขึ้นมาผูกกับ vmbr1 ตรง ผมใช้ qm create กำหนด spec ตามที่ลูกค้าต้องการ

qm create 101 \
  --name newserver \
  --memory 60000 \
  --cores 16 \
  --machine q35 \
  --bios seabios \
  --scsihw virtio-scsi-single \
  --net0 virtio,bridge=vmbr1 \
  --scsi0 VMDATA:900,discard=on,ssd=1,iothread=1

ตรง --net0 ...,bridge=vmbr1 คือจุดที่ผูก VM ไว้กับ internal bridge ทำให้มันเกิดมาอยู่ใน private subnet เลย

ขั้นนี้มี gotcha อยู่ 4 อันที่ผมเคยโดนมาก่อน ขอเตือนไว้ให้ระวัง

4 จุดที่ทำให้ผมเสียเวลา

1) อย่าใส่ viommu=on — installer จะตก kernel panic บน Debian 12 + q35 ผมเสียเวลาไป 2 ชั่วโมงกว่าจะรู้ว่าตัวนี้คือต้นเหตุ. 2) ใช้ q35 ไม่ใช่ i440fx — เป็น modern PCIe ให้ ZFS performance ดีกว่า. 3) NIC name บน Debian 12 + q35 + virtio จะเป็น enp6s18 ไม่ใช่ ens18 ของ Debian 13 ใครชินกับ ens18 มาก่อนจะหลงทาง. 4) virtio queues=8 ตั้งทีหลังเพื่อให้ใช้ทุก vCPU แบบ concurrent.

ส่วน virtio multiqueue ผมไปตั้งทีหลังด้วยคำสั่งนี้

qm set 101 --net0 virtio,bridge=vmbr1,queues=8

การตั้ง queues ให้เท่ากับจำนวน vCPU จะช่วยให้ traffic กระจายงานข้าม core ได้ ไม่ไปกองอยู่ core เดียวเวลามี throughput สูงๆ

ลง Debian 12 minimal

boot เข้า ISO แล้วเลือก install แบบ minimal เลยครับ ติ๊กเฉพาะ SSH server กับ standard system utilities พอ ไม่ต้องลง desktop หรือ service อะไรเกินจำเป็น เดี๋ยว CustomBuild จะมาวางของที่ต้องใช้เองทีหลัง

ส่วน partition ผมแบ่งประมาณนี้

500M/boot
200G/
ใหญ่สุด/home
8Gswap
8G/tmp

/home ให้ใหญ่ที่สุดเพราะ data ของ user ทั้ง 80 กว่ารายจะไปกองอยู่ตรงนั้น

Quota mount option — จุดที่พลาดง่าย

ตรงนี้สำคัญมากสำหรับ DirectAdmin ที่ partition / และ /home ต้องใส่ mount option สำหรับ quota เข้าไปด้วย

usrjquota=aquota.user,grpjquota=aquota.group,jqfmt=vfsv0
ใช้ vfsv0 ไม่ใช่ vfsv1

ผมเลือก vfsv0 ทั้งที่ DA docs รุ่นใหม่แนะนำ vfsv1 เพราะ vfsv0 compat กับ quota file format ของ CentOS 7 เดิม ตอน restore quota ของลูกค้ามา ถ้าใช้ vfsv1 มันจะ restore ไม่ขึ้น ผมเสียเวลาลองรอบหนึ่งก่อนถึงยอมเปลี่ยนกลับมา vfsv0

ติดตั้ง base packages

หลัง install OS เสร็จ ผมลง package พื้นฐานที่ DA และ CustomBuild ต้องใช้ก่อน

apt update && apt install -y \
    openssh-server curl wget quota iptables chrony \
    perl python3 sudo rsync bzip2 \
    netfilter-persistent

systemctl enable --now chrony
chronyc sources -v
chrony สำคัญกับ DA license

เวลาบนเครื่องต้องตรง เพราะ DA license validation จะ check time ด้วย ผมเคยลืมตั้ง chrony มาก่อน ผลคือ license activate ไม่ผ่านเพราะ time skew มากเกินไป เสียเวลาไล่หาตั้งนาน กว่าจะรู้ว่าเป็นเรื่องนาฬิกา

ประโยชน์ที่ได้: prep ทั้งหมดทำได้โดยไม่กระทบลูกค้า

นี่คือคุณค่าจริงของ NAT pre-stage ครับ — ทุกขั้นตอนเตรียมระบบด้านล่างนี้ทำบน VM ใหม่ได้เลยขณะที่ลูกค้ายังใช้งานเครื่องเก่าอยู่

  • Debian 12 install + base packages — ราว 30 นาที
  • DA install + license activate — ราว 10 นาที (DA panel ตัวเก่าจะหลุดไปแค่ 1 นาที แต่ services ฝั่งลูกค้ายังทำงานปกติ)
  • CustomBuild stack — ราว 2 ถึง 2.5 ชั่วโมง
  • custom data prep (DNSSEC keys, hooks, templates) — ราว 30 นาที
  • firewall config staging — ราว 10 นาที
  • pre-cutover smoke test — ราว 30 นาที

รวมแล้วราว 3 ถึง 4 ชั่วโมงของงาน prep ทั้งหมด — ช่วงนี้ลูกค้าไม่กระทบเลยแม้แต่นิดเดียว เพราะทุกอย่างเกิดบนเครื่องคู่ขนานที่ซ่อนอยู่ใน private subnet

แต่ cutover เองยังต้องใช้เวลา ไม่ใช่ศูนย์

ตอนแรกผมหวังว่า downtime จะเข้าใกล้ศูนย์ แต่ของจริงไม่เป็นอย่างนั้น เพราะติดสองเรื่อง

กำแพงที่ 1

DA Legacy license

  • เป็นแบบ last DA wins
  • รัน DA สองตัวพร้อมกันไม่ได้
  • ต้อง stop DA เก่าก่อนถึงจะ activate ตัวใหม่ได้
กำแพงที่ 2

qcow2 อ่านช้า

  • DA backup ของเครื่องเก่าใช้เวลาเป็นชั่วโมง
  • เป็น bottleneck หลักของ cutover
  • ตรงนี้เป็นเหตุผลที่ ZFS เข้ามาช่วยในตอนถัดไป

สองเรื่องนี้รวมกันทำให้ downtime จริงของลูกค้าจบที่ประมาณ 1 ชั่วโมง ไม่ใช่ศูนย์อย่างที่ตั้งใจไว้ตอนแรก รายละเอียดของ cutover เต็มๆ ผมจะเล่าในตอนท้ายของซีรีส์ครับ

ตอนหน้า

ตอนหน้าจะต่อเรื่อง storage — ผมจะถอด mdadm เก่าออก แล้วสร้าง ZFS mirror ขึ้นมาแทน โดยทำขณะที่ VM เก่ายังรัน online ให้บริการลูกค้าอยู่พร้อมกันเลย

ใครจะปรับ subnet, port, หรือ spec ให้เข้ากับเครื่องตัวเองก็ตามสะดวกครับ หลักการเหมือนกันหมด — เตรียมเครื่องใหม่ให้พร้อมก่อน แล้วค่อย swap ทีหลัง เพื่อให้ลูกค้ากระทบน้อยที่สุด ไว้นึกอะไรออกเพิ่มหรือเจอจุดที่ควรแก้ ผมจะมาอัปเดตให้ครับ

อยากให้เราทำให้ไหม?

ให้เราช่วยติดตั้ง ตั้งค่า ย้ายระบบ หรือแก้ปัญหาเซิร์ฟเวอร์ เพื่อให้คุณมีเวลาไปทำงานที่สำคัญกว่า

คุยเรื่องงานกับเรา

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

ความคิดเห็น 0

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย