ปัญหา: 31 ตัว API keys อยู่เป็น plain text
ตอนอยู่บน Mac Mini ทุกอย่างเก็บใน macOS Keychain — encrypted by default แต่พอย้ายมา VPS ก็เจอว่า credentials ทั้งหมด dump ออกมาเป็น .env หรือ plain text files
Solution: SOPS + age encryption
- เข้ารหัสทุก secret ด้วย SOPS (Mozilla SOPS)
- ใช้ age key สำหรับ encrypt/decrypt
- เขียน init script ที่ decrypt เฉพาะตอน boot
- เก็บ decrypted values ใน RAM (environment variables) — ไม่เขียน disk เลย
ผลลัพธ์: บน disk มีแต่ encrypted files ถ้าใคร hack เข้ามาอ่าน disk ตรงๆ ก็ได้แค่ ciphertext
บทเรียนราคาแพง: อย่าแก้ SSH + Firewall พร้อมกัน
นี่คือส่วนที่เจ็บปวดที่สุด
รอบที่ 1: UFW vs nftables
Ubuntu 24.04 เปลี่ยนจาก iptables เป็น nftables เป็น default แล้ว แต่ UFW (Uncomplicated Firewall) ยังไม่ adapt เต็มที่ — ลง ufw enable แล้ว rules ที่เขียนไม่ match กับ nftables backend
ผล: Firewall ดูเปิดอยู่ แต่จริงๆ rules ไม่ทำงาน → ports ที่ควร block ยังเปิดอยู่
รอบที่ 2: Tailscale เขย่า iptables
เปิด Tailscale แล้วมันเปลี่ยน iptables rules ของระบบทุกครั้งที่ start — ทับ rules ที่เราเขียนเอง
รอบที่ 3: ล็อกตัวเองออก
ลอง harden SSH (เปลี่ยน port, disable root login, key-only) + ตั้ง nftables DROP policy + เปลี่ยน user permissions พร้อมกัน ทั้ง 3 อย่าง
ผล: SSH ไม่รับ connection, firewall block ทุก port → ต้องเข้า VPS provider console แก้หลายรอบ
กฎทอง: ทำทีละอย่าง ทดสอบทุกครั้ง
- แก้ SSH config → เปิด connection ใหม่ทดสอบก่อนปิด session เดิม
- ตั้ง firewall → ยืนยัน ports ที่ต้องการ open ก่อน set DROP policy
- แล้วค่อยไป user permissions
สิ่งที่ได้มา


- ✅ SSH: ไม่ใช้ port 22 + key-only authentication + root login ปิด
- ✅ nftables: DROP policy default, allow เฉพาะ ports ที่จำเป็น
- ✅ fail2ban: ban 4 IPs ใน 24 ชม. แรก
- ✅ Kernel hardening: sysctl 25+ rules
- ✅ auditd: monitoring 16 rules
- ✅ Rootkit scanner: ทำงานตอน boot + process monitor ทุก 15 นาที
- ✅ API keys: encrypted at rest ด้วย SOPS + age
TL;DR
- อย่าใช้ UFW บน Ubuntu 24.04 — เขียน nftables rules เองจะแม่นกว่า
- Tailscale จะขัดกับ firewall rules — ต้องจัดการลำดับ startup
- ทำทีละอย่าง — แก้ SSH → test → firewall → test → permissions → test
- เก็บ session ที่ใช้งานได้ไว้ — อย่าปิดจนกว่า confirm ว่าอะไรใหม่ทำงาน
- Encrypt secrets at rest — SOPS + age ทำงานดีมาก