เดิมทีการตั้งค่าบล็อกของผมถูกวางแผนให้เป็น โปรเจกต์ IPv6 ล้วนผ่าน WireGuard เนื่องจากรันอยู่บนโฮมเซิร์ฟเวอร์ (คุณสามารถขอที่อยู่ IPv6 ได้ฟรีที่ route64.org) เพื่อเพิ่มความสามารถในการเข้าถึง ตอนนี้ผมได้เพิ่ม IPv4 Proxy ภายนอกเข้ามาแล้ว (ขอบคุณ @Larvitz)
อย่างไรก็ตาม มีปัญหาเรื่อง SSL เกิดขึ้นทันที: เนื่องจากในตอนแรกทั้งเรคคอร์ด A และ AAAA วิ่งผ่าน Proxy ทำให้การตรวจสอบความถูกต้อง (Validation) ของ Let's Encrypt บนเซิร์ฟเวอร์ของผมล้มเหลว
วิธีแก้ปัญหา: "IPv6-Hack"
วิธีแก้คือการกำหนดให้ AAAA-Record ชี้ไปยัง IP ของ WireGuard บนเซิร์ฟเวอร์ของผมโดยตรง แทนที่จะส่งผ่าน Proxy เหมือนเดิม
- โดเมน:
blog.burningboard.org
- A-Record (Proxy):
194.28.98.217
- AAAA-Record (Server):
2a11:6c7:f05:a8::2 (WireGuard)
ด้วยการชี้ AAAA-Record ไปยัง IP ของ WireGuard โดยตรง Let’s Encrypt จะยังคงเข้าถึงเซิร์ฟเวอร์ของผมได้โดยตรงผ่าน IPv6 (เนื่องจากปกติแล้ว AAAA-Record จะได้รับความสำคัญก่อน) และออกใบรับรอง SSL ให้ ส่วนทราฟฟิก IPv4 จะถูกส่งต่อจาก Proxy มายังผมในรูปแบบที่เข้ารหัสไว้
การกำหนดค่าขั้นสุดท้าย
เพื่อให้การสื่อสารทำงานได้อย่างราบรื่น เราจำเป็นต้องปรับแต่งเซิร์ฟเวอร์ Caddy:
1. บนเซิร์ฟเวอร์ของผม (NixOS, blog.nix)
เพื่อให้ IP จริงของผู้เข้าชมส่งมาถึงอย่างถูกต้องและไม่ถูกเขียนทับด้วย IP ของ Proxy เราต้องกำหนดให้ Proxy นั้นเป็นที่น่าเชื่อถือ (trusted):
services.caddy.globalConfig = ''
servers {
trusted_proxies static 2a06:9801:1c:1000::10
}
'';
2. บน Proxy ภายนอก (Caddy)
เพื่อให้ Proxy ติดต่อกับเซิร์ฟเวอร์ของผมผ่าน HTTPS ได้อย่างถูกต้อง จะต้องส่งชื่อโฮสต์ (SNI) ไปด้วย:
reverse_proxy [https://[2a11:6c7:f05:a8::2]:443](https://[2a11:6c7:f05:a8::2]:443) {
header_up Host {host}
transport http {
tls_server_name blog.burningboard.org
}
}
ตอนนี้บล็อกสามารถเข้าถึงได้ทั้งผ่าน IPv4 และ IPv6 มีการเข้ารหัสที่ปลอดภัย และ IP ที่บ้านของผมก็ยังคงเป็นส่วนตัวอยู่! 🚀
สิ่งสำคัญที่สุดก่อนอื่นเลย: ไฟล์ Markdown ที่คุ้นเคยยังคงเป็นพื้นฐานเหมือนเดิม – ผมเป็นแฟนตัวยงของโซลูชันที่เรียบง่ายแบบนี้ แต่เบื้องหลังมีการเปลี่ยนแปลงไปเยอะมาก:
ผมได้ปรับแต่งการตั้งค่าไปหลายอย่าง:
📂 ไฟล์ MD: โครงสร้างบล็อกยังคงเรียบง่ายบนพื้นฐานของ Markdown
🌍 เป็นสากลยิ่งกว่าที่เคย: ตอนนี้บล็อกของผมรองรับการแปลถึง 43 ภาษา ใช่แล้ว รวมภาษาคลิงออนด้วย! 🖖 (Qapla'!)

เดิมทีผมวางแผนจะให้มีการแปลแบบเรียลไทม์อัตโนมัติทั้งหมดโดยอิงจากการตรวจจับภาษาของเบราว์เซอร์ สปอยล์เลยครับ: มันทำงานได้แค่บางส่วนเท่านั้น จะเห็นได้ว่า: AI นั้นน่าทึ่งมาก แต่ก็ยังไม่ถึงจุดที่เราต้องการให้เป็นเสียทีเดียว
วิธีแก้ปัญหา: ตอนนี้ผมใช้วิธีแปลทุกบทความล่วงหน้าเป็น ทุก ภาษาที่กำหนดไว้ ซึ่งส่งผลดีต่อการทำอันดับในเครื่องมือค้นหา (SEO) มากกว่าด้วย หากการตรวจจับอัตโนมัติไม่ทำงาน คุณสามารถเลือกภาษาที่ต้องการได้ด้วยตนเองผ่านไอคอนรูปโลก ซึ่งจะถูกบันทึกไว้ผ่านคุกกี้อย่างง่ายดาย
ตอนนี้การแปลดำเนินการด้วย Gemini 3 Flash ซึ่งให้ผลลัพธ์ที่ดีอย่างน่าประหลาดใจ อย่างไรก็ตาม เรายังต้องคอยตรวจสอบการทำงานของ AI อย่างใกล้ชิด: ในการรันแบบกลุ่ม (Bulk) ครั้งแรก แท็กต่างๆ ถูกแปลไปด้วยโดยผิดพลาด ซึ่งแน่นอนว่าไม่ได้วางแผนไว้แบบนั้น
โค้ดยังคงมีให้ใช้งาน (ถ้าสนใจก็ส่งข้อความมาหาผมได้เลย) 👍 แต่โปรดทราบว่าตอนนี้ระบบจำเป็นต้องใช้ Gemini API Key 🔑 ของตัวเองแล้ว
ฉันตัดสินใจเปลี่ยนบล็อกของฉันจาก WriteFreely มาเป็นระบบที่พัฒนาขึ้นเองอย่างรวดเร็ว: MD-Blog (แน่นอนว่า MD ย่อมาจาก Markdown) จุดเริ่มต้นเกิดจากการอัปเดตระบบเก่าที่ล้มเหลว แต่สุดท้ายมันกลับเป็นแรงผลักดันที่สมบูรณ์แบบในการทำให้ทุกอย่างง่ายขึ้นอย่างสิ้นเชิง และทำให้ฉันสามารถ ควบคุมการออกแบบ ได้อย่างเต็มที่
หัวใจสำคัญคือไฟล์ Markdown ง่ายๆ ในโฟลเดอร์ data/ ซึ่งจะถูกแปลงเป็น HTML ที่ทันสมัยในขณะประมวลผล ผลลัพธ์ที่ได้นั้นรวดเร็วมาก ไม่ต้องใช้ฐานข้อมูล และด้วยระบบการออกแบบของตัวเอง (รวมถึง Dark Mode) ตอนนี้มันจึงดูตรงตามที่ฉันจินตนาการไว้ทุกประการ แถมยังมี ปุ่มแชร์ไปยัง Mastodon ที่ทันสมัยติดตั้งมาให้ในตัวเลยด้วย
หากใครสนใจโค้ดหรือการตั้งค่าที่เรียบง่ายนี้ สามารถติดต่อฉันผ่าน Mastodon ได้เลย!
อันที่จริงแนวคิดเบื้องหลัง #Winboat นั้นยอดเยี่ยมมาก แต่การนำไปใช้งานจริงในปัจจุบันดูเหมือนจะยังไม่ค่อยเสถียรนัก ตั้งแต่ติดตั้งเมื่อต้นปีที่ผ่านมา ระบบก็ทำงานได้ดีมาตลอด แต่ทว่าวันนี้ซอฟต์แวร์กลับหยุดทำงานไปโดยสิ้นเชิง
จู่ๆ อิมเมจก็แจ้งเตือนว่าหน่วยความจำ (RAM) ไม่เพียงพอ ผมพยายามแก้ไขปัญหาด้วยตัวเองแล้ว แต่นั่นกลับทำให้ระบบใช้งานไม่ได้อย่างถาวร แทนที่จะเสียเวลาไปกับการหาสาเหตุของปัญหา ผมจึงตัดสินใจเปลี่ยนมาใช้ Dockurr Windows-Image โดยตรง ซึ่งจริงๆ แล้วมันคือพื้นฐานทางเทคนิคของ Winboat นั่นเอง

1. การเตรียมการ
เนื่องจากผมใช้ Podman ผมจึงเริ่มจากการสร้างไดเรกทอรีที่จำเป็นบนระบบโฮสต์ของผมก่อน เพื่อให้ข้อมูลยังคงอยู่ครบถ้วนในกรณีที่ต้องสร้างคอนเทนเนอร์ใหม่:
mkdir -p $HOME/Windows/System
mkdir -p $HOME/Windows/Shared
2. คำสั่งเริ่มต้น
ข้อควรระวัง: ให้แทนที่ตัวยึดตำแหน่ง (placeholder) ในตัวแปร -e USERNAME และ -e PASSWORD ด้วยข้อมูลการเข้าสู่ระบบส่วนตัวของคุณ
podman run -d \
--name windows \
-p 8006:8006 \
--device=/dev/kvm \
--cap-add NET_ADMIN \
-e RAM_SIZE="8G" \
-e USERNAME="Carsten" \
-e PASSWORD="1234" \
-e LANGUAGE="German" \
-v $HOME/Windows/System:/storage:Z \
-v $HOME/Windows/Shared:/shared:Z \
--stop-timeout 120 \
dockurr/windows
ทันทีที่คอนเทนเนอร์ทำงาน คุณสามารถเข้าถึงอินสแตนซ์ Windows ได้โดยตรงผ่านเบราว์เซอร์ของคุณ:
http://127.0.0.1:8006

3. สรุป
ผมต้องรันคำสั่งข้างต้นเพียงครั้งเดียวเท่านั้น ในการใช้งานประจำวัน ตอนนี้คุณสามารถควบคุมสภาพแวดล้อม Windows ได้อย่างสะดวกสบายผ่านคำสั่งลัดเหล่านี้:
- เริ่มทำงาน:
podman start windows
- หยุดทำงาน:
podman stop windows (หรือสั่งปิดเครื่องจากภายใน Windows โดยตรง)
- ตรวจสอบสถานะ:
podman ps -a
ลิงก์เพิ่มเติม:
ผมได้ติดตั้งบล็อกส่วนตัวของตัวเองขึ้นมา — โดยมีจุดประสงค์หลักคือเพื่อทำความรู้จักกับ #NixOS ให้มากขึ้น ซึ่งก็น่าประหลาดใจที่ทุกอย่างดำเนินไปอย่างราบรื่นและไม่ซับซ้อนเลย
WriteFreely ตอบโจทย์นี้ได้ดีมาก ทั้งความเรียบง่าย ติดตั้งได้รวดเร็ว และไม่มีฟีเจอร์ที่เกินความจำเป็น เหมาะอย่างยิ่งสำหรับการเริ่มต้นเขียนและเรียนรู้สิ่งใหม่ๆ ไปพร้อมกัน การตั้งค่าก็ดูสะอาดตาและเข้าใจง่าย เพียงแค่กำหนดตัวเลือกไม่กี่อย่าง เตรียมไดเรกทอรี ตั้งค่า Reverse Proxy ไว้ข้างหน้า เท่านี้ก็เรียบร้อย
นี่คือการตั้งค่า NixOS ปัจจุบันของผมสำหรับโปรเจกต์นี้:
{ config, pkgs, ... }:
{
services.writefreely = {
enable = true;
host = "blog.burningboard.org";
settings = {
server = {
port = 8080;
min_log_level = "debug";
};
app = {
host = "https://blog.burningboard.org";
single_user = true;
landing = "/read";
wf_modesty = true;
federation = true;
public_stats = true;
theme = "write";
};
};
stateDir = "/opt/writefreely";
};
# แก้ไขสำหรับการสร้างคีย์ ActivityPub: Federation จำเป็นต้องใช้ openssl
systemd.services.writefreely.path = [ pkgs.openssl ];
# สร้างไดเรกทอรีข้อมูลโดยอัตโนมัติพร้อมกำหนดสิทธิ์ที่ถูกต้อง
systemd.tmpfiles.rules = [
"d /opt/writefreely 0700 writefreely writefreely -"
];
services.caddy.virtualHosts."blog.burningboard.org".extraConfig = ''
reverse_proxy 127.0.0.1:8080 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
'';
}
หลักๆ ก็มีเพียงเท่านี้ NixOS ช่วยให้การตั้งค่าบริการต่างๆ เป็นไปอย่างเป็นระเบียบและสามารถทำซ้ำได้ง่ายจริงๆ