[{"data":1,"prerenderedAt":12280},["ShallowReactive",2],{"blog-entry-numbers":3,"blogs-2026-10-27-claude-code-server-management":119,"next-blog-2026-10-27-claude-code-server-management":936,"prev-blog-2026-10-27-claude-code-server-management":936,"recommended-blog-2026-10-27-claude-code-server-management":947,"related-blog-2026-10-27-claude-code-server-management":1408},[4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,75,78,81,84,87,90,92,94,96,99,102,105,107,110,113,116],{"path":5,"date":6},"\u002Fblogs\u002F2024-01-14-setup-ubuntu-server","2024-01-14",{"path":8,"date":9},"\u002Fblogs\u002F2024-01-19-setup-uptime-kuma","2024-01-19",{"path":11,"date":12},"\u002Fblogs\u002F2024-01-20-simple-paginate","2024-01-20",{"path":14,"date":15},"\u002Fblogs\u002F2024-06-06-openvpn-exclude-network","2024-06-06",{"path":17,"date":18},"\u002Fblogs\u002F2025-04-14-dotenv-leak-lab","2025-04-14",{"path":20,"date":21},"\u002Fblogs\u002F2025-04-15-ubuntu-pro","2025-04-15",{"path":23,"date":24},"\u002Fblogs\u002F2025-04-24-n8n-part-1","2025-04-24",{"path":26,"date":27},"\u002Fblogs\u002F2025-04-25-setup-nuxt-medium-zoom","2025-04-25",{"path":29,"date":30},"\u002Fblogs\u002F2025-04-28-n8n-part-2","2025-04-28",{"path":32,"date":33},"\u002Fblogs\u002F2025-05-10-n8n-with-telegram-notify","2025-05-10",{"path":35,"date":36},"\u002Fblogs\u002F2025-05-12-next-dns","2025-05-12",{"path":38,"date":39},"\u002Fblogs\u002F2025-05-18-from-old-notebook-to-home-lab-server","2025-05-18",{"path":41,"date":42},"\u002Fblogs\u002F2025-05-23-nuxt-tailwindcss-nuxtui-setup","2025-05-23",{"path":44,"date":45},"\u002Fblogs\u002F2025-08-18-ollama-desktop-ui","2025-08-18",{"path":47,"date":48},"\u002Fblogs\u002F2025-08-26-xponology-on-old-pc","2025-08-26",{"path":50,"date":51},"\u002Fblogs\u002F2025-08-30-pagecms-opensource","2025-08-30",{"path":53,"date":54},"\u002Fblogs\u002F2025-09-19-chuwi-minibook-x","2025-09-19",{"path":56,"date":57},"\u002Fblogs\u002F2025-10-03-typhoon-ai-n8n","2025-10-03",{"path":59,"date":60},"\u002Fblogs\u002F2025-10-30-3d-printer-bambu-lab-a1","2025-10-30",{"path":62,"date":63},"\u002Fblogs\u002F2025-11-03-dirsearch-uv","2025-11-03",{"path":65,"date":66},"\u002Fblogs\u002F2025-11-06-environment-mac-keychains","2025-11-06",{"path":68,"date":69},"\u002Fblogs\u002F2025-11-09-nanokvm-kvm","2025-11-09",{"path":71,"date":72},"\u002Fblogs\u002F2025-12-28-powerlevel10k-spaceship","2025-12-28",{"path":74,"date":72},"\u002Fblogs\u002F2025-12-28-zshrc-config-folder",{"path":76,"date":77},"\u002Fblogs\u002F2026-01-02-cli-macos-sips","2026-01-02",{"path":79,"date":80},"\u002Fblogs\u002F2026-01-03-2026-finn-mobile","2026-01-03",{"path":82,"date":83},"\u002Fblogs\u002F2026-01-17-zshhistory","2026-01-17",{"path":85,"date":86},"\u002Fblogs\u002F2026-02-07-scrapper","2026-02-07",{"path":88,"date":89},"\u002Fblogs\u002F2026-02-08-glm-4-7","2026-02-08",{"path":91,"date":89},"\u002Fblogs\u002F2026-02-08-kimi-k2-5",{"path":93,"date":89},"\u002Fblogs\u002F2026-02-08-n8n-skills",{"path":95,"date":89},"\u002Fblogs\u002F2026-02-08-nanobot-ai-agent",{"path":97,"date":98},"\u002Fblogs\u002F2026-02-12-glm-5","2026-02-12",{"path":100,"date":101},"\u002Fblogs\u002F2026-03-30-how-to-use-uv","2026-03-30",{"path":103,"date":104},"\u002Fblogs\u002F2026-08-03-docker-dind-vs-dood","2026-08-03",{"path":106,"date":104},"\u002Fblogs\u002F2026-08-03-grafana-alloy-loki",{"path":108,"date":109},"\u002Fblogs\u002F2026-08-07-node-exporter-mtls-basic-auth","2026-08-07",{"path":111,"date":112},"\u002Fblogs\u002F2026-09-16-headroom","2026-09-16",{"path":114,"date":115},"\u002Fblogs\u002F2026-10-17-humanizer-skills","2026-10-17",{"path":117,"date":118},"\u002Fblogs\u002F2026-10-27-claude-code-server-management","2026-10-27",{"id":120,"title":121,"body":122,"date":118,"description":931,"draft":932,"extension":933,"meta":934,"navigation":935,"next":936,"ogTitle":937,"path":117,"pin":932,"prev":936,"recommends":938,"seo":940,"sitemap":941,"stem":942,"tags":943,"updated":936,"__hash__":946},"content\u002Fblogs\u002F2026-10-27-claude-code-server-management.md","ใช้ Claude Code ช่วยดูแล Server ได้ไหม และควรระวังอะไรบ้าง",{"type":123,"value":124,"toc":912},"minimark",[125,129,132,135,138,143,146,149,152,157,160,163,196,211,222,258,269,276,288,304,311,327,338,344,351,380,386,394,405,409,412,419,422,426,433,444,481,491,494,510,517,521,524,532,535,538,545,549,552,567,574,588,591,651,654,659,663,666,672,679,685,699,703,706,725,728,731,735,738,744,758,761,765,768,771,774,777,780,787,790,793,796,799,802,805,808,811,908],[126,127,128],"p",{},"เวลามีปัญหาบน Server งานที่กินเวลามักเป็นการไล่อ่าน Logs ดู config แล้วค่อย ๆ ตัดสาเหตุที่ไม่เกี่ยวข้องออก ถ้ามี AI ช่วยอ่านข้อมูลพวกนี้และเสนอว่าควรตรวจอะไรต่อ ก็น่าจะช่วยเบาแรงได้พอสมควร",[126,130,131],{},"Claude Code ช่วยงานลักษณะนี้ได้ครับ โดยรันบนเครื่องของเราแล้วเรียกคำสั่งผ่าน SSH ไปยัง Server ที่เราดูแล แต่เมื่อคำสั่งไปรันบนเครื่องจริง การแก้ config, restart service หรือลบไฟล์ ก็มีผลกับระบบจริงตามไปด้วย",[126,133,134],{},"ผมจึงอยากให้เริ่มจากการกำหนดขอบเขตให้ชัดว่า AI จะใช้บัญชีไหน ตรวจอะไรได้บ้าง และต้องหยุดรอเราตรงไหน โดยเฉพาะก่อนเปลี่ยนแปลงระบบ",[126,136,137],{},"บทความนี้ใช้ตัวอย่างการเชื่อมต่อ Linux Server ผ่าน SSH และแบ่งสิ่งที่ควรเตรียมออกเป็นสี่เรื่องครับ",[139,140,142],"h2",{"id":141},"_1-ใช้-ssh-key-แทนการส่ง-password-ให้-claude-code","1. ใช้ SSH key แทนการส่ง Password ให้ Claude Code",[126,144,145],{},"ก่อนอื่น ผมไม่แนะนำให้พิมพ์ Password ของ Server ลงใน prompt หรือให้ Claude Code นำ Password ไปใส่ในคำสั่ง",[126,147,148],{},"เหตุผลคือ Claude Code มีการเก็บประวัติการสนทนาและผลลัพธ์จากเครื่องมือไว้ใน session transcript บนเครื่อง เอกสารระบุว่าข้อมูลเหล่านี้เก็บเป็น plaintext และถ้าคำสั่งแสดง credential ออกมา ค่านั้นก็ถูกเขียนลงใน transcript ได้ด้วย ดังนั้น Password ที่เราใส่ในแชตหรือปล่อยให้ปรากฏใน output อาจมีสำเนาค้างอยู่อีกจุดหนึ่ง",[126,150,151],{},"อีกอย่างคือ แม้เรารัน Claude Code บนเครื่องตัวเอง แต่ยังมีการส่งข้อมูลไปให้โมเดลประมวลผลผ่านเครือข่าย จึงควรระวังทั้ง Password, API key, token และข้อมูลผู้ใช้ที่อาจปนอยู่ใน Logs หรือ config ที่ให้ AI อ่าน",[153,154,156],"h3",{"id":155},"เตรียม-ssh-key-ให้เรียบร้อยก่อนเริ่มงาน","เตรียม SSH key ให้เรียบร้อยก่อนเริ่มงาน",[126,158,159],{},"SSH key pair ประกอบด้วยสองส่วน: public key ที่ติดตั้งไว้ฝั่ง Server และ private key ที่เก็บไว้ฝั่งเครื่องที่ใช้เชื่อมต่อ ตัว SSH client ใช้ key คู่นี้สำหรับยืนยันตัวตน เราจึงไม่จำเป็นต้องบอก Password หรือส่งเนื้อหา private key ให้ Claude Code",[126,161,162],{},"ถ้ายังไม่มี key แยกสำหรับงานนี้ สามารถสร้างเองใน Terminal ก่อนเริ่ม Claude Code ได้ เช่น",[164,165,170],"pre",{"className":166,"code":167,"language":168,"meta":169,"style":169},"language-bash shiki shiki-themes material-theme-lighter one-dark-pro github-dark","ssh-keygen -t ed25519 -f ~\u002F.ssh\u002Fid_ed25519_server_review\n","bash","",[171,172,173],"code",{"__ignoreMap":169},[174,175,178,182,186,190,193],"span",{"class":176,"line":177},"line",1,[174,179,181],{"class":180},"sosa_","ssh-keygen",[174,183,185],{"class":184},"sEoV_"," -t",[174,187,189],{"class":188},"sAlJX"," ed25519",[174,191,192],{"class":184}," -f",[174,194,195],{"class":188}," ~\u002F.ssh\u002Fid_ed25519_server_review\n",[126,197,198,199,202,203,206,207,210],{},"ตั้ง passphrase ให้ key แล้วเพิ่มเนื้อหาของไฟล์ ",[171,200,201],{},"id_ed25519_server_review.pub"," ต่อท้าย ",[171,204,205],{},"~\u002F.ssh\u002Fauthorized_keys"," ของบัญชีปลายทาง โดยเก็บ key เดิมที่ยังใช้งานอยู่ไว้ ส่วนไฟล์ที่ไม่มี ",[171,208,209],{},".pub"," คือ private key ให้เก็บไว้บนเครื่องของเรา",[126,212,213,214,217,218,221],{},"จากนั้นตั้งชื่อเครื่องไว้ใน ",[171,215,216],{},"~\u002F.ssh\u002Fconfig"," เพื่อให้คำสั่งอ่านง่ายขึ้น ตัวอย่างนี้สมมติว่ามีบัญชี ",[171,219,220],{},"server-review"," บนเครื่อง Staging อยู่แล้ว",[164,223,227],{"className":224,"code":225,"language":226,"meta":169,"style":169},"language-sshconfig shiki shiki-themes material-theme-lighter one-dark-pro github-dark","Host staging-web\n    HostName staging.example.com\n    User server-review\n    IdentityFile ~\u002F.ssh\u002Fid_ed25519_server_review\n    IdentitiesOnly yes\n","sshconfig",[171,228,229,234,240,246,252],{"__ignoreMap":169},[174,230,231],{"class":176,"line":177},[174,232,233],{},"Host staging-web\n",[174,235,237],{"class":176,"line":236},2,[174,238,239],{},"    HostName staging.example.com\n",[174,241,243],{"class":176,"line":242},3,[174,244,245],{},"    User server-review\n",[174,247,249],{"class":176,"line":248},4,[174,250,251],{},"    IdentityFile ~\u002F.ssh\u002Fid_ed25519_server_review\n",[174,253,255],{"class":176,"line":254},5,[174,256,257],{},"    IdentitiesOnly yes\n",[126,259,260,261,264,265,268],{},"เปลี่ยน hostname และชื่อบัญชีให้ตรงกับเครื่องที่ใช้จริง โดย ",[171,262,263],{},"IdentityFile"," ระบุไฟล์ key และ ",[171,266,267],{},"IdentitiesOnly yes"," ให้ SSH ใช้ identity ที่ตั้งค่าไว้",[126,270,271,272,275],{},"เมื่อมี ",[171,273,274],{},"ssh-agent"," ทำงานอยู่แล้ว ให้โหลด key เข้า agent จาก Terminal ที่จะใช้เปิด Claude Code เช่น",[164,277,279],{"className":166,"code":278,"language":168,"meta":169,"style":169},"ssh-add ~\u002F.ssh\u002Fid_ed25519_server_review\n",[171,280,281],{"__ignoreMap":169},[174,282,283,286],{"class":176,"line":177},[174,284,285],{"class":180},"ssh-add",[174,287,195],{"class":188},[126,289,290,291,299,300,303],{},"กรอก passphrase ใน Terminal ด้วยตัวเอง คำสั่ง ",[292,293,297],"a",{"href":294,"rel":295},"https:\u002F\u002Fman.openbsd.org\u002Fssh-add.1",[296],"nofollow",[171,298,285],{}," จะเพิ่ม key เข้า agent ให้ SSH client ใช้ได้ โดย Claude Code ต้องทำงานใน environment ที่เข้าถึง agent ตัวเดียวกัน (SSH หา agent ผ่านตัวแปร ",[171,301,302],{},"SSH_AUTH_SOCK",")",[126,305,306,307,310],{},"ผมชอบใส่ ",[171,308,309],{},"-t"," ให้ key หมดอายุใน agent เอง จะได้ไม่ค้างไว้ทั้งวันหลังทำงานเสร็จ",[164,312,314],{"className":166,"code":313,"language":168,"meta":169,"style":169},"ssh-add -t 1h ~\u002F.ssh\u002Fid_ed25519_server_review\n",[171,315,316],{"__ignoreMap":169},[174,317,318,320,322,325],{"class":176,"line":177},[174,319,285],{"class":180},[174,321,185],{"class":184},[174,323,324],{"class":188}," 1h",[174,326,195],{"class":188},[126,328,329,330,333,334,337],{},"เช็กว่าใน agent มี key อะไรอยู่บ้างด้วย ",[171,331,332],{},"ssh-add -l"," และถ้าเสร็จงานก่อนหมดเวลา ใช้ ",[171,335,336],{},"ssh-add -d ~\u002F.ssh\u002Fid_ed25519_server_review"," เอาออกได้เลยครับ",[126,339,340,341,343],{},"อีกเรื่องที่ควรรู้คือ agent ไม่ส่ง private key ออกไปไหน แต่ process ไหนที่เข้าถึง ",[171,342,302],{}," ได้ก็ขอให้ agent ใช้ key เซ็นยืนยันตัวตนได้ (รวมถึง Claude Code ด้วย) เพราะงั้นเรื่องสิทธิ์ของบัญชีปลายทางยังสำคัญอยู่",[126,345,346,347,350],{},"จากนั้นลองเชื่อมต่อด้วย ",[171,348,349],{},"ssh staging-web"," เอง ตรวจสอบ host key fingerprint กับข้อมูลที่เชื่อถือได้ และทดสอบคำสั่งด้านล่างให้ผ่านก่อนส่งงานให้ Claude Code",[164,352,354],{"className":166,"code":353,"language":168,"meta":169,"style":169},"ssh -o BatchMode=yes staging-web 'hostname'\n",[171,355,356],{"__ignoreMap":169},[174,357,358,361,364,367,370,374,377],{"class":176,"line":177},[174,359,360],{"class":180},"ssh",[174,362,363],{"class":184}," -o",[174,365,366],{"class":188}," BatchMode=yes",[174,368,369],{"class":188}," staging-web",[174,371,373],{"class":372},"snfNA"," '",[174,375,376],{"class":188},"hostname",[174,378,379],{"class":372},"'\n",[126,381,382,385],{},[171,383,384],{},"BatchMode=yes"," ปิดการถาม Password และการยืนยันแบบโต้ตอบ ถ้าเชื่อมต่อด้วยข้อมูลที่เตรียมไว้ไม่ได้ คำสั่งจะล้มเหลวให้เรากลับไปตรวจเอง ไม่ต้องให้ AI ขอ Password มาใส่แทน",[126,387,388,389,393],{},"อย่างไรก็ตาม ",[390,391,392],"strong",{},"SSH key ไม่ได้จำกัดสิทธิ์ของบัญชีปลายทาง"," ถ้าบัญชีนั้นแก้ไฟล์หรือลบข้อมูลได้ คำสั่งที่ Claude Code รันผ่านบัญชีนั้นก็ทำได้เหมือนกัน",[126,395,396,397,400,401,404],{},"ผมแนะนำให้แยก key และบัญชีสำหรับงานนี้ ให้สิทธิ์เท่าที่จำเป็น และไม่เริ่มด้วย ",[171,398,399],{},"root"," หรือ ",[171,402,403],{},"sudo"," ที่ทำได้ทุกอย่างเพียงเพราะสะดวกกว่า ถ้างานต้องใช้สิทธิ์เพิ่ม ให้พิจารณาเป็นเรื่อง ๆ ไป",[139,406,408],{"id":407},"_2-ใช้หลัก-proof-before-modify-ให้หาหลักฐานก่อนแก้","2. ใช้หลัก Proof before modify ให้หาหลักฐานก่อนแก้",[126,410,411],{},"คำสั่งอย่าง “เว็บเข้าไม่ได้ ช่วยแก้ให้หน่อย” ขอบเขตกว้างมาก เราควรบอกเพิ่มว่าช่วงแรกต้องตรวจสอบอะไร และยังห้ามเปลี่ยนแปลงอะไรบ้าง",[126,413,414,415,418],{},"ผมใช้คำว่า ",[390,416,417],{},"Proof before modify"," เพื่อเรียกกติกานี้: ให้หาหลักฐาน อธิบายสาเหตุ และเสนอแผนก่อนแก้ไข คำนี้เป็นชื่อแนวทางที่ใช้ในบทความ ไม่ใช่ชื่อ permission mode ของ Claude Code",[126,420,421],{},"สิ่งที่อยากได้ก่อนอนุมัติคือคำตอบว่า พบอะไรจากข้อมูลจริง ข้อมูลนั้นสนับสนุนสาเหตุไหน และยังมีอะไรที่ไม่รู้ ถ้าหลักฐานยังไม่พอ ก็ควรบอกว่ายังสรุปไม่ได้ พร้อมเสนอว่าจะตรวจอะไรต่อ",[153,423,425],{"id":424},"เตรียม-plan-mode-ก่อนเริ่มตรวจ","เตรียม Plan Mode ก่อนเริ่มตรวจ",[126,427,428,429,432],{},"Claude Code มี Plan Mode สำหรับสำรวจข้อมูลและเสนอแผนก่อนแก้ไข แต่โหมดนี้ไม่ได้เปลี่ยนบัญชี SSH ให้กลายเป็นบัญชีที่อ่านได้อย่างเดียว และ shell command ระหว่างวางแผนอาจผ่านการอนุมัติจากตัวตรวจอัตโนมัติได้ ถ้าใช้ Auto mode ได้และเปิด ",[171,430,431],{},"useAutoModeDuringPlan"," อยู่ (ค่าเริ่มต้นคือเปิดนะครับ)",[126,434,435,436,439,440,443],{},"ถ้าต้องการตรวจ shell command เองระหว่างวางแผน ให้ตั้งค่านี้เป็น ",[171,437,438],{},"false"," ใน ",[171,441,442],{},".claude\u002Fsettings.local.json"," ของโฟลเดอร์งาน โดยเพิ่มเข้าไปใน JSON เดิม ไม่เขียนทับการตั้งค่าอื่น",[164,445,449],{"className":446,"code":447,"language":448,"meta":169,"style":169},"language-json shiki shiki-themes material-theme-lighter one-dark-pro github-dark","{\n  \"useAutoModeDuringPlan\": false\n}\n","json",[171,450,451,457,476],{"__ignoreMap":169},[174,452,453],{"class":176,"line":177},[174,454,456],{"class":455},"stlKB","{\n",[174,458,459,463,466,469,472],{"class":176,"line":236},[174,460,462],{"class":461},"sObbn","  \"",[174,464,431],{"class":465},"sVeMc",[174,467,468],{"class":461},"\"",[174,470,471],{"class":455},":",[174,473,475],{"class":474},"scCEF"," false\n",[174,477,478],{"class":176,"line":242},[174,479,480],{"class":455},"}\n",[126,482,483,484,400,487,490],{},"สำหรับงานนี้ อย่าเปิดความสามารถ bypass ให้ session ทั้งผ่าน ",[171,485,486],{},"--dangerously-skip-permissions",[171,488,489],{},"--allow-dangerously-skip-permissions"," เพราะแม้เพียงเปิดให้เลือกใช้ bypass ได้ ก็มีผลต่อการตรวจ shell command ใน Plan Mode",[126,492,493],{},"จากโฟลเดอร์งาน เปิด session ใน Plan Mode ได้ด้วยคำสั่ง",[164,495,497],{"className":166,"code":496,"language":168,"meta":169,"style":169},"claude --permission-mode plan\n",[171,498,499],{"__ignoreMap":169},[174,500,501,504,507],{"class":176,"line":177},[174,502,503],{"class":180},"claude",[174,505,506],{"class":184}," --permission-mode",[174,508,509],{"class":188}," plan\n",[126,511,512,513,516],{},"ก่อนส่งงาน ให้เปิด ",[171,514,515],{},"\u002Fpermissions"," ตรวจรายการที่เคยอนุญาตไว้ โดยเฉพาะกฎที่ครอบคลุมคำสั่งผ่าน SSH แบบกว้าง ๆ ซึ่งจะอธิบายต่อในหัวข้อ Manual mode การตั้งค่าฝั่ง Claude Code ยังต้องใช้ควบคู่กับสิทธิ์ของบัญชีบน Server ไม่ควรอาศัยข้อความ “read-only” ใน prompt อย่างเดียว",[153,518,520],{"id":519},"ตัวอย่าง-prompt-สำหรับตรวจหาสาเหตุ","ตัวอย่าง prompt สำหรับตรวจหาสาเหตุ",[126,522,523],{},"จากนั้นกำหนดขอบเขตงานให้ชัด เช่น",[164,525,530],{"className":526,"code":528,"language":529,"meta":169},[527],"language-text","ช่วยตรวจปัญหาเว็บตอบ 502 บน staging-web ผ่าน SSH\n\nช่วงนี้ให้ตรวจสอบแบบ read-only เท่านั้น\nก่อนรัน ให้บอกว่าจะตรวจอะไร ใช้คำสั่งไหน และข้อมูลนั้นช่วยตอบคำถามอะไร\nยืนยัน hostname และบัญชีที่เชื่อมต่อก่อนเริ่มตรวจ\n\nห้ามแก้ไฟล์ ติดตั้งหรืออัปเดต package ลบข้อมูล\nrestart\u002Freload service เปลี่ยน firewall หรือแก้ข้อมูลในฐานข้อมูล\n\nอ่านเฉพาะ Logs และ config ที่เกี่ยวข้อง\nหลีกเลี่ยงการอ่านหรือแสดง Password, token, private key และข้อมูลผู้ใช้\nถ้าต้องอ่านไฟล์ที่อาจมีข้อมูลลับ ให้หยุดและเสนอวิธีเลือกข้อมูลก่อน\n\nเมื่อได้ข้อมูลแล้ว ให้สรุป:\n- หลักฐานที่พบ พร้อมที่มาหรือช่วงเวลา\n- สาเหตุที่เป็นไปได้ และส่วนที่ยังยืนยันไม่ได้\n- สิ่งที่ควรตรวจเพิ่ม\n- แผนแก้ไข ผลกระทบ วิธีตรวจผล และวิธีย้อนกลับ\n\nการอนุมัติให้อ่านข้อมูลไม่ถือเป็นการอนุมัติให้แก้ไข\nหยุดรอผมตรวจแผนก่อน\n","text",[171,531,528],{"__ignoreMap":169},[126,533,534],{},"ตัวอย่างเช่น ถ้าพบว่า Nginx ติดต่อ upstream ไม่ได้ นั่นเป็นข้อมูลให้ตรวจต่อว่าปลายทางคืออะไร มี process รับ connection อยู่หรือไม่ และมีการเปลี่ยน config มาก่อนหน้านั้นหรือเปล่า การเห็น error บรรทัดเดียวอาจยังไม่พอจะบอกได้ว่าควรแก้ตรงไหน",[126,536,537],{},"ผมอยากให้แยก “อาการที่พบ” ออกจาก “สาเหตุที่ยืนยันแล้ว” ให้ชัด เพราะการ restart แล้วเว็บกลับมาได้ ก็ยังไม่ได้อธิบายเสมอไปว่าปัญหาเกิดจากอะไร",[126,539,540,541,544],{},"ถ้าจะใช้กติกาเดิมบ่อย ๆ สามารถเก็บไว้ใน ",[171,542,543],{},"CLAUDE.md"," ของโฟลเดอร์งานได้ แต่ไฟล์นี้เป็นคำแนะนำที่โมเดลอ่าน ไม่ใช่กลไกบังคับสิทธิ์ของระบบ",[139,546,548],{"id":547},"_3-ช่วงแก้ไข-ใช้-manual-mode-และตรวจคำสั่งก่อนอนุมัติ","3. ช่วงแก้ไข ใช้ Manual mode และตรวจคำสั่งก่อนอนุมัติ",[126,550,551],{},"เมื่ออ่านหลักฐานและเห็นด้วยกับแผนแล้ว ค่อยเปลี่ยนเข้าสู่ช่วงแก้ไข",[126,553,554,555,558,559,562,563,566],{},"สำหรับงาน Server ที่ต้องตรวจการเปลี่ยนแปลงเอง ผมแนะนำ ",[390,556,557],{},"Manual mode"," ถ้าออกจาก Plan Mode ให้เลือกตัวเลือกที่อนุมัติการแก้ไขด้วยตนเอง เช่น ",[171,560,561],{},"Yes, manually approve edits"," หรือใช้ ",[171,564,565],{},"Shift+Tab"," สลับโหมดแล้วตรวจชื่อโหมดบนหน้าจอก่อนดำเนินการ",[126,568,569,570,573],{},"ถ้าจะเปิด session ใหม่ใน Manual mode ตั้งแต่แรก ใช้คำสั่งนี้ได้ โดย ",[171,571,572],{},"default"," เป็นชื่อค่าการตั้งค่าของโหมด Manual",[164,575,577],{"className":166,"code":576,"language":168,"meta":169,"style":169},"claude --permission-mode default\n",[171,578,579],{"__ignoreMap":169},[174,580,581,583,585],{"class":176,"line":177},[174,582,503],{"class":180},[174,584,506],{"class":184},[174,586,587],{"class":188}," default\n",[126,589,590],{},"โหมดที่ชื่อคล้ายกันทำงานต่างกัน จึงควรตรวจให้แน่ใจว่าเลือกตรงกับที่ต้องการ",[592,593,594,607],"table",{},[595,596,597],"thead",{},[598,599,600,604],"tr",{},[601,602,603],"th",{},"โหมด",[601,605,606],{},"พฤติกรรมที่ควรรู้",[608,609,610,621,631,641],"tbody",{},[598,611,612,618],{},[613,614,615,616,303],"td",{},"Manual (",[171,617,572],{},[613,619,620],{},"โดยทั่วไปจะถามก่อนแก้ไฟล์หรือรันคำสั่งที่ต้องขอสิทธิ์ แต่คำสั่งอ่านบางชนิดและรายการที่อนุญาตไว้แล้วอาจรันได้",[598,622,623,628],{},[613,624,625],{},[171,626,627],{},"acceptEdits",[613,629,630],{},"อนุมัติการแก้ไฟล์และคำสั่งจัดการไฟล์บางชนิดให้อัตโนมัติ",[598,632,633,638],{},[613,634,635],{},[171,636,637],{},"auto",[613,639,640],{},"ใช้โมเดลอีกตัวช่วยตัดสินใจอนุญาต action หลายประเภทแทนผู้ใช้",[598,642,643,648],{},[613,644,645],{},[171,646,647],{},"bypassPermissions",[613,649,650],{},"ข้ามการตรวจขออนุญาตส่วนใหญ่ เหลือข้อยกเว้นบางอย่างตามระบบ",[126,652,653],{},"พฤติกรรมของแต่ละโหมดอ้างอิงจากเอกสาร Claude Code และอาจเปลี่ยนตามเวอร์ชัน",[126,655,656,657],{},"สำหรับขั้นตอนที่เราตั้งใจจะ review เอง จึงไม่ควรเลือก Auto, auto-accept edits หรือเปิดด้วย ",[171,658,486],{},[153,660,662],{"id":661},"ตรวจ-permission-ที่เคยอนุญาตไว้ด้วย","ตรวจ permission ที่เคยอนุญาตไว้ด้วย",[126,664,665],{},"การเปลี่ยนเป็น Manual ไม่ได้แปลว่าจะถามใหม่ทุกคำสั่ง ให้เปิด",[164,667,670],{"className":668,"code":669,"language":529,"meta":169},[527],"\u002Fpermissions\n",[171,671,669],{"__ignoreMap":169},[126,673,674,675,678],{},"แล้วดูว่ามี allow rule ที่กว้างเกินไปหรือไม่ เช่น ",[171,676,677],{},"Bash(ssh *)"," ซึ่งอาจครอบคลุมคำสั่งผ่าน SSH ได้หลายแบบ รวมถึงคำสั่งที่เปลี่ยนแปลงระบบด้วย เพราะ wildcard จับข้อความส่วนที่ตามมาได้",[126,680,681,682,684],{},"หลีกเลี่ยงการกดอนุญาตถาวรให้ ",[171,683,360],{}," ทั้งชุด ถ้าเราต้องการตรวจคำสั่งปลายทางทีละครั้ง",[126,686,687,688,691,692,695,696,698],{},"ถ้าเปิด sandbox และใช้การอนุมัติ Bash อัตโนมัติอยู่ ให้เลือก Regular permissions ใน ",[171,689,690],{},"\u002Fsandbox"," หรือตั้ง ",[171,693,694],{},"sandbox.autoAllowBashIfSandboxed"," เป็น ",[171,697,438],{}," เพื่อให้คำสั่งผ่านขั้นตอนขออนุญาตตามปกติ การตั้งค่านี้ยังคงใช้ร่วมกับ allow rules ที่มีอยู่ จึงต้องตรวจทั้งสองส่วน",[153,700,702],{"id":701},"review-ทั้ง-command-และสิ่งที่จะเกิดขึ้น","Review ทั้ง Command และสิ่งที่จะเกิดขึ้น",[126,704,705],{},"เวลามีคำขออนุมัติ ผมจะดูมากกว่าแค่ว่าคำสั่งนั้น “ดูคุ้น ๆ” หรือไม่ อย่างน้อยควรตอบคำถามเหล่านี้ได้",[707,708,709,713,716,719,722],"ul",{},[710,711,712],"li",{},"คำสั่งจะรันบนเครื่องไหน เป็น Staging หรือ Production และใช้บัญชีอะไร",[710,714,715],{},"จะแก้ไฟล์ บริการ หรือข้อมูลส่วนไหน ตรงกับแผนที่อ่านไปหรือเปล่า",[710,717,718],{},"มีการเขียนทับ ลบข้อมูล เปลี่ยน permission หรือหยุดบริการหรือไม่",[710,720,721],{},"ถ้ามี script, pipe หรือคำสั่งหลายขั้นต่อกัน แต่ละขั้นทำอะไรบ้าง",[710,723,724],{},"ถ้าไม่สำเร็จ จะตรวจอย่างไร และจะกลับไปใช้ค่าเดิมด้วยวิธีไหน",[126,726,727],{},"ตัวอย่างเช่น “แก้ config ให้ถูกต้อง” ยังไม่ละเอียดพอสำหรับอนุมัติ ควรเห็นว่าจะเปลี่ยนไฟล์ไหน ค่าเดิมเป็นอะไร ค่าใหม่เป็นอะไร และจะตรวจความถูกต้องก่อนนำไปใช้ได้อย่างไร",[126,729,730],{},"อนุมัติให้แก้ไฟล์ก็ไม่ได้แปลว่าอนุมัติให้ restart service หรือ deploy ต่อทันทีด้วย ถ้าสิ่งเหล่านั้นยังไม่ได้อยู่ในขอบเขตที่เราอ่านและตกลงไว้",[153,732,734],{"id":733},"ถ้ายังไม่เข้าใจ-ให้หยุดก่อน","ถ้ายังไม่เข้าใจ ให้หยุดก่อน",[126,736,737],{},"ไม่จำเป็นต้องกด Yes เพียงเพราะ Claude Code อธิบายมาดูมั่นใจครับ ถ้ายังไม่เข้าใจ ให้ปฏิเสธคำสั่งนั้นแล้วถามต่อ เช่น",[164,739,742],{"className":740,"code":741,"language":529,"meta":169},[527],"หยุดก่อน ยังไม่อนุมัติคำสั่งนี้\n\nอธิบายว่าคำสั่งแต่ละส่วนทำอะไร\nรันที่เครื่องไหน กระทบไฟล์หรือบริการใด\nมีโอกาสทำให้บริการหยุด ข้อมูลหาย หรือ SSH กลับเข้าไปไม่ได้หรือไม่\nและจะตรวจผลกับย้อนกลับอย่างไร\n\nถ้ามี script ที่จะนำไปรัน ให้แสดงเนื้อหาเพื่อ review ก่อน\nยังไม่ต้องแก้ไขหรือรันคำสั่งเพิ่มเติม\n",[171,743,741],{"__ignoreMap":169},[126,745,746,747,750,751,753,754,757],{},"ใน CLI กด ",[171,748,749],{},"Esc"," เพื่อขัดจังหวะการทำงานปัจจุบันได้ และถ้าอยู่หน้าขออนุมัติ ",[171,752,749],{}," จะปฏิเสธ action นั้น ส่วน ",[171,755,756],{},"Ctrl+C"," ใช้ interrupt งานที่กำลังรันได้",[126,759,760],{},"แต่การกดหยุดไม่ได้ย้อนสิ่งที่ทำสำเร็จไปแล้ว และงานที่เริ่มบน Server ไปแล้วอาจยังทำงานต่อ จึงควรตรวจสถานะจริงก่อนสั่งซ้ำ",[139,762,764],{"id":763},"_4-claude-code-ยังมีโอกาสผิดพลาดได้","4. Claude Code ยังมีโอกาสผิดพลาดได้",[126,766,767],{},"ต่อให้เตรียม SSH key ใช้ Plan Mode และตรวจคำสั่งใน Manual แล้ว ก็ยังต้องเผื่อกรณีที่ AI เข้าใจระบบผิดครับ",[126,769,770],{},"สิ่งที่ผมจะระวังคือการตีความ Logs จากข้อมูลไม่ครบ เสนอ config ที่ไม่ตรงกับเวอร์ชันที่ติดตั้ง หรือแก้จน service กลับมาทำงานได้ แต่เผลอลดข้อจำกัดด้านความปลอดภัยลงไปด้วย เช่น เสนอให้ขยาย permission เพื่อให้อาการหาย โดยยังไม่ได้อธิบายว่าทำไมสิทธิ์เดิมจึงไม่พอ",[126,772,773],{},"อย่าใช้ความมั่นใจในคำอธิบายเป็นหลักฐานว่าคำสั่งถูกต้อง เอกสารด้านความปลอดภัยของ Claude Code เองก็ระบุให้ผู้ใช้ตรวจ code และคำสั่งก่อนอนุมัติ",[153,775,776],{"id":776},"เตรียมวิธีย้อนกลับก่อนเริ่มแก้",[126,778,779],{},"ก่อนเปลี่ยน config ควรมีสำเนาค่าเดิมและรู้ว่าจะนำกลับมาใช้อย่างไร ถ้าเกี่ยวกับฐานข้อมูล ต้องเตรียม backup และวิธีกู้คืนให้เหมาะกับฐานข้อมูลนั้น ส่วนการแก้ SSH, firewall หรือ network ควรมีช่องทางเข้าเครื่องสำรอง เผื่อการเปลี่ยนแปลงทำให้ connection หลุด",[126,781,782,783,786],{},"อย่าคิดว่ามี ",[171,784,785],{},"\u002Frewind"," แล้วจะย้อน Server กลับได้ทั้งหมด ความสามารถ checkpoint ของ Claude Code มีขอบเขตอยู่ที่ไฟล์ที่ติดตามไว้ ไม่ใช่การย้อนสถานะของ service, database หรือคำสั่งที่รันผ่าน SSH ทั้งเครื่อง",[126,788,789],{},"สำหรับ Production ผมจะเพิ่มการทดสอบบน Staging และกำหนดช่วงเวลาที่รับผลกระทบได้ก่อนลงมือ โดยเฉพาะงานที่เกี่ยวกับข้อมูลหรือการเชื่อมต่อเข้าเครื่อง",[153,791,792],{"id":792},"ตรวจหลังแก้จากระบบจริง",[126,794,795],{},"หลังจบงาน ให้ตรวจทั้งอาการเดิมและผลกระทบข้างเคียง เช่น service ยังทำงานอยู่หรือไม่ request ที่เคยมีปัญหากลับมาใช้งานได้จริงไหม และมี error ใหม่ใน Logs หรือเปล่า",[126,797,798],{},"จากนั้นให้ Claude Code สรุปสิ่งที่ทำไปว่าเปลี่ยนไฟล์ไหน รันคำสั่งอะไร ผลการตรวจเป็นอย่างไร และยังมีอะไรที่ไม่ได้ยืนยัน เก็บข้อมูลนี้ไว้ใช้ตรวจย้อนหลังได้ โดยไม่ใส่ credential ลงในบันทึก",[126,800,801],{},"ถ้าเพิ่งเริ่มใช้ ผมแนะนำให้ลองกับ VM หรือ Server ใน Homelab ที่กู้คืนได้ก่อน เลือกงานเล็ก ๆ อย่างอ่าน Logs และอธิบาย config แล้วค่อยให้มันลงมือแก้เมื่อเราเข้าใจวิธีตรวจงานของมันมากขึ้น",[126,803,804],{},"สำหรับผม Claude Code น่าใช้เป็นผู้ช่วยไล่ปัญหาและเตรียมการแก้ไข ส่วนจังหวะที่จะเปลี่ยนระบบจริง ควรเป็นจุดที่เราอ่านหลักฐาน เข้าใจคำสั่ง และพร้อมรับผลของการเปลี่ยนแปลงนั้นแล้ว",[139,806,807],{"id":807},"แหล่งอ้างอิง",[126,809,810],{},"ตรวจสอบเอกสารเมื่อ 27 ตุลาคม 2026",[812,813,814,821,828,835,852,859,866,873,880,887,894,901],"ol",{},[710,815,816],{},[292,817,820],{"href":818,"rel":819},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fclaude-directory#plaintext-storage",[296],"Claude Code — Explore the .claude directory: Plaintext storage",[710,822,823],{},[292,824,827],{"href":825,"rel":826},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fdata-usage",[296],"Claude Code — Data usage",[710,829,830],{},[292,831,834],{"href":832,"rel":833},"https:\u002F\u002Fubuntu.com\u002Fserver\u002Fdocs\u002Fhow-to\u002Fsecurity\u002Fopenssh-server\u002F#ssh-keys",[296],"Ubuntu Server — OpenSSH server: SSH keys",[710,836,837,838,843,844,847,848],{},"OpenSSH — ",[292,839,842],{"href":840,"rel":841},"https:\u002F\u002Fman.openbsd.org\u002Fssh_config",[296],"ssh_config",", ",[292,845,285],{"href":294,"rel":846},[296]," และ ",[292,849,274],{"href":850,"rel":851},"https:\u002F\u002Fman.openbsd.org\u002Fssh-agent.1",[296],[710,853,854],{},[292,855,858],{"href":856,"rel":857},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fpermission-modes",[296],"Claude Code — Choose a permission mode",[710,860,861],{},[292,862,865],{"href":863,"rel":864},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fsettings",[296],"Claude Code — Settings files and precedence",[710,867,868],{},[292,869,872],{"href":870,"rel":871},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fmemory",[296],"Claude Code — How Claude remembers your project",[710,874,875],{},[292,876,879],{"href":877,"rel":878},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fpermissions",[296],"Claude Code — Configure permissions",[710,881,882],{},[292,883,886],{"href":884,"rel":885},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Finteractive-mode",[296],"Claude Code — Interactive mode",[710,888,889],{},[292,890,893],{"href":891,"rel":892},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fsecurity",[296],"Claude Code — Security",[710,895,896],{},[292,897,900],{"href":898,"rel":899},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fcheckpointing",[296],"Claude Code — Checkpointing",[710,902,903],{},[292,904,907],{"href":905,"rel":906},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fsandboxing",[296],"Claude Code — Configure the sandboxed Bash tool",[909,910,911],"style",{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sObbn, html code.shiki .sObbn{--shiki-light:#39ADB5;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sVeMc, html code.shiki .sVeMc{--shiki-light:#9C3EDA;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .scCEF, html code.shiki .scCEF{--shiki-light:#39ADB5;--shiki-default:#D19A66;--shiki-dark:#79B8FF}",{"title":169,"searchDepth":236,"depth":236,"links":913},[914,917,921,926,930],{"id":141,"depth":236,"text":142,"children":915},[916],{"id":155,"depth":242,"text":156},{"id":407,"depth":236,"text":408,"children":918},[919,920],{"id":424,"depth":242,"text":425},{"id":519,"depth":242,"text":520},{"id":547,"depth":236,"text":548,"children":922},[923,924,925],{"id":661,"depth":242,"text":662},{"id":701,"depth":242,"text":702},{"id":733,"depth":242,"text":734},{"id":763,"depth":236,"text":764,"children":927},[928,929],{"id":776,"depth":242,"text":776},{"id":792,"depth":242,"text":792},{"id":807,"depth":236,"text":807},"ใช้ Claude Code ช่วยอ่าน Logs และตรวจปัญหา Server ผ่าน SSH โดยไม่ส่ง Password ให้ AI พร้อมแนวทางหาหลักฐานก่อนแก้ ใช้ Manual mode และตรวจคำสั่งก่อนอนุมัติ",false,"md",{},true,null,"Using Claude Code on Servers Safely",[939],"2026-10-17-humanizer-skills.md",{"title":121,"description":931},{"loc":117,"lastmod":118},"blogs\u002F2026-10-27-claude-code-server-management",[944,945],"AI","Homelab","RFJV_S-YN-he1_scY81Ys5cQageIPMJJwYbD5fuqeY4",[948],{"id":949,"title":950,"body":951,"date":115,"description":1397,"draft":932,"extension":933,"meta":1398,"navigation":935,"next":936,"ogTitle":950,"path":114,"pin":932,"prev":936,"recommends":1399,"seo":1402,"sitemap":1403,"stem":1404,"tags":1405,"updated":1406,"__hash__":1407},"content\u002Fblogs\u002F2026-10-17-humanizer-skills.md","เปลี่ยนข้อความสไตล์ AI ให้เป็นธรรมชาติมากขึ้นด้วย Humanizer Skill",{"type":123,"value":952,"toc":1386},[953,956,959,970,974,977,980,1003,1006,1020,1023,1027,1030,1036,1039,1044,1047,1050,1055,1057,1062,1065,1069,1072,1078,1081,1109,1125,1129,1132,1135,1140,1147,1150,1153,1158,1163,1168,1171,1174,1179,1182,1186,1189,1192,1215,1218,1244,1247,1250,1253,1258,1261,1266,1269,1273,1276,1279,1282,1289,1292,1295,1298,1301,1304,1327,1330,1333,1336,1339,1342,1345,1350,1355,1360,1365,1368,1371,1374,1377,1380,1383],[126,954,955],{},"ช่วงหลังผมใช้ AI ช่วยเขียนและปรับข้อความค่อนข้างบ่อย ทั้งบทความ เอกสาร และข้อความอธิบายต่าง ๆ ปัญหาที่เจอคือ ถึงเนื้อหาจะถูกต้อง แต่บางครั้งอ่านแล้วก็ยังรู้สึกได้ทันทีว่า \"อันนี้ AI เขียน\"",[126,957,958],{},"ไม่ได้หมายความว่า AI เขียนไม่ดีนะครับ แต่รูปแบบการเขียนของโมเดลมักมีนิสัยบางอย่างที่โผล่มาซ้ำ ๆ เช่น ชอบเกริ่นก่อนเข้าประเด็น ใช้คำใหญ่เกินความจำเป็น หรือพยายามจัดทุกอย่างให้ดูเป็นระเบียบมากจนผิดธรรมชาติ",[126,960,961,962,969],{},"ผมเลยลองใช้ Skill ชื่อ ",[292,963,966],{"href":964,"rel":965},"https:\u002F\u002Fgithub.com\u002Fblader\u002Fhumanizer",[296],[171,967,968],{},"humanizer"," เพื่อช่วยตรวจและปรับข้อความพวกนี้อีกชั้นหนึ่ง (ใช้กับภาษาไทยก็ได้ด้วยนะ)",[139,971,973],{"id":972},"humanizer-ทำอะไร","Humanizer ทำอะไร",[126,975,976],{},"Humanizer เป็น Skill ที่เอาไว้ตรวจรูปแบบการเขียนที่มักพบในข้อความจาก AI แล้วเขียนใหม่ให้อ่านเป็นธรรมชาติมากขึ้น โดยพยายามรักษาความหมายเดิมไว้",[126,978,979],{},"หลักการสำคัญคือ ไม่ได้พยายามทำให้ข้อความ \"ดูเหมือนมนุษย์แบบหลอก detector (aka: AI Slop Detector)\" แต่เน้นแก้ปัญหาด้านสำนวนและโครงสร้างการเขียน เช่น",[707,981,982,985,988,991,994,997,1000],{},[710,983,984],{},"ตัดคำเกริ่นที่ไม่จำเป็น",[710,986,987],{},"ลดประโยคที่พูดซ้ำความหมายเดิม",[710,989,990],{},"แก้โครงสร้างแบบ \"ไม่ใช่แค่ X แต่ยัง Y\"",[710,992,993],{},"ลดคำที่ฟังดูใหญ่เกินเนื้อหา",[710,995,996],{},"ลดการใช้คำอย่าง \"สำคัญ\", \"ทรงพลัง\", \"โดดเด่น\", \"ยกระดับ\" ถ้าไม่ได้เพิ่มข้อมูลจริง",[710,998,999],{},"ทำให้ประโยคสั้นลงเมื่อข้อความเดิมวกไปมา",[710,1001,1002],{},"ตัดข้อความตกค้างจากสไตล์ chatbot เช่น \"หวังว่าจะช่วยได้นะครับ\" หรือ \"ถ้าต้องการสามารถ...\"",[126,1004,1005],{},"ตัว Skill เองกำหนดขั้นตอนการทำงานไว้ประมาณนี้",[812,1007,1008,1011,1014,1017],{},[710,1009,1010],{},"อ่านข้อความทั้งหมดก่อน",[710,1012,1013],{},"หา pattern ที่ดูเป็น AI",[710,1015,1016],{},"เขียนข้อความใหม่โดยเก็บข้อมูลเดิม",[710,1018,1019],{},"ตรวจอีกครั้งว่าไม่ได้เพิ่มหรือลดข้อเท็จจริง",[126,1021,1022],{},"จุดที่ผมชอบคือมันไม่ได้แก้แบบค้นหาคำแล้วแทนคำตรง ๆ แต่พยายามมองทั้งประโยคและย่อหน้า",[139,1024,1026],{"id":1025},"ตัวอย่างง่าย-ๆ","ตัวอย่างง่าย ๆ",[126,1028,1029],{},"ข้อความก่อนปรับ:",[1031,1032,1033],"blockquote",{},[126,1034,1035],{},"ระบบนี้ไม่ได้เป็นเพียงเครื่องมือสำหรับตรวจสอบเว็บไซต์ แต่ยังเป็นโซลูชันที่ช่วยยกระดับความปลอดภัยในหลายมิติ ไม่ว่าจะเป็น HTTP Security Headers, SSL\u002FTLS และความพร้อมด้าน PQC ซึ่งทั้งหมดนี้สะท้อนให้เห็นถึงความสำคัญของการเตรียมพร้อมรับมือกับภัยคุกคามทางไซเบอร์ที่เปลี่ยนแปลงอยู่ตลอดเวลา",[126,1037,1038],{},"หลังปรับ:",[1031,1040,1041],{},[126,1042,1043],{},"ระบบนี้ใช้ตรวจ HTTP Security Headers, SSL\u002FTLS และความพร้อมด้าน PQC ของเว็บไซต์ เพื่อดูว่ามีจุดไหนที่ควรปรับปรุงด้านความปลอดภัยบ้าง",[126,1045,1046],{},"ข้อมูลที่ต้องการสื่อยังเหมือนเดิม แต่ข้อความสั้นลง และไม่มีส่วนที่พยายามทำให้เรื่องธรรมดาฟังดูใหญ่เกินไป อีกตัวอย่างหนึ่ง",[126,1048,1049],{},"ก่อนปรับ:",[1031,1051,1052],{},[126,1053,1054],{},"สิ่งสำคัญที่ต้องเข้าใจคือ การอัปเดต dependency ไม่ได้เป็นเพียงเรื่องของการเปลี่ยนเวอร์ชันให้ใหม่ขึ้นเท่านั้น แต่ยังเกี่ยวข้องกับความปลอดภัย ประสิทธิภาพ และความเข้ากันได้ของระบบอีกด้วย ดังนั้น การวางแผนและทดสอบอย่างรอบคอบจึงถือเป็นหัวใจสำคัญของกระบวนการนี้",[126,1056,1038],{},[1031,1058,1059],{},[126,1060,1061],{},"การอัปเดต dependency มีผลทั้งเรื่องความปลอดภัย ประสิทธิภาพ และความเข้ากันได้ของระบบ จึงควรวางแผนและทดสอบก่อนนำขึ้นใช้งานจริง",[126,1063,1064],{},"พอตัดประโยคเกริ่นและคำขยายออก ข้อความก็เข้าเรื่องเร็วขึ้นเยอะ และ ลดกลิ่นของ AI Slop ได้ด้วย :3",[139,1066,1068],{"id":1067},"ติดตั้งและเรียกใช้ใน-claude-code","ติดตั้งและเรียกใช้ใน Claude Code",[126,1070,1071],{},"ติดตั้งผ่าน Plugin Marketplace ได้เลย พิมพ์สองคำสั่งนี้ใน Claude Code",[164,1073,1076],{"className":1074,"code":1075,"language":529,"meta":169},[527],"\u002Fplugin marketplace add blader\u002Fhumanizer\n\u002Fplugin install humanizer@humanizer\n",[171,1077,1075],{"__ignoreMap":169},[126,1079,1080],{},"วิธีนี้ต้องใช้ Claude Code 2.1.142 ขึ้นไป ถ้าเวอร์ชันเก่ากว่านั้นก็ลงผ่าน Skills CLI แทน",[164,1082,1084],{"className":166,"code":1083,"language":168,"meta":169,"style":169},"npx skills add blader\u002Fhumanizer --global --agent claude-code\n",[171,1085,1086],{"__ignoreMap":169},[174,1087,1088,1091,1094,1097,1100,1103,1106],{"class":176,"line":177},[174,1089,1090],{"class":180},"npx",[174,1092,1093],{"class":188}," skills",[174,1095,1096],{"class":188}," add",[174,1098,1099],{"class":188}," blader\u002Fhumanizer",[174,1101,1102],{"class":184}," --global",[174,1104,1105],{"class":184}," --agent",[174,1107,1108],{"class":188}," claude-code\n",[126,1110,1111,1112,1115,1116,1119,1120],{},"ลงเสร็จแล้วเรียกด้วย ",[171,1113,1114],{},"\u002Fhumanizer:humanizer"," (ถ้าลงผ่าน Skills CLI จะเป็น ",[171,1117,1118],{},"\u002Fhumanizer",") แล้ววางข้อความต่อท้าย หรือจะพิมพ์บอกตรง ๆ ว่า \"humanize ข้อความนี้ให้หน่อย\" ก็ได้เหมือนกัน ใครใช้ Codex หรือ Agent ตัวอื่น ดูคำสั่งติดตั้งได้ใน ",[292,1121,1124],{"href":1122,"rel":1123},"https:\u002F\u002Fgithub.com\u002Fblader\u002Fhumanizer#installation",[296],"README ของ repo",[139,1126,1128],{"id":1127},"pattern-ที่-humanizer-มองหา","Pattern ที่ Humanizer มองหา",[126,1130,1131],{},"ใน Skill มีรายการ pattern อยู่หลายข้อ แต่บางอันเจอบ่อยมากเวลาใช้กับภาษาไทย",[126,1133,1134],{},"อย่างแรกคือประโยคแบบ",[1031,1136,1137],{},[126,1138,1139],{},"ไม่ได้เป็นเพียง X แต่ยังเป็น Y",[126,1141,1142,1143,1146],{},"ภาษาอังกฤษมักเป็นรูปแบบ ",[171,1144,1145],{},"not just X, but Y"," ซึ่งโมเดลชอบใช้เวลาต้องการเพิ่มน้ำหนักให้ประโยค",[126,1148,1149],{},"หลายครั้งจริง ๆ แล้วพูด Y ไปตรง ๆ ก็พอ",[126,1151,1152],{},"อีกแบบคือการเกริ่นก่อนเข้าประเด็น เช่น",[1031,1154,1155],{},[126,1156,1157],{},"สิ่งสำคัญที่ต้องเข้าใจคือ...",[1031,1159,1160],{},[126,1161,1162],{},"ประเด็นสำคัญคือ...",[1031,1164,1165],{},[126,1166,1167],{},"สิ่งที่น่าสนใจคือ...",[126,1169,1170],{},"ถ้าประโยคถัดไปมีข้อมูลอยู่แล้ว ส่วนเกริ่นมักตัดออกได้เลย",[126,1172,1173],{},"อีก pattern ที่เห็นบ่อยคือการปิดย่อหน้าด้วยประโยคสรุปซ้ำ เช่น",[1031,1175,1176],{},[126,1177,1178],{},"นี่จึงเป็นเหตุผลว่าทำไมเรื่องนี้ถึงสำคัญ",[126,1180,1181],{},"ถ้าย่อหน้าก่อนหน้าอธิบายเหตุผลครบแล้ว ประโยคนี้ไม่ได้เพิ่มข้อมูลอะไร",[139,1183,1185],{"id":1184},"คำบางคำไม่ได้ผิด-แต่-ai-ใช้บ่อยเกินไป","คำบางคำไม่ได้ผิด แต่ AI ใช้บ่อยเกินไป",[126,1187,1188],{},"อีกส่วนหนึ่งของ Humanizer คือการมองหาคำที่ AI มักหยิบมาใช้ซ้ำ ๆ",[126,1190,1191],{},"ตัวอย่างในภาษาอังกฤษ เช่น",[126,1193,1194,843,1197,843,1200,843,1203,843,1206,843,1209,843,1212],{},[171,1195,1196],{},"crucial",[171,1198,1199],{},"robust",[171,1201,1202],{},"pivotal",[171,1204,1205],{},"showcase",[171,1207,1208],{},"landscape",[171,1210,1211],{},"highlight",[171,1213,1214],{},"enhance",[126,1216,1217],{},"ถ้าแปลเป็นภาษาไทยก็จะได้อารมณ์ประมาณ",[707,1219,1220,1223,1226,1229,1232,1235,1238,1241],{},[710,1221,1222],{},"สำคัญอย่างยิ่ง",[710,1224,1225],{},"แข็งแกร่ง",[710,1227,1228],{},"มีบทบาทสำคัญ",[710,1230,1231],{},"ยกระดับ",[710,1233,1234],{},"สะท้อนให้เห็น",[710,1236,1237],{},"ภูมิทัศน์",[710,1239,1240],{},"แสดงให้เห็นถึง",[710,1242,1243],{},"โดดเด่น",[126,1245,1246],{},"คำพวกนี้ไม่ได้ผิด และบางบริบทก็เหมาะที่จะใช้",[126,1248,1249],{},"ปัญหาเกิดตอนที่ข้อความหนึ่งย่อหน้ามีคำลักษณะนี้เต็มไปหมด ทั้งที่เนื้อหาจริง ๆ ค่อนข้างธรรมดา",[126,1251,1252],{},"เช่น",[1031,1254,1255],{},[126,1256,1257],{},"Docker เป็นเครื่องมือที่ทรงพลังและมีบทบาทสำคัญในการยกระดับ workflow ของทีมพัฒนา",[126,1259,1260],{},"อาจเขียนง่าย ๆ ว่า",[1031,1262,1263],{},[126,1264,1265],{},"Docker ช่วยให้ทีมพัฒนาใช้ environment ใกล้เคียงกันมากขึ้น",[126,1267,1268],{},"ประโยคหลังบอกสิ่งที่ Docker ทำจริง ๆ ชัดกว่า",[139,1270,1272],{"id":1271},"humanizer-ไม่ใช่-ai-detector","Humanizer ไม่ใช่ AI Detector",[126,1274,1275],{},"จุดนี้สำคัญ เพราะ Humanizer ไม่ได้เอาไว้ตรวจว่าข้อความถูกเขียนโดย AI หรือมนุษย์",[126,1277,1278],{},"มันแค่ใช้รายการ pattern ที่มักพบในข้อความจาก LLM แล้วเอามาใช้เป็นแนวทางในการ edit",[126,1280,1281],{},"คนก็สามารถเขียนแบบเดียวกันได้ และ AI ก็สามารถเขียนโดยไม่มี pattern พวกนี้ได้เหมือนกัน",[126,1283,1284,1285,1288],{},"ดังนั้นถ้าเจอคำว่า ",[171,1286,1287],{},"not just X but Y"," หรือเห็น em dash ก็ไม่ได้แปลว่าข้อความนั้นมาจาก AI",[126,1290,1291],{},"มอง Humanizer เป็น style editor จะตรงกว่า",[139,1293,1294],{"id":1294},"สิ่งที่ควรระวังเวลาใช้กับภาษาไทย",[126,1296,1297],{},"Skill นี้ถูกเขียนขึ้นโดยอ้างอิง pattern ภาษาอังกฤษเป็นหลัก ดังนั้นบางกฎเอามาใช้กับภาษาไทยตรง ๆ ไม่ได้ทั้งหมด",[126,1299,1300],{},"ตัวอย่างเช่นเรื่อง em dash ซึ่งแทบไม่ได้เป็นปัญหาในภาษาไทยอยู่แล้ว",[126,1302,1303],{},"ขณะเดียวกันภาษาไทยมี pattern ของตัวเองที่ควรเพิ่มเข้าไป เช่น",[707,1305,1306,1309,1312,1315,1318,1321,1324],{},[710,1307,1308],{},"การใช้ \"โดย...\" หลายประโยคติดกัน",[710,1310,1311],{},"\"ซึ่ง...\" ยาวมากจนจำไม่ได้ว่าขยายประโยคไหน",[710,1313,1314],{},"\"เพื่อให้สามารถ...\" ทั้งที่เขียน \"เพื่อ...\" ได้เลย",[710,1316,1317],{},"\"มีการดำเนินการ...\" แทนคำกริยาง่าย ๆ",[710,1319,1320],{},"\"ในส่วนของ...\" ที่ใช้เปิดแทบทุกย่อหน้า",[710,1322,1323],{},"\"ทั้งนี้...\" และ \"อย่างไรก็ตาม...\" บ่อยเกินไป",[710,1325,1326],{},"คำทับศัพท์ที่เป็นทางการเกินบริบท",[126,1328,1329],{},"ถ้าจะใช้ Humanizer กับงานภาษาไทยจริงจัง ผมคิดว่าควรปรับ Skill เพิ่มอีกชุดหนึ่งสำหรับภาษาไทยโดยเฉพาะ",[139,1331,1332],{"id":1332},"ใช้กับงานแบบไหนได้บ้าง",[126,1334,1335],{},"ผมว่า Humanizer เหมาะกับงานที่เราใช้ AI ช่วยร่างก่อน แล้วต้องการเก็บงานอีกครั้ง เช่น",[126,1337,1338],{},"บทความ technical, FAQ, documentation, README, รายละเอียดสินค้า, หน้าเว็บไซต์ หรือข้อความอธิบายในระบบ",[126,1340,1341],{},"โดยเฉพาะงานที่ข้อมูลถูกแล้ว แต่ยังมีความรู้สึกว่า \"อ่านแล้วเป็น ChatGPT\"",[126,1343,1344],{},"แทนที่จะต้องไล่บอก AI ทุกครั้งว่า",[1031,1346,1347],{},[126,1348,1349],{},"เขียนให้ธรรมชาติขึ้น",[1031,1351,1352],{},[126,1353,1354],{},"อย่าใช้คำเว่อร์",[1031,1356,1357],{},[126,1358,1359],{},"ไม่ต้องเกริ่น",[1031,1361,1362],{},[126,1363,1364],{},"ไม่ต้องสรุปซ้ำ",[126,1366,1367],{},"ก็เอากฎพวกนี้รวมไว้ใน Skill แล้วเรียกใช้ซ้ำได้",[139,1369,1370],{"id":1370},"สรุป",[126,1372,1373],{},"Humanizer ไม่ได้ทำให้ AI กลายเป็นนักเขียนมนุษย์โดยอัตโนมัติ และไม่ได้รับประกันว่าข้อความจะไม่มีใครเดาได้ว่าใช้ AI ช่วยเขียน",[126,1375,1376],{},"สิ่งที่มันทำได้ดีคือช่วยจับนิสัยการเขียนบางอย่างที่โมเดลชอบใช้ซ้ำ แล้วบังคับให้กลับมาเขียนตรงประเด็นขึ้น",[126,1378,1379],{},"สำหรับผม วิธีใช้ที่เหมาะที่สุดคือให้ AI ช่วยร่างเนื้อหาก่อน จากนั้นใช้ Humanizer เป็นรอบ edit อีกครั้ง แล้วคนอ่านและแก้รอบสุดท้ายเอง",[126,1381,1382],{},"แบบนี้ได้ทั้งความเร็วจาก AI และยังรักษาสำนวนของคนเขียนไว้ได้มากกว่าเอาข้อความจาก AI ไปใช้ตรง ๆ",[909,1384,1385],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":169,"searchDepth":236,"depth":236,"links":1387},[1388,1389,1390,1391,1392,1393,1394,1395,1396],{"id":972,"depth":236,"text":973},{"id":1025,"depth":236,"text":1026},{"id":1067,"depth":236,"text":1068},{"id":1127,"depth":236,"text":1128},{"id":1184,"depth":236,"text":1185},{"id":1271,"depth":236,"text":1272},{"id":1294,"depth":236,"text":1294},{"id":1332,"depth":236,"text":1332},{"id":1370,"depth":236,"text":1370},"ลองใช้ Humanizer Skill ใน Claude Code ตรวจและปรับข้อความที่อ่านแล้วดูเป็น AI ตัดคำเกริ่น ประโยคซ้ำ และคำฟุ่มเฟือย โดยยังเก็บความหมายเดิมไว้ พร้อมวิธีติดตั้ง",{},[1400,1401],"2026-02-08-n8n-skills.md","2026-09-16-headroom.md",{"title":950,"description":1397},{"loc":114,"lastmod":115},"blogs\u002F2026-10-17-humanizer-skills",[944],"2026-10-24","kbGLXEzkUxpWwKG-M3Bk4YSi0r83_RSLRjHtWhKD4iA",[1409,3200,3654,3845,4646,5430,5660,5900,6029,6513,6629,6853,6940,7035,7119,7177,7280,7397,7452,9238,10937,11964],{"id":1410,"title":1411,"body":1412,"date":6,"description":3187,"draft":932,"extension":933,"meta":3188,"navigation":935,"next":936,"ogTitle":1411,"path":5,"pin":932,"prev":936,"recommends":3189,"seo":3193,"sitemap":3194,"stem":3195,"tags":3196,"updated":1406,"__hash__":3199},"content\u002Fblogs\u002F2024-01-14-setup-ubuntu-server.md","ตั้งค่า Ubuntu Server หลังติดตั้ง สำหรับ Homelab",{"type":123,"value":1413,"toc":3159},[1414,1421,1424,1428,1434,1437,1450,1460,1468,1471,1474,1477,1501,1520,1523,1563,1566,1578,1586,1589,1592,1618,1625,1641,1662,1666,1673,1696,1715,1719,1726,1749,1760,1775,1778,1784,1792,1796,1799,1818,1828,1840,1850,1917,1920,1933,1937,1940,1959,1963,1966,2026,2029,2138,2142,2198,2201,2233,2243,2247,2253,2279,2282,2305,2308,2321,2325,2344,2348,2355,2364,2368,2371,2395,2402,2427,2430,2450,2462,2466,2475,2478,2509,2512,2524,2535,2539,2542,2549,2572,2579,2601,2614,2618,2621,2625,2659,2666,2678,2686,2690,2700,2703,2798,2801,2814,2829,2860,2863,2875,2879,2888,2934,2945,2954,2957,2967,2970,2979,2982,2986,2989,2992,3006,3009,3035,3043,3050,3074,3085,3088,3156],[126,1415,1416,1417,1420],{},"หลังติดตั้ง Ubuntu Server ควรเริ่มจากอัปเดตแพ็กเกจ ตั้งเวลาและชื่อเครื่องให้ถูกต้อง แล้วตรวจการเชื่อมต่อ SSH ก่อนเปิด Firewall จากนั้นจึงติดตั้งเครื่องมือให้ตรงกับงานที่จะใช้เครื่องนั้นทำ บทความนี้รวมขั้นตอนเหล่านั้นสำหรับ ",[390,1418,1419],{},"Ubuntu Server 24.04 และ 22.04 LTS บน Homelab"," พร้อมคำสั่งติดตั้ง Docker Engine, Docker Compose และ Node.js ส่วน Helm, Zsh และ Powerlevel10k เลือกติดตั้งเพิ่มได้ตามการใช้งาน",[126,1422,1423],{},"ปรับปรุงเนื้อหา: 24 ตุลาคม 2026",[139,1425,1427],{"id":1426},"ก่อนเริ่มตั้งค่า-ubuntu-server","ก่อนเริ่มตั้งค่า Ubuntu Server",[126,1429,1430,1431,1433],{},"เตรียมบัญชีผู้ใช้ที่เรียก ",[171,1432,403],{}," ได้ และตรวจว่าเครื่องเชื่อมต่ออินเทอร์เน็ตได้ หากตั้งค่าผ่าน SSH ควรมีวิธีเข้า Console ของเครื่องหรือ VM ไว้ด้วย โดยเฉพาะก่อนแก้ Firewall หรือ Network",[126,1435,1436],{},"ตรวจเวอร์ชัน Ubuntu ที่ใช้อยู่:",[164,1438,1440],{"className":166,"code":1439,"language":168,"meta":169,"style":169},"cat \u002Fetc\u002Fos-release\n",[171,1441,1442],{"__ignoreMap":169},[174,1443,1444,1447],{"class":176,"line":177},[174,1445,1446],{"class":180},"cat",[174,1448,1449],{"class":188}," \u002Fetc\u002Fos-release\n",[126,1451,1452,1453,400,1456,1459],{},"ดูค่า ",[171,1454,1455],{},"PRETTY_NAME",[171,1457,1458],{},"VERSION_ID"," เพื่อเลือกคำสั่งให้ตรงกับระบบ",[126,1461,1462,1463],{},"Ubuntu 20.04 สิ้นสุดการสนับสนุนความปลอดภัยมาตรฐานแล้วตั้งแต่พฤษภาคม 2025 หากยังใช้อยู่ ควรวางแผนอัปเกรดหรือพิจารณา Ubuntu Pro เพื่อรับ ESM ตามขอบเขตที่รองรับ ดูรายละเอียดใน ",[292,1464,1467],{"href":1465,"rel":1466},"https:\u002F\u002Fubuntu.com\u002Fabout\u002Frelease-cycle",[296],"ตารางการสนับสนุน Ubuntu",[139,1469,1470],{"id":1470},"ตั้งค่าพื้นฐานหลังติดตั้ง",[153,1472,1473],{"id":1473},"อัปเดตแพ็กเกจ",[126,1475,1476],{},"อัปเดตรายการแพ็กเกจ แล้วติดตั้งเวอร์ชันที่มีใน Repository ที่เครื่องใช้อยู่:",[164,1478,1480],{"className":166,"code":1479,"language":168,"meta":169,"style":169},"sudo apt update\nsudo apt upgrade\n",[171,1481,1482,1492],{"__ignoreMap":169},[174,1483,1484,1486,1489],{"class":176,"line":177},[174,1485,403],{"class":180},[174,1487,1488],{"class":188}," apt",[174,1490,1491],{"class":188}," update\n",[174,1493,1494,1496,1498],{"class":176,"line":236},[174,1495,403],{"class":180},[174,1497,1488],{"class":188},[174,1499,1500],{"class":188}," upgrade\n",[126,1502,1503,1506,1507,1510,1511,1514,1515],{},[171,1504,1505],{},"apt update"," ดึงรายการแพ็กเกจ ส่วน ",[171,1508,1509],{},"apt upgrade"," อัปเกรดแพ็กเกจที่ติดตั้งแล้ว ตรวจรายการที่ APT แสดงก่อนยืนยันด้วย ",[171,1512,1513],{},"y"," ขั้นตอนนี้ไม่ได้เปลี่ยนรุ่น Ubuntu เช่น จาก 22.04 เป็น 24.04 รายละเอียดอยู่ใน ",[292,1516,1519],{"href":1517,"rel":1518},"https:\u002F\u002Fubuntu.com\u002Fserver\u002Fdocs\u002Fhow-to\u002Fsoftware\u002Fpackage-management\u002F",[296],"คู่มือจัดการแพ็กเกจของ Ubuntu",[126,1521,1522],{},"หลังอัปเดต ตรวจว่าระบบแจ้งให้รีสตาร์ตหรือไม่:",[164,1524,1526],{"className":166,"code":1525,"language":168,"meta":169,"style":169},"if [ -f \u002Fvar\u002Frun\u002Freboot-required ]; then\n  cat \u002Fvar\u002Frun\u002Freboot-required\nfi\n",[171,1527,1528,1550,1558],{"__ignoreMap":169},[174,1529,1530,1534,1537,1540,1544,1547],{"class":176,"line":177},[174,1531,1533],{"class":1532},"s36IK","if",[174,1535,1536],{"class":455}," [",[174,1538,192],{"class":1539},"sMTEB",[174,1541,1543],{"class":1542},"sZDfs"," \u002Fvar\u002Frun\u002Freboot-required ",[174,1545,1546],{"class":455},"];",[174,1548,1549],{"class":1532}," then\n",[174,1551,1552,1555],{"class":176,"line":236},[174,1553,1554],{"class":180},"  cat",[174,1556,1557],{"class":188}," \u002Fvar\u002Frun\u002Freboot-required\n",[174,1559,1560],{"class":176,"line":242},[174,1561,1562],{"class":1532},"fi\n",[126,1564,1565],{},"หากมีข้อความแจ้งและพร้อมให้เครื่องหยุดทำงานชั่วคราว ให้รีสตาร์ต:",[164,1567,1569],{"className":166,"code":1568,"language":168,"meta":169,"style":169},"sudo reboot\n",[171,1570,1571],{"__ignoreMap":169},[174,1572,1573,1575],{"class":176,"line":177},[174,1574,403],{"class":180},[174,1576,1577],{"class":188}," reboot\n",[126,1579,1580,1581],{},"ถ้าเชื่อมต่อผ่าน SSH การเชื่อมต่อจะขาดระหว่างรีสตาร์ต รอให้เครื่องกลับมาทำงานแล้วจึงเชื่อมต่อใหม่ อ่านเพิ่มเติมเรื่องการรีสตาร์ตหลังอัปเดตได้ใน ",[292,1582,1585],{"href":1583,"rel":1584},"https:\u002F\u002Fubuntu.com\u002Fblog\u002Fubuntu-updates-best-practices-for-updating-your-instance",[296],"คำแนะนำของ Ubuntu",[153,1587,1588],{"id":1588},"ติดตั้งเครื่องมือพื้นฐาน",[126,1590,1591],{},"ติดตั้งเครื่องมือสำหรับดาวน์โหลดไฟล์ ใช้งาน Git และแก้ไขไฟล์ตั้งค่า:",[164,1593,1595],{"className":166,"code":1594,"language":168,"meta":169,"style":169},"sudo apt install curl ca-certificates git nano\n",[171,1596,1597],{"__ignoreMap":169},[174,1598,1599,1601,1603,1606,1609,1612,1615],{"class":176,"line":177},[174,1600,403],{"class":180},[174,1602,1488],{"class":188},[174,1604,1605],{"class":188}," install",[174,1607,1608],{"class":188}," curl",[174,1610,1611],{"class":188}," ca-certificates",[174,1613,1614],{"class":188}," git",[174,1616,1617],{"class":188}," nano\n",[126,1619,1620,1621,1624],{},"หากต้องคอมไพล์โปรแกรมหรือ Dependency จาก Source ให้ติดตั้ง ",[171,1622,1623],{},"build-essential"," เพิ่ม:",[164,1626,1628],{"className":166,"code":1627,"language":168,"meta":169,"style":169},"sudo apt install build-essential\n",[171,1629,1630],{"__ignoreMap":169},[174,1631,1632,1634,1636,1638],{"class":176,"line":177},[174,1633,403],{"class":180},[174,1635,1488],{"class":188},[174,1637,1605],{"class":188},[174,1639,1640],{"class":188}," build-essential\n",[126,1642,1643,1644,843,1647,843,1650,847,1653,1656,1657],{},"แพ็กเกจนี้ดึงเครื่องมืออย่าง ",[171,1645,1646],{},"gcc",[171,1648,1649],{},"g++",[171,1651,1652],{},"make",[171,1654,1655],{},"libc6-dev"," มาให้ เครื่องที่ใช้รัน Container อย่างเดียวอาจข้ามส่วนนี้ได้ ดู ",[292,1658,1661],{"href":1659,"rel":1660},"https:\u002F\u002Fpackages.ubuntu.com\u002Fnoble\u002Fbuild-essential",[296],"รายการ Dependency ของ build-essential",[153,1663,1665],{"id":1664},"ตั้งค่า-timezone-เป็น-asiabangkok","ตั้งค่า Timezone เป็น Asia\u002FBangkok",[126,1667,1668,1669,1672],{},"หากต้องการให้เวลาที่แสดงบน Server ตรงกับเวลาประเทศไทย ให้ตั้ง Timezone เป็น ",[171,1670,1671],{},"Asia\u002FBangkok"," แล้วตรวจผล:",[164,1674,1676],{"className":166,"code":1675,"language":168,"meta":169,"style":169},"sudo timedatectl set-timezone Asia\u002FBangkok\ntimedatectl\n",[171,1677,1678,1691],{"__ignoreMap":169},[174,1679,1680,1682,1685,1688],{"class":176,"line":177},[174,1681,403],{"class":180},[174,1683,1684],{"class":188}," timedatectl",[174,1686,1687],{"class":188}," set-timezone",[174,1689,1690],{"class":188}," Asia\u002FBangkok\n",[174,1692,1693],{"class":176,"line":236},[174,1694,1695],{"class":180},"timedatectl\n",[126,1697,1698,1699,1702,1703,1705,1706,1709,1710],{},"บรรทัด ",[171,1700,1701],{},"Time zone"," ควรแสดง ",[171,1704,1671],{}," การตั้ง Timezone กับการซิงก์เวลาผ่าน Network เป็นคนละส่วน ตรวจสถานะการซิงก์ได้จากผล ",[171,1707,1708],{},"timedatectl"," เช่นกัน ดู ",[292,1711,1714],{"href":1712,"rel":1713},"https:\u002F\u002Fmanpages.ubuntu.com\u002Fmanpages\u002Fjammy\u002Fman1\u002Ftimedatectl.1.html",[296],"เอกสาร timedatectl",[153,1716,1718],{"id":1717},"เปลี่ยน-hostname-ให้จำเครื่องได้ง่าย","เปลี่ยน Hostname ให้จำเครื่องได้ง่าย",[126,1720,1721,1722,1725],{},"ตั้งชื่อให้บอกได้ว่าเป็นเครื่องใด เช่น ",[171,1723,1724],{},"homelab-01"," โดยเปลี่ยนชื่อในตัวอย่างให้ตรงกับเครื่องของคุณ:",[164,1727,1729],{"className":166,"code":1728,"language":168,"meta":169,"style":169},"sudo hostnamectl set-hostname homelab-01\nhostnamectl\n",[171,1730,1731,1744],{"__ignoreMap":169},[174,1732,1733,1735,1738,1741],{"class":176,"line":177},[174,1734,403],{"class":180},[174,1736,1737],{"class":188}," hostnamectl",[174,1739,1740],{"class":188}," set-hostname",[174,1742,1743],{"class":188}," homelab-01\n",[174,1745,1746],{"class":176,"line":236},[174,1747,1748],{"class":180},"hostnamectl\n",[126,1750,1751,1752,1755,1756,1759],{},"หาก ",[171,1753,1754],{},"\u002Fetc\u002Fhosts"," ยังผูกชื่อเดิมไว้กับ ",[171,1757,1758],{},"127.0.1.1"," ให้แก้ชื่อนั้นให้ตรงกับ Hostname ใหม่:",[164,1761,1763],{"className":166,"code":1762,"language":168,"meta":169,"style":169},"sudo nano \u002Fetc\u002Fhosts\n",[171,1764,1765],{"__ignoreMap":169},[174,1766,1767,1769,1772],{"class":176,"line":177},[174,1768,403],{"class":180},[174,1770,1771],{"class":188}," nano",[174,1773,1774],{"class":188}," \u002Fetc\u002Fhosts\n",[126,1776,1777],{},"ตัวอย่างเฉพาะบรรทัดที่เกี่ยวข้อง:",[164,1779,1782],{"className":1780,"code":1781,"language":529,"meta":169},[527],"127.0.1.1 homelab-01\n",[171,1783,1781],{"__ignoreMap":169},[126,1785,1786,1787],{},"คงรายการอื่นในไฟล์ไว้ การเปลี่ยน Hostname ไม่ได้สร้าง DNS Record ให้เครื่องอื่นค้นหาชื่อนี้ได้โดยอัตโนมัติ ดูเพิ่มเติมเรื่อง ",[292,1788,1791],{"href":1789,"rel":1790},"https:\u002F\u002Fubuntu.com\u002Fserver\u002Fdocs\u002Fexplanation\u002Fnetworking\u002Fconfiguring-networks\u002F",[296],"การตั้งชื่อและเครือข่ายบน Ubuntu",[139,1793,1795],{"id":1794},"ตรวจ-ssh-และเปิด-firewall","ตรวจ SSH และเปิด Firewall",[126,1797,1798],{},"ติดตั้ง OpenSSH Server และ UFW หากยังไม่มี:",[164,1800,1802],{"className":166,"code":1801,"language":168,"meta":169,"style":169},"sudo apt install openssh-server ufw\n",[171,1803,1804],{"__ignoreMap":169},[174,1805,1806,1808,1810,1812,1815],{"class":176,"line":177},[174,1807,403],{"class":180},[174,1809,1488],{"class":188},[174,1811,1605],{"class":188},[174,1813,1814],{"class":188}," openssh-server",[174,1816,1817],{"class":188}," ufw\n",[126,1819,1820,1821,847,1824,1827],{},"ถ้ายังไม่เคยเชื่อมต่อผ่าน SSH ให้ลองจาก Terminal บนเครื่องที่ใช้ดูแล Server ก่อน โดยแทน ",[171,1822,1823],{},"your-user",[171,1825,1826],{},"SERVER_IP"," ด้วยค่าจริง:",[164,1829,1831],{"className":166,"code":1830,"language":168,"meta":169,"style":169},"ssh your-user@SERVER_IP\n",[171,1832,1833],{"__ignoreMap":169},[174,1834,1835,1837],{"class":176,"line":177},[174,1836,360],{"class":180},[174,1838,1839],{"class":188}," your-user@SERVER_IP\n",[126,1841,1842,1843,1846,1847,471],{},"ตัวอย่างด้านล่างใช้ ",[390,1844,1845],{},"SSH พอร์ต 22"," หากเครื่องใช้พอร์ตอื่น ให้เปิดพอร์ตนั้นแทน และอนุญาตพอร์ตของบริการที่ต้องใช้งานก่อนสั่ง ",[171,1848,1849],{},"ufw enable",[164,1851,1853],{"className":166,"code":1852,"language":168,"meta":169,"style":169},"sudo ufw allow 22\u002Ftcp\nsudo ufw default deny incoming\nsudo ufw default allow outgoing\nsudo ufw enable\nsudo ufw status verbose\n",[171,1854,1855,1868,1883,1896,1905],{"__ignoreMap":169},[174,1856,1857,1859,1862,1865],{"class":176,"line":177},[174,1858,403],{"class":180},[174,1860,1861],{"class":188}," ufw",[174,1863,1864],{"class":188}," allow",[174,1866,1867],{"class":188}," 22\u002Ftcp\n",[174,1869,1870,1872,1874,1877,1880],{"class":176,"line":236},[174,1871,403],{"class":180},[174,1873,1861],{"class":188},[174,1875,1876],{"class":188}," default",[174,1878,1879],{"class":188}," deny",[174,1881,1882],{"class":188}," incoming\n",[174,1884,1885,1887,1889,1891,1893],{"class":176,"line":242},[174,1886,403],{"class":180},[174,1888,1861],{"class":188},[174,1890,1876],{"class":188},[174,1892,1864],{"class":188},[174,1894,1895],{"class":188}," outgoing\n",[174,1897,1898,1900,1902],{"class":176,"line":248},[174,1899,403],{"class":180},[174,1901,1861],{"class":188},[174,1903,1904],{"class":188}," enable\n",[174,1906,1907,1909,1911,1914],{"class":176,"line":254},[174,1908,403],{"class":180},[174,1910,1861],{"class":188},[174,1912,1913],{"class":188}," status",[174,1915,1916],{"class":188}," verbose\n",[126,1918,1919],{},"หลังเปิด Firewall ให้คง SSH Session เดิมไว้ แล้วลองเชื่อมต่อจากอีกหน้าต่างหนึ่ง เพื่อยืนยันว่ายังเข้าเครื่องได้",[126,1921,1922,1923,847,1928],{},"ดูรายละเอียดใน ",[292,1924,1927],{"href":1925,"rel":1926},"https:\u002F\u002Fubuntu.com\u002Fserver\u002Fdocs\u002Fhow-to\u002Fsecurity\u002Fopenssh-server\u002F",[296],"คู่มือ OpenSSH Server",[292,1929,1932],{"href":1930,"rel":1931},"https:\u002F\u002Fubuntu.com\u002Fserver\u002Fdocs\u002Fhow-to\u002Fsecurity\u002Ffirewalls\u002F",[296],"คู่มือ UFW ของ Ubuntu",[139,1934,1936],{"id":1935},"ติดตั้ง-docker-engine-และ-docker-compose","ติดตั้ง Docker Engine และ Docker Compose",[126,1938,1939],{},"ส่วนนี้เหมาะกับเครื่องที่จะรันแอปพลิเคชันด้วย Container โดยติดตั้ง Docker Engine ผ่าน APT Repository ของ Docker เพื่อให้อัปเดตต่อผ่าน APT ได้ วิธีนี้ติดตั้ง Compose Plugin และ Buildx ไปพร้อมกัน",[126,1941,1942,1943,843,1946,843,1949,1952,1953,1958],{},"คำสั่งต่อไปนี้ใช้กับเครื่องที่ยังไม่ได้ติดตั้ง Docker หากมี ",[171,1944,1945],{},"docker.io",[171,1947,1948],{},"podman-docker",[171,1950,1951],{},"containerd"," หรือแพ็กเกจ Container Runtime อยู่แล้ว ให้ตรวจเรื่องแพ็กเกจที่ขัดกันใน ",[292,1954,1957],{"href":1955,"rel":1956},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Finstall\u002Fubuntu\u002F",[296],"คู่มือติดตั้ง Docker บน Ubuntu"," ก่อน",[153,1960,1962],{"id":1961},"เพิ่ม-repository-ของ-docker","เพิ่ม Repository ของ Docker",[126,1964,1965],{},"เตรียม Directory และดาวน์โหลด Signing Key:",[164,1967,1969],{"className":166,"code":1968,"language":168,"meta":169,"style":169},"sudo install -m 0755 -d \u002Fetc\u002Fapt\u002Fkeyrings\nsudo curl -fsSL https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg \\\n  -o \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\nsudo chmod a+r \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\n",[171,1970,1971,1990,2006,2014],{"__ignoreMap":169},[174,1972,1973,1975,1977,1980,1984,1987],{"class":176,"line":177},[174,1974,403],{"class":180},[174,1976,1605],{"class":188},[174,1978,1979],{"class":184}," -m",[174,1981,1983],{"class":1982},"snOyU"," 0755",[174,1985,1986],{"class":184}," -d",[174,1988,1989],{"class":188}," \u002Fetc\u002Fapt\u002Fkeyrings\n",[174,1991,1992,1994,1996,1999,2002],{"class":176,"line":236},[174,1993,403],{"class":180},[174,1995,1608],{"class":188},[174,1997,1998],{"class":184}," -fsSL",[174,2000,2001],{"class":188}," https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg",[174,2003,2005],{"class":2004},"sicAX"," \\\n",[174,2007,2008,2011],{"class":176,"line":242},[174,2009,2010],{"class":184},"  -o",[174,2012,2013],{"class":188}," \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\n",[174,2015,2016,2018,2021,2024],{"class":176,"line":248},[174,2017,403],{"class":180},[174,2019,2020],{"class":188}," chmod",[174,2022,2023],{"class":188}," a+r",[174,2025,2013],{"class":188},[126,2027,2028],{},"เพิ่ม Repository โดยอ่าน Codename และ Architecture จากเครื่อง:",[164,2030,2032],{"className":166,"code":2031,"language":168,"meta":169,"style":169},"sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.sources > \u002Fdev\u002Fnull \u003C\u003CEOF\nTypes: deb\nURIs: https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\nSuites: $(. \u002Fetc\u002Fos-release && echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\")\nComponents: stable\nArchitectures: $(dpkg --print-architecture)\nSigned-By: \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\nEOF\n",[171,2033,2034,2058,2063,2068,2105,2110,2127,2133],{"__ignoreMap":169},[174,2035,2036,2038,2041,2044,2048,2051,2054],{"class":176,"line":177},[174,2037,403],{"class":180},[174,2039,2040],{"class":188}," tee",[174,2042,2043],{"class":188}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.sources",[174,2045,2047],{"class":2046},"sbGrh"," >",[174,2049,2050],{"class":188}," \u002Fdev\u002Fnull",[174,2052,2053],{"class":2046}," \u003C\u003C",[174,2055,2057],{"class":2056},"s2KDN","EOF\n",[174,2059,2060],{"class":176,"line":236},[174,2061,2062],{"class":188},"Types: deb\n",[174,2064,2065],{"class":176,"line":242},[174,2066,2067],{"class":188},"URIs: https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\n",[174,2069,2070,2073,2076,2080,2083,2086,2089,2092,2096,2099,2102],{"class":176,"line":248},[174,2071,2072],{"class":188},"Suites: ",[174,2074,2075],{"class":372},"$(",[174,2077,2079],{"class":2078},"sJZfL",".",[174,2081,2082],{"class":188}," \u002Fetc\u002Fos-release ",[174,2084,2085],{"class":372},"&&",[174,2087,2088],{"class":2078}," echo",[174,2090,2091],{"class":372}," \"${",[174,2093,2095],{"class":2094},"sLHrO","UBUNTU_CODENAME",[174,2097,2098],{"class":2046},":-",[174,2100,2101],{"class":2094},"$VERSION_CODENAME",[174,2103,2104],{"class":372},"}\")\n",[174,2106,2107],{"class":176,"line":254},[174,2108,2109],{"class":188},"Components: stable\n",[174,2111,2113,2116,2118,2121,2124],{"class":176,"line":2112},6,[174,2114,2115],{"class":188},"Architectures: ",[174,2117,2075],{"class":372},[174,2119,2120],{"class":180},"dpkg",[174,2122,2123],{"class":184}," --print-architecture",[174,2125,2126],{"class":372},")\n",[174,2128,2130],{"class":176,"line":2129},7,[174,2131,2132],{"class":188},"Signed-By: \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\n",[174,2134,2136],{"class":176,"line":2135},8,[174,2137,2057],{"class":2056},[153,2139,2141],{"id":2140},"ติดตั้งและทดสอบ-docker","ติดตั้งและทดสอบ Docker",[164,2143,2145],{"className":166,"code":2144,"language":168,"meta":169,"style":169},"sudo apt update\nsudo apt install docker-ce docker-ce-cli containerd.io \\\n  docker-buildx-plugin docker-compose-plugin\nsudo systemctl enable --now docker\n",[171,2146,2147,2155,2174,2182],{"__ignoreMap":169},[174,2148,2149,2151,2153],{"class":176,"line":177},[174,2150,403],{"class":180},[174,2152,1488],{"class":188},[174,2154,1491],{"class":188},[174,2156,2157,2159,2161,2163,2166,2169,2172],{"class":176,"line":236},[174,2158,403],{"class":180},[174,2160,1488],{"class":188},[174,2162,1605],{"class":188},[174,2164,2165],{"class":188}," docker-ce",[174,2167,2168],{"class":188}," docker-ce-cli",[174,2170,2171],{"class":188}," containerd.io",[174,2173,2005],{"class":2004},[174,2175,2176,2179],{"class":176,"line":242},[174,2177,2178],{"class":188},"  docker-buildx-plugin",[174,2180,2181],{"class":188}," docker-compose-plugin\n",[174,2183,2184,2186,2189,2192,2195],{"class":176,"line":248},[174,2185,403],{"class":180},[174,2187,2188],{"class":188}," systemctl",[174,2190,2191],{"class":188}," enable",[174,2193,2194],{"class":184}," --now",[174,2196,2197],{"class":188}," docker\n",[126,2199,2200],{},"ตรวจว่าเรียกใช้งานได้:",[164,2202,2204],{"className":166,"code":2203,"language":168,"meta":169,"style":169},"sudo docker run --rm hello-world\ndocker compose version\n",[171,2205,2206,2222],{"__ignoreMap":169},[174,2207,2208,2210,2213,2216,2219],{"class":176,"line":177},[174,2209,403],{"class":180},[174,2211,2212],{"class":188}," docker",[174,2214,2215],{"class":188}," run",[174,2217,2218],{"class":184}," --rm",[174,2220,2221],{"class":188}," hello-world\n",[174,2223,2224,2227,2230],{"class":176,"line":236},[174,2225,2226],{"class":180},"docker",[174,2228,2229],{"class":188}," compose",[174,2231,2232],{"class":188}," version\n",[126,2234,2235,2238,2239,2242],{},[171,2236,2237],{},"hello-world"," ทดสอบทั้งการติดต่อ Docker Daemon การดึง Image และการรัน Container ส่วน ",[171,2240,2241],{},"docker compose version"," ใช้ตรวจว่า Compose Plugin พร้อมใช้งานแล้ว",[153,2244,2246],{"id":2245},"ใช้-docker-โดยไม่ต้องพิมพ์-sudo","ใช้ Docker โดยไม่ต้องพิมพ์ sudo",[126,2248,2249,2250,2252],{},"หากต้องการให้บัญชีปัจจุบันเรียก Docker ได้โดยตรง ให้เพิ่มเข้ากลุ่ม ",[171,2251,2226],{}," โดยรันจากบัญชีผู้ใช้ปกติที่ต้องการให้สิทธิ์:",[164,2254,2256],{"className":166,"code":2255,"language":168,"meta":169,"style":169},"sudo usermod -aG docker \"$USER\"\n",[171,2257,2258],{"__ignoreMap":169},[174,2259,2260,2262,2265,2268,2270,2273,2276],{"class":176,"line":177},[174,2261,403],{"class":180},[174,2263,2264],{"class":188}," usermod",[174,2266,2267],{"class":184}," -aG",[174,2269,2212],{"class":188},[174,2271,2272],{"class":372}," \"",[174,2274,2275],{"class":2094},"$USER",[174,2277,2278],{"class":372},"\"\n",[126,2280,2281],{},"ออกจากระบบแล้วเข้าสู่ระบบใหม่ หากใช้ SSH ให้เชื่อมต่อใหม่ จากนั้นตรวจชื่อกลุ่มและลองรัน Container:",[164,2283,2285],{"className":166,"code":2284,"language":168,"meta":169,"style":169},"id -nG\ndocker run --rm hello-world\n",[171,2286,2287,2295],{"__ignoreMap":169},[174,2288,2289,2292],{"class":176,"line":177},[174,2290,2291],{"class":180},"id",[174,2293,2294],{"class":184}," -nG\n",[174,2296,2297,2299,2301,2303],{"class":176,"line":236},[174,2298,2226],{"class":180},[174,2300,2215],{"class":188},[174,2302,2218],{"class":184},[174,2304,2221],{"class":188},[126,2306,2307],{},"การเพิ่มกลุ่มมีผลกับ Session ใหม่ จึงไม่ต้องรีสตาร์ต Docker เพื่อทำให้สิทธิ์ของ Session เดิมเปลี่ยน",[1031,2309,2310],{},[126,2311,2312,2313,2315,2316],{},"สมาชิกกลุ่ม ",[171,2314,2226],{}," มีสิทธิ์ควบคุมเครื่องในระดับ Root ควรเพิ่มเฉพาะบัญชีที่ไว้ใจ รายละเอียดอยู่ใน ",[292,2317,2320],{"href":2318,"rel":2319},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Finstall\u002Flinux-postinstall\u002F",[296],"คู่มือหลังติดตั้ง Docker",[153,2322,2324],{"id":2323},"ตรวจพอร์ตของ-container-แยกจาก-ufw","ตรวจพอร์ตของ Container แยกจาก UFW",[126,2326,2327,2328,2331,2332,400,2335,2338,2339],{},"พอร์ตที่ Publish ผ่าน Docker สามารถข้ามกฎ UFW ได้ จึงไม่ควรใช้ผล ",[171,2329,2330],{},"ufw status"," เพียงอย่างเดียวเพื่อตัดสินว่าบริการใน Container เข้าถึงจากภายนอกไม่ได้ ตรวจการตั้งค่า ",[171,2333,2334],{},"ports",[171,2336,2337],{},"-p"," และขอบเขตการเข้าถึงของแต่ละบริการด้วย ดู ",[292,2340,2343],{"href":2341,"rel":2342},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Fnetwork\u002Fpacket-filtering-firewalls\u002F#docker-and-ufw",[296],"คำอธิบาย Docker กับ UFW",[139,2345,2347],{"id":2346},"ติดตั้ง-nodejs-และ-yarn","ติดตั้ง Node.js และ Yarn",[126,2349,2350,2351,2354],{},"ทำส่วนนี้เมื่อ Server ต้องรัน Node.js บน Host หรือใช้ Build โปรเจกต์ ตัวอย่างเลือก ",[390,2352,2353],{},"Node.js 24 LTS"," ผ่าน Repository ของ NodeSource หากโปรเจกต์กำหนดเวอร์ชันไว้ ให้ยึดเวอร์ชันของโปรเจกต์ก่อน",[126,2356,2357,2358,2363],{},"Node.js 22 ยังอยู่ในระยะสนับสนุนถึง 30 เมษายน 2027 ส่วน Node.js 24 ถึง 30 เมษายน 2028 ตาม ",[292,2359,2362],{"href":2360,"rel":2361},"https:\u002F\u002Fgithub.com\u002Fnodejs\u002FRelease",[296],"กำหนดการของ Node.js"," จึงไม่จำเป็นต้องเปลี่ยนโปรเจกต์เดิมจาก 22 เป็น 24 เพียงเพื่อทำตามบทความนี้",[153,2365,2367],{"id":2366},"ติดตั้ง-nodejs-ผ่าน-nodesource","ติดตั้ง Node.js ผ่าน NodeSource",[126,2369,2370],{},"ดาวน์โหลด Setup Script:",[164,2372,2374],{"className":166,"code":2373,"language":168,"meta":169,"style":169},"curl -fsSL https:\u002F\u002Fdeb.nodesource.com\u002Fsetup_24.x \\\n  -o \u002Ftmp\u002Fnodesource-setup.sh\n",[171,2375,2376,2388],{"__ignoreMap":169},[174,2377,2378,2381,2383,2386],{"class":176,"line":177},[174,2379,2380],{"class":180},"curl",[174,2382,1998],{"class":184},[174,2384,2385],{"class":188}," https:\u002F\u002Fdeb.nodesource.com\u002Fsetup_24.x",[174,2387,2005],{"class":2004},[174,2389,2390,2392],{"class":176,"line":236},[174,2391,2010],{"class":184},[174,2393,2394],{"class":188}," \u002Ftmp\u002Fnodesource-setup.sh\n",[126,2396,2397,2398,2401],{},"เปิดอ่านไฟล์ก่อนรันด้วย ",[171,2399,2400],{},"nano \u002Ftmp\u002Fnodesource-setup.sh"," จากนั้นติดตั้ง Repository และแพ็กเกจ:",[164,2403,2405],{"className":166,"code":2404,"language":168,"meta":169,"style":169},"sudo bash \u002Ftmp\u002Fnodesource-setup.sh\nsudo apt install nodejs\n",[171,2406,2407,2416],{"__ignoreMap":169},[174,2408,2409,2411,2414],{"class":176,"line":177},[174,2410,403],{"class":180},[174,2412,2413],{"class":188}," bash",[174,2415,2394],{"class":188},[174,2417,2418,2420,2422,2424],{"class":176,"line":236},[174,2419,403],{"class":180},[174,2421,1488],{"class":188},[174,2423,1605],{"class":188},[174,2425,2426],{"class":188}," nodejs\n",[126,2428,2429],{},"ตรวจเวอร์ชัน:",[164,2431,2433],{"className":166,"code":2432,"language":168,"meta":169,"style":169},"node --version\nnpm --version\n",[171,2434,2435,2443],{"__ignoreMap":169},[174,2436,2437,2440],{"class":176,"line":177},[174,2438,2439],{"class":180},"node",[174,2441,2442],{"class":184}," --version\n",[174,2444,2445,2448],{"class":176,"line":236},[174,2446,2447],{"class":180},"npm",[174,2449,2442],{"class":184},[126,2451,2452,2453,2456,2457],{},"ถ้าต้องใช้ Node.js 22 ให้เปลี่ยน URL เป็น ",[171,2454,2455],{},"https:\u002F\u002Fdeb.nodesource.com\u002Fsetup_22.x"," ก่อนดาวน์โหลด ดูวิธีติดตั้งและระบบที่รองรับใน ",[292,2458,2461],{"href":2459,"rel":2460},"https:\u002F\u002Fgithub.com\u002Fnodesource\u002Fdistributions\u002Fblob\u002Fmaster\u002FDEV_README.md",[296],"เอกสาร NodeSource",[153,2463,2465],{"id":2464},"เปิดใช้-yarn-ผ่าน-corepack","เปิดใช้ Yarn ผ่าน Corepack",[126,2467,2468,2469,2474],{},"หากโปรเจกต์ใช้ Yarn ให้จัดการเวอร์ชันผ่าน Corepack ตาม ",[292,2470,2473],{"href":2471,"rel":2472},"https:\u002F\u002Fyarnpkg.com\u002Fcorepack",[296],"คำแนะนำของ Yarn"," เพื่อให้ใช้เวอร์ชัน Package Manager ตามที่โปรเจกต์กำหนด",[126,2476,2477],{},"สำหรับ Node.js ที่ติดตั้งทั้งระบบผ่าน APT ตามขั้นตอนข้างต้น:",[164,2479,2481],{"className":166,"code":2480,"language":168,"meta":169,"style":169},"sudo npm install --global corepack\nsudo corepack enable yarn\n",[171,2482,2483,2497],{"__ignoreMap":169},[174,2484,2485,2487,2490,2492,2494],{"class":176,"line":177},[174,2486,403],{"class":180},[174,2488,2489],{"class":188}," npm",[174,2491,1605],{"class":188},[174,2493,1102],{"class":184},[174,2495,2496],{"class":188}," corepack\n",[174,2498,2499,2501,2504,2506],{"class":176,"line":236},[174,2500,403],{"class":180},[174,2502,2503],{"class":188}," corepack",[174,2505,2191],{"class":188},[174,2507,2508],{"class":188}," yarn\n",[126,2510,2511],{},"เข้า Directory ของโปรเจกต์แล้วตรวจเวอร์ชัน:",[164,2513,2515],{"className":166,"code":2514,"language":168,"meta":169,"style":169},"yarn --version\n",[171,2516,2517],{"__ignoreMap":169},[174,2518,2519,2522],{"class":176,"line":177},[174,2520,2521],{"class":180},"yarn",[174,2523,2442],{"class":184},[126,2525,2526,2527,2530,2531,2534],{},"ถ้า ",[171,2528,2529],{},"package.json"," มีฟิลด์ ",[171,2532,2533],{},"packageManager"," อยู่แล้ว ให้ใช้เวอร์ชันตามนั้น ส่วนโปรเจกต์ใหม่ควรกำหนดเวอร์ชัน Package Manager และเก็บค่าไว้ใน Repository ด้วย",[139,2536,2538],{"id":2537},"ติดตั้ง-helm-สำหรับใช้งาน-kubernetes","ติดตั้ง Helm สำหรับใช้งาน Kubernetes",[126,2540,2541],{},"Helm ใช้ติดตั้งและจัดการแอปพลิเคชันบน Kubernetes หากยังไม่ได้ใช้งาน Kubernetes สามารถข้ามส่วนนี้ได้ การติดตั้ง Helm CLI อย่างเดียวไม่ได้สร้าง Cluster ให้",[126,2543,2544,2545,2548],{},"ตัวอย่างใช้สคริปต์ติดตั้ง ",[390,2546,2547],{},"Helm 4"," จากโครงการโดยตรง:",[164,2550,2552],{"className":166,"code":2551,"language":168,"meta":169,"style":169},"curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fhelm\u002Fhelm\u002Fmain\u002Fscripts\u002Fget-helm-4 \\\n  -o \u002Ftmp\u002Finstall-helm.sh\n",[171,2553,2554,2565],{"__ignoreMap":169},[174,2555,2556,2558,2560,2563],{"class":176,"line":177},[174,2557,2380],{"class":180},[174,2559,1998],{"class":184},[174,2561,2562],{"class":188}," https:\u002F\u002Fraw.githubusercontent.com\u002Fhelm\u002Fhelm\u002Fmain\u002Fscripts\u002Fget-helm-4",[174,2564,2005],{"class":2004},[174,2566,2567,2569],{"class":176,"line":236},[174,2568,2010],{"class":184},[174,2570,2571],{"class":188}," \u002Ftmp\u002Finstall-helm.sh\n",[126,2573,2574,2575,2578],{},"เปิดอ่านด้วย ",[171,2576,2577],{},"nano \u002Ftmp\u002Finstall-helm.sh"," แล้วจึงรัน:",[164,2580,2582],{"className":166,"code":2581,"language":168,"meta":169,"style":169},"bash \u002Ftmp\u002Finstall-helm.sh\nhelm version --short\n",[171,2583,2584,2590],{"__ignoreMap":169},[174,2585,2586,2588],{"class":176,"line":177},[174,2587,168],{"class":180},[174,2589,2571],{"class":188},[174,2591,2592,2595,2598],{"class":176,"line":236},[174,2593,2594],{"class":180},"helm",[174,2596,2597],{"class":188}," version",[174,2599,2600],{"class":184}," --short\n",[126,2602,2603,2604,847,2609],{},"หากระบบเดิมกำหนดให้ใช้ Helm 3 ให้เลือกติดตั้งเวอร์ชันนั้นและตรวจ Compatibility ก่อนเปลี่ยน Major Version ดู ",[292,2605,2608],{"href":2606,"rel":2607},"https:\u002F\u002Fhelm.sh\u002Fdocs\u002Fintro\u002Finstall\u002F",[296],"คู่มือติดตั้ง Helm",[292,2610,2613],{"href":2611,"rel":2612},"https:\u002F\u002Fhelm.sh\u002Fdocs\u002Fv3\u002Fintro\u002Finstall\u002F",[296],"คู่มือสำหรับ Helm 3",[139,2615,2617],{"id":2616},"ปรับแต่ง-shell-ด้วย-zsh-และ-oh-my-zsh","ปรับแต่ง Shell ด้วย Zsh และ Oh My Zsh",[126,2619,2620],{},"ส่วนนี้สำหรับคนที่ต้องการคำแนะนำขณะพิมพ์และปรับแต่ง Prompt หากใช้ Bash อยู่แล้วสามารถข้ามไปได้ โดยไม่มีผลต่อการติดตั้ง Docker หรือ Node.js",[153,2622,2624],{"id":2623},"ติดตั้ง-zsh-และ-oh-my-zsh","ติดตั้ง Zsh และ Oh My Zsh",[164,2626,2628],{"className":166,"code":2627,"language":168,"meta":169,"style":169},"sudo apt install zsh\ncurl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fohmyzsh\u002Fohmyzsh\u002Fmaster\u002Ftools\u002Finstall.sh \\\n  -o \u002Ftmp\u002Finstall-oh-my-zsh.sh\n",[171,2629,2630,2641,2652],{"__ignoreMap":169},[174,2631,2632,2634,2636,2638],{"class":176,"line":177},[174,2633,403],{"class":180},[174,2635,1488],{"class":188},[174,2637,1605],{"class":188},[174,2639,2640],{"class":188}," zsh\n",[174,2642,2643,2645,2647,2650],{"class":176,"line":236},[174,2644,2380],{"class":180},[174,2646,1998],{"class":184},[174,2648,2649],{"class":188}," https:\u002F\u002Fraw.githubusercontent.com\u002Fohmyzsh\u002Fohmyzsh\u002Fmaster\u002Ftools\u002Finstall.sh",[174,2651,2005],{"class":2004},[174,2653,2654,2656],{"class":176,"line":242},[174,2655,2010],{"class":184},[174,2657,2658],{"class":188}," \u002Ftmp\u002Finstall-oh-my-zsh.sh\n",[126,2660,2661,2662,2665],{},"เปิดอ่านสคริปต์ด้วย ",[171,2663,2664],{},"nano \u002Ftmp\u002Finstall-oh-my-zsh.sh"," แล้วติดตั้งในบัญชีผู้ใช้ปัจจุบัน:",[164,2667,2669],{"className":166,"code":2668,"language":168,"meta":169,"style":169},"sh \u002Ftmp\u002Finstall-oh-my-zsh.sh\n",[171,2670,2671],{"__ignoreMap":169},[174,2672,2673,2676],{"class":176,"line":177},[174,2674,2675],{"class":180},"sh",[174,2677,2658],{"class":188},[126,2679,2680,2681],{},"ตัวติดตั้งอาจถามว่าจะเปลี่ยน Default Shell เป็น Zsh หรือไม่ หากต้องการใช้ Zsh ทุกครั้งที่เข้าเครื่อง ให้ตอบตกลงแล้วออกจากระบบและเข้าใหม่ ดู ",[292,2682,2685],{"href":2683,"rel":2684},"https:\u002F\u002Fgithub.com\u002Fohmyzsh\u002Fohmyzsh",[296],"คู่มือติดตั้ง Oh My Zsh",[153,2687,2689],{"id":2688},"เพิ่ม-autosuggestions-และ-syntax-highlighting","เพิ่ม Autosuggestions และ Syntax Highlighting",[126,2691,2692,2695,2696,2699],{},[171,2693,2694],{},"zsh-autosuggestions"," ช่วยเสนอคำสั่งจาก History ส่วน ",[171,2697,2698],{},"zsh-syntax-highlighting"," ช่วยแยกสีขณะพิมพ์คำสั่ง",[126,2701,2702],{},"ติดตั้งทั้งสอง Plugin:",[164,2704,2706],{"className":166,"code":2705,"language":168,"meta":169,"style":169},"git clone https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-autosuggestions.git \\\n  \"${ZSH_CUSTOM:-$HOME\u002F.oh-my-zsh\u002Fcustom}\u002Fplugins\u002Fzsh-autosuggestions\"\n\ngit clone https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-syntax-highlighting.git \\\n  \"${ZSH_CUSTOM:-$HOME\u002F.oh-my-zsh\u002Fcustom}\u002Fplugins\u002Fzsh-syntax-highlighting\"\n",[171,2707,2708,2721,2755,2760,2771],{"__ignoreMap":169},[174,2709,2710,2713,2716,2719],{"class":176,"line":177},[174,2711,2712],{"class":180},"git",[174,2714,2715],{"class":188}," clone",[174,2717,2718],{"class":188}," https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-autosuggestions.git",[174,2720,2005],{"class":2004},[174,2722,2723,2726,2729,2731,2734,2737,2739,2742,2744,2747,2750,2753],{"class":176,"line":236},[174,2724,2725],{"class":372},"  \"${",[174,2727,2728],{"class":2094},"ZSH_CUSTOM",[174,2730,2098],{"class":2046},[174,2732,2733],{"class":2094},"$HOME",[174,2735,2736],{"class":2046},"\u002F",[174,2738,2079],{"class":188},[174,2740,2741],{"class":2094},"oh-my-zsh",[174,2743,2736],{"class":2046},[174,2745,2746],{"class":2094},"custom",[174,2748,2749],{"class":372},"}",[174,2751,2752],{"class":188},"\u002Fplugins\u002Fzsh-autosuggestions",[174,2754,2278],{"class":372},[174,2756,2757],{"class":176,"line":242},[174,2758,2759],{"emptyLinePlaceholder":935},"\n",[174,2761,2762,2764,2766,2769],{"class":176,"line":248},[174,2763,2712],{"class":180},[174,2765,2715],{"class":188},[174,2767,2768],{"class":188}," https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-syntax-highlighting.git",[174,2770,2005],{"class":2004},[174,2772,2773,2775,2777,2779,2781,2783,2785,2787,2789,2791,2793,2796],{"class":176,"line":254},[174,2774,2725],{"class":372},[174,2776,2728],{"class":2094},[174,2778,2098],{"class":2046},[174,2780,2733],{"class":2094},[174,2782,2736],{"class":2046},[174,2784,2079],{"class":188},[174,2786,2741],{"class":2094},[174,2788,2736],{"class":2046},[174,2790,2746],{"class":2094},[174,2792,2749],{"class":372},[174,2794,2795],{"class":188},"\u002Fplugins\u002Fzsh-syntax-highlighting",[174,2797,2278],{"class":372},[126,2799,2800],{},"เปิดไฟล์ตั้งค่า:",[164,2802,2804],{"className":166,"code":2803,"language":168,"meta":169,"style":169},"nano ~\u002F.zshrc\n",[171,2805,2806],{"__ignoreMap":169},[174,2807,2808,2811],{"class":176,"line":177},[174,2809,2810],{"class":180},"nano",[174,2812,2813],{"class":188}," ~\u002F.zshrc\n",[126,2815,2816,2817,2820,2821,2823,2824,471],{},"แก้รายการ ",[171,2818,2819],{},"plugins"," เดิม โดยวาง ",[171,2822,2698],{}," ไว้ท้ายสุดตาม ",[292,2825,2828],{"href":2826,"rel":2827},"https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-syntax-highlighting\u002Fblob\u002Fmaster\u002FINSTALL.md",[296],"คำแนะนำของ Plugin",[164,2830,2834],{"className":2831,"code":2832,"language":2833,"meta":169,"style":169},"language-zsh shiki shiki-themes material-theme-lighter one-dark-pro github-dark","plugins=(\n  git\n  zsh-autosuggestions\n  zsh-syntax-highlighting\n)\n","zsh",[171,2835,2836,2841,2846,2851,2856],{"__ignoreMap":169},[174,2837,2838],{"class":176,"line":177},[174,2839,2840],{},"plugins=(\n",[174,2842,2843],{"class":176,"line":236},[174,2844,2845],{},"  git\n",[174,2847,2848],{"class":176,"line":242},[174,2849,2850],{},"  zsh-autosuggestions\n",[174,2852,2853],{"class":176,"line":248},[174,2854,2855],{},"  zsh-syntax-highlighting\n",[174,2857,2858],{"class":176,"line":254},[174,2859,2126],{},[126,2861,2862],{},"เริ่ม Zsh ใหม่เพื่อโหลดการตั้งค่า:",[164,2864,2866],{"className":166,"code":2865,"language":168,"meta":169,"style":169},"exec zsh\n",[171,2867,2868],{"__ignoreMap":169},[174,2869,2870,2873],{"class":176,"line":177},[174,2871,2872],{"class":2078},"exec",[174,2874,2640],{"class":188},[153,2876,2878],{"id":2877},"ตั้งค่า-powerlevel10k","ตั้งค่า Powerlevel10k",[126,2880,2881,2882,2887],{},"หากต้องการ Prompt แบบ Powerlevel10k สามารถติดตั้งเพิ่มเติมได้ อย่างไรก็ตาม ",[292,2883,2886],{"href":2884,"rel":2885},"https:\u002F\u002Fgithub.com\u002Fromkatv\u002Fpowerlevel10k",[296],"ผู้พัฒนาระบุว่าปัจจุบันดูแลโครงการในขอบเขตจำกัด"," และไม่มีแผนเพิ่มฟีเจอร์ใหม่ ควรพิจารณาสถานะนี้ก่อนเลือกใช้ระยะยาว",[164,2889,2891],{"className":166,"code":2890,"language":168,"meta":169,"style":169},"git clone --depth=1 https:\u002F\u002Fgithub.com\u002Fromkatv\u002Fpowerlevel10k.git \\\n  \"${ZSH_CUSTOM:-$HOME\u002F.oh-my-zsh\u002Fcustom}\u002Fthemes\u002Fpowerlevel10k\"\n",[171,2892,2893,2907],{"__ignoreMap":169},[174,2894,2895,2897,2899,2902,2905],{"class":176,"line":177},[174,2896,2712],{"class":180},[174,2898,2715],{"class":188},[174,2900,2901],{"class":184}," --depth=1",[174,2903,2904],{"class":188}," https:\u002F\u002Fgithub.com\u002Fromkatv\u002Fpowerlevel10k.git",[174,2906,2005],{"class":2004},[174,2908,2909,2911,2913,2915,2917,2919,2921,2923,2925,2927,2929,2932],{"class":176,"line":236},[174,2910,2725],{"class":372},[174,2912,2728],{"class":2094},[174,2914,2098],{"class":2046},[174,2916,2733],{"class":2094},[174,2918,2736],{"class":2046},[174,2920,2079],{"class":188},[174,2922,2741],{"class":2094},[174,2924,2736],{"class":2046},[174,2926,2746],{"class":2094},[174,2928,2749],{"class":372},[174,2930,2931],{"class":188},"\u002Fthemes\u002Fpowerlevel10k",[174,2933,2278],{"class":372},[126,2935,2936,2937,2940,2941,2944],{},"เปิด ",[171,2938,2939],{},"~\u002F.zshrc"," แล้วแก้ค่า ",[171,2942,2943],{},"ZSH_THEME"," เดิม:",[164,2946,2948],{"className":2831,"code":2947,"language":2833,"meta":169,"style":169},"ZSH_THEME=\"powerlevel10k\u002Fpowerlevel10k\"\n",[171,2949,2950],{"__ignoreMap":169},[174,2951,2952],{"class":176,"line":177},[174,2953,2947],{},[126,2955,2956],{},"เริ่ม Zsh ใหม่:",[164,2958,2959],{"className":166,"code":2865,"language":168,"meta":169,"style":169},[171,2960,2961],{"__ignoreMap":169},[174,2962,2963,2965],{"class":176,"line":177},[174,2964,2872],{"class":2078},[174,2966,2640],{"class":188},[126,2968,2969],{},"หากตัวช่วยตั้งค่าไม่เปิดขึ้นมา ให้เรียกเอง:",[164,2971,2973],{"className":2831,"code":2972,"language":2833,"meta":169,"style":169},"p10k configure\n",[171,2974,2975],{"__ignoreMap":169},[174,2976,2977],{"class":176,"line":177},[174,2978,2972],{},[126,2980,2981],{},"ถ้าไอคอนแสดงเป็นสี่เหลี่ยมหรืออักขระผิด ให้ติดตั้งและเลือก Nerd Font เช่น MesloLGS NF ในแอป Terminal ที่ใช้ เมื่อเชื่อมต่อผ่าน SSH ให้ตั้งฟอนต์บนเครื่องที่แสดง Terminal",[139,2983,2985],{"id":2984},"ปิด-cloud-init-network-เฉพาะกรณีที่จัดการเครือข่ายเอง","ปิด Cloud-init Network เฉพาะกรณีที่จัดการเครือข่ายเอง",[126,2987,2988],{},"ทำส่วนนี้เมื่อเครื่องใช้ Cloud-init และต้องการดูแลค่า Network ด้วยตัวเอง เช่น ตั้งค่าผ่าน Netplan หากเป็น Cloud Instance ที่รับการตั้งค่าจากผู้ให้บริการ ให้ตรวจวิธีจัดการ Network ของแพลตฟอร์มนั้นก่อน",[126,2990,2991],{},"เปิดไฟล์:",[164,2993,2995],{"className":166,"code":2994,"language":168,"meta":169,"style":169},"sudo nano \u002Fetc\u002Fcloud\u002Fcloud.cfg.d\u002F99-disable-network-config.cfg\n",[171,2996,2997],{"__ignoreMap":169},[174,2998,2999,3001,3003],{"class":176,"line":177},[174,3000,403],{"class":180},[174,3002,1771],{"class":188},[174,3004,3005],{"class":188}," \u002Fetc\u002Fcloud\u002Fcloud.cfg.d\u002F99-disable-network-config.cfg\n",[126,3007,3008],{},"ใส่ค่า:",[164,3010,3014],{"className":3011,"code":3012,"language":3013,"meta":169,"style":169},"language-yaml shiki shiki-themes material-theme-lighter one-dark-pro github-dark","network:\n  config: disabled\n","yaml",[171,3015,3016,3025],{"__ignoreMap":169},[174,3017,3018,3022],{"class":176,"line":177},[174,3019,3021],{"class":3020},"s0Prt","network",[174,3023,3024],{"class":455},":\n",[174,3026,3027,3030,3032],{"class":176,"line":236},[174,3028,3029],{"class":3020},"  config",[174,3031,471],{"class":455},[174,3033,3034],{"class":188}," disabled\n",[126,3036,3037,3038],{},"ค่านี้ปิดเฉพาะการสร้างไฟล์ตั้งค่า Network ของ Cloud-init โดยไม่ได้ปิด Cloud-init ทั้งระบบ ไฟล์ Netplan ที่สร้างไว้เดิมยังคงอยู่ และคำสั่งนี้ไม่ได้ตั้ง IP ใหม่ให้เครื่อง ดู ",[292,3039,3042],{"href":3040,"rel":3041},"https:\u002F\u002Fdocs.cloud-init.io\u002Fen\u002Flatest\u002Freference\u002Fnetwork-config.html",[296],"เอกสาร Network Configuration ของ Cloud-init",[126,3044,3045,3046,3049],{},"หากจะแก้ไฟล์ใน ",[171,3047,3048],{},"\u002Fetc\u002Fnetplan\u002F"," ต่อ ให้สำรองไฟล์ปัจจุบันและเตรียมช่องทางเข้า Console ไว้ หลังแก้จึงตรวจรูปแบบและทดลองใช้ค่า:",[164,3051,3053],{"className":166,"code":3052,"language":168,"meta":169,"style":169},"sudo netplan generate\nsudo netplan try\n",[171,3054,3055,3065],{"__ignoreMap":169},[174,3056,3057,3059,3062],{"class":176,"line":177},[174,3058,403],{"class":180},[174,3060,3061],{"class":188}," netplan",[174,3063,3064],{"class":188}," generate\n",[174,3066,3067,3069,3071],{"class":176,"line":236},[174,3068,403],{"class":180},[174,3070,3061],{"class":188},[174,3072,3073],{"class":188}," try\n",[126,3075,3076,3079,3080],{},[171,3077,3078],{},"netplan try"," จะรอให้ยืนยันการตั้งค่าและมีกลไกย้อนกลับหากไม่ยืนยัน แต่ควรตรวจการเชื่อมต่อจริงก่อนปิด Console โดยเฉพาะเครื่องที่เข้าถึงผ่าน Network ทางเดียว ดูข้อจำกัดใน ",[292,3081,3084],{"href":3082,"rel":3083},"https:\u002F\u002Fnetplan.readthedocs.io\u002Fen\u002Fstable\u002Fnetplan-try\u002F",[296],"เอกสาร netplan try",[139,3086,3087],{"id":3087},"ปัญหาที่อาจพบหลังตั้งค่า",[592,3089,3090,3100],{},[595,3091,3092],{},[598,3093,3094,3097],{},[601,3095,3096],{},"อาการ",[601,3098,3099],{},"จุดที่ควรตรวจ",[608,3101,3102,3121,3136,3148],{},[598,3103,3104,3111],{},[613,3105,3106,3107,3110],{},"Docker แจ้ง ",[171,3108,3109],{},"permission denied"," หลังเพิ่มกลุ่ม",[613,3112,3113,3114,3117,3118,3120],{},"เชื่อมต่อ SSH ใหม่ แล้วดู ",[171,3115,3116],{},"id -nG"," ว่ามีกลุ่ม ",[171,3119,2226],{}," หรือไม่",[598,3122,3123,3126],{},[613,3124,3125],{},"Docker แจ้งว่าเชื่อมต่อ Daemon ไม่ได้",[613,3127,3128,3129,3132,3133],{},"ตรวจ Service ด้วย ",[171,3130,3131],{},"sudo systemctl status docker"," และดูรายละเอียดด้วย ",[171,3134,3135],{},"sudo journalctl -u docker -n 50 --no-pager",[598,3137,3138,3141],{},[613,3139,3140],{},"เครื่องอื่นเรียก Hostname ใหม่ไม่ได้",[613,3142,3143,3144,3147],{},"ตรวจ DNS หรือ ",[171,3145,3146],{},"hosts"," ของเครื่องที่เชื่อมต่อ การเปลี่ยน Hostname บน Server ไม่ได้สร้าง DNS Record",[598,3149,3150,3153],{},[613,3151,3152],{},"ไอคอน Powerlevel10k แสดงผิด",[613,3154,3155],{},"ตรวจฟอนต์ที่เลือกในแอป Terminal บนเครื่องที่ใช้เชื่อมต่อ",[909,3157,3158],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .s36IK, html code.shiki .s36IK{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sicAX, html code.shiki .sicAX{--shiki-light:#90A4AE;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .s2KDN, html code.shiki .s2KDN{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#9ECBFF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .s0Prt, html code.shiki .s0Prt{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#85E89D}",{"title":169,"searchDepth":236,"depth":236,"links":3160},[3161,3162,3168,3169,3175,3179,3180,3185,3186],{"id":1426,"depth":236,"text":1427},{"id":1470,"depth":236,"text":1470,"children":3163},[3164,3165,3166,3167],{"id":1473,"depth":242,"text":1473},{"id":1588,"depth":242,"text":1588},{"id":1664,"depth":242,"text":1665},{"id":1717,"depth":242,"text":1718},{"id":1794,"depth":236,"text":1795},{"id":1935,"depth":236,"text":1936,"children":3170},[3171,3172,3173,3174],{"id":1961,"depth":242,"text":1962},{"id":2140,"depth":242,"text":2141},{"id":2245,"depth":242,"text":2246},{"id":2323,"depth":242,"text":2324},{"id":2346,"depth":236,"text":2347,"children":3176},[3177,3178],{"id":2366,"depth":242,"text":2367},{"id":2464,"depth":242,"text":2465},{"id":2537,"depth":236,"text":2538},{"id":2616,"depth":236,"text":2617,"children":3181},[3182,3183,3184],{"id":2623,"depth":242,"text":2624},{"id":2688,"depth":242,"text":2689},{"id":2877,"depth":242,"text":2878},{"id":2984,"depth":236,"text":2985},{"id":3087,"depth":236,"text":3087},"ตั้งค่า Ubuntu Server 24.04 และ 22.04 หลังติดตั้ง อัปเดตแพ็กเกจ ตั้งเวลา ชื่อเครื่อง SSH และ Firewall พร้อมติดตั้ง Docker, Node.js และเครื่องมือสำหรับ Homelab",{},[3190,3191,3192],"2025-04-15-ubuntu-pro.md","2025-09-19-chuwi-minibook-x.md","2024-01-19-setup-uptime-kuma.md",{"title":1411,"description":3187},{"loc":5,"lastmod":6},"blogs\u002F2024-01-14-setup-ubuntu-server",[945,3197,3198],"Ubuntu","Docker","nyIGIHYmvBK-W0OHd9QfqOXgZ6ZXdi2QrzfQiWHZlUU",{"id":3201,"title":3202,"body":3203,"date":9,"description":3642,"draft":932,"extension":933,"meta":3643,"navigation":935,"next":936,"ogTitle":3202,"path":8,"pin":932,"prev":936,"recommends":3644,"seo":3648,"sitemap":3649,"stem":3650,"tags":3651,"updated":3652,"__hash__":3653},"content\u002Fblogs\u002F2024-01-19-setup-uptime-kuma.md","Setup Uptime Kuma",{"type":123,"value":3204,"toc":3634},[3205,3209,3212,3222,3227,3231,3288,3292,3299,3406,3410,3500,3506,3511,3515,3592,3604,3615,3619,3631],[139,3206,3208],{"id":3207},"introduction","Introduction",[126,3210,3211],{},"โน๊ตนี้คือ วิธีการ setup uptime kuma แบบไม่ใช้ docker",[707,3213,3214],{},[710,3215,3216,3217],{},"สำหรับข้อมูลฉบับเต็มสามารถดูได้ที่ ",[292,3218,3221],{"href":3219,"rel":3220},"https:\u002F\u002Fgithub.com\u002Flouislam\u002Fuptime-kuma",[296],"louislam\u002Fuptime-kuma",[1031,3223,3224],{},[126,3225,3226],{},"อัปเดต 2026-08-09 ตอนที่เขียนโน๊ตนี้ครั้งแรกยังเป็น 1.23.x อยู่ ตอนนี้ 2.x ออกมาแล้วนะ\nเลยกลับมาแก้ส่วนของการอัปเดตให้ตรงกับของจริง",[139,3228,3230],{"id":3229},"_1-basic-setup","1. Basic setup",[164,3232,3235],{"className":3233,"code":3234,"language":2675,"meta":169,"style":169},"language-sh shiki shiki-themes material-theme-lighter one-dark-pro github-dark","sudo apt update && sudo apt upgrade -y\nsudo timedatectl set-timezone Asia\u002FBangkok\n\nsudo apt install curl git -y\n",[171,3236,3237,3260,3270,3274],{"__ignoreMap":169},[174,3238,3239,3241,3243,3246,3249,3252,3254,3257],{"class":176,"line":177},[174,3240,403],{"class":180},[174,3242,1488],{"class":188},[174,3244,3245],{"class":188}," update",[174,3247,3248],{"class":455}," &&",[174,3250,3251],{"class":180}," sudo",[174,3253,1488],{"class":188},[174,3255,3256],{"class":188}," upgrade",[174,3258,3259],{"class":184}," -y\n",[174,3261,3262,3264,3266,3268],{"class":176,"line":236},[174,3263,403],{"class":180},[174,3265,1684],{"class":188},[174,3267,1687],{"class":188},[174,3269,1690],{"class":188},[174,3271,3272],{"class":176,"line":242},[174,3273,2759],{"emptyLinePlaceholder":935},[174,3275,3276,3278,3280,3282,3284,3286],{"class":176,"line":248},[174,3277,403],{"class":180},[174,3279,1488],{"class":188},[174,3281,1605],{"class":188},[174,3283,1608],{"class":188},[174,3285,1614],{"class":188},[174,3287,3259],{"class":184},[139,3289,3291],{"id":3290},"_2-install-nodejs-v22-and-pm2","2. Install nodejs (v.22) and pm2",[126,3293,3294,3295,3298],{},"Uptime Kuma 2.x บังคับ nodejs ตั้งแต่ 20.4.0 ขึ้นไป (ดูได้จาก ",[171,3296,3297],{},"engines"," ใน package.json ของ repo) ลง v.22 ไปเลยก็ได้ครับ",[164,3300,3302],{"className":3233,"code":3301,"language":2675,"meta":169,"style":169},"curl -sL https:\u002F\u002Fdeb.nodesource.com\u002Fsetup_22.x -o \u002Ftmp\u002Fnodesource_setup.sh\n\nsudo bash \u002Ftmp\u002Fnodesource_setup.sh\n\nsudo apt install nodejs\n\n# Verify\nnode -v\n\n# Install pm2\nsudo npm install -g pm2\n\n# Verify\npm2 --version\n",[171,3303,3304,3319,3323,3331,3335,3345,3349,3355,3362,3367,3373,3388,3393,3398],{"__ignoreMap":169},[174,3305,3306,3308,3311,3314,3316],{"class":176,"line":177},[174,3307,2380],{"class":180},[174,3309,3310],{"class":184}," -sL",[174,3312,3313],{"class":188}," https:\u002F\u002Fdeb.nodesource.com\u002Fsetup_22.x",[174,3315,363],{"class":184},[174,3317,3318],{"class":188}," \u002Ftmp\u002Fnodesource_setup.sh\n",[174,3320,3321],{"class":176,"line":236},[174,3322,2759],{"emptyLinePlaceholder":935},[174,3324,3325,3327,3329],{"class":176,"line":242},[174,3326,403],{"class":180},[174,3328,2413],{"class":188},[174,3330,3318],{"class":188},[174,3332,3333],{"class":176,"line":248},[174,3334,2759],{"emptyLinePlaceholder":935},[174,3336,3337,3339,3341,3343],{"class":176,"line":254},[174,3338,403],{"class":180},[174,3340,1488],{"class":188},[174,3342,1605],{"class":188},[174,3344,2426],{"class":188},[174,3346,3347],{"class":176,"line":2112},[174,3348,2759],{"emptyLinePlaceholder":935},[174,3350,3351],{"class":176,"line":2129},[174,3352,3354],{"class":3353},"sDKbk","# Verify\n",[174,3356,3357,3359],{"class":176,"line":2135},[174,3358,2439],{"class":180},[174,3360,3361],{"class":184}," -v\n",[174,3363,3365],{"class":176,"line":3364},9,[174,3366,2759],{"emptyLinePlaceholder":935},[174,3368,3370],{"class":176,"line":3369},10,[174,3371,3372],{"class":3353},"# Install pm2\n",[174,3374,3376,3378,3380,3382,3385],{"class":176,"line":3375},11,[174,3377,403],{"class":180},[174,3379,2489],{"class":188},[174,3381,1605],{"class":188},[174,3383,3384],{"class":184}," -g",[174,3386,3387],{"class":188}," pm2\n",[174,3389,3391],{"class":176,"line":3390},12,[174,3392,2759],{"emptyLinePlaceholder":935},[174,3394,3396],{"class":176,"line":3395},13,[174,3397,3354],{"class":3353},[174,3399,3401,3404],{"class":176,"line":3400},14,[174,3402,3403],{"class":180},"pm2",[174,3405,2442],{"class":184},[139,3407,3409],{"id":3408},"_3-install-uptime-kuma","3. Install Uptime Kuma",[164,3411,3413],{"className":3233,"code":3412,"language":2675,"meta":169,"style":169},"git clone https:\u002F\u002Fgithub.com\u002Flouislam\u002Fuptime-kuma.git\n\ncd uptime-kuma\n\nnpm run setup\n\npm2 install pm2-logrotate\n\npm2 start server\u002Fserver.js --name uptime-kuma\n\npm2 save && pm2 startup\n",[171,3414,3415,3424,3428,3436,3440,3449,3453,3462,3466,3481,3485],{"__ignoreMap":169},[174,3416,3417,3419,3421],{"class":176,"line":177},[174,3418,2712],{"class":180},[174,3420,2715],{"class":188},[174,3422,3423],{"class":188}," https:\u002F\u002Fgithub.com\u002Flouislam\u002Fuptime-kuma.git\n",[174,3425,3426],{"class":176,"line":236},[174,3427,2759],{"emptyLinePlaceholder":935},[174,3429,3430,3433],{"class":176,"line":242},[174,3431,3432],{"class":2078},"cd",[174,3434,3435],{"class":188}," uptime-kuma\n",[174,3437,3438],{"class":176,"line":248},[174,3439,2759],{"emptyLinePlaceholder":935},[174,3441,3442,3444,3446],{"class":176,"line":254},[174,3443,2447],{"class":180},[174,3445,2215],{"class":188},[174,3447,3448],{"class":188}," setup\n",[174,3450,3451],{"class":176,"line":2112},[174,3452,2759],{"emptyLinePlaceholder":935},[174,3454,3455,3457,3459],{"class":176,"line":2129},[174,3456,3403],{"class":180},[174,3458,1605],{"class":188},[174,3460,3461],{"class":188}," pm2-logrotate\n",[174,3463,3464],{"class":176,"line":2135},[174,3465,2759],{"emptyLinePlaceholder":935},[174,3467,3468,3470,3473,3476,3479],{"class":176,"line":3364},[174,3469,3403],{"class":180},[174,3471,3472],{"class":188}," start",[174,3474,3475],{"class":188}," server\u002Fserver.js",[174,3477,3478],{"class":184}," --name",[174,3480,3435],{"class":188},[174,3482,3483],{"class":176,"line":3369},[174,3484,2759],{"emptyLinePlaceholder":935},[174,3486,3487,3489,3492,3494,3497],{"class":176,"line":3375},[174,3488,3403],{"class":180},[174,3490,3491],{"class":188}," save",[174,3493,3248],{"class":455},[174,3495,3496],{"class":180}," pm2",[174,3498,3499],{"class":188}," startup\n",[126,3501,3502,3505],{},[171,3503,3504],{},"npm run setup"," จะ checkout ไปที่ tag ล่าสุดให้เองครับ ไม่ต้องระบุ version เอง ตอนนี้ (2026-08-09) คือ 2.5.0",[126,3507,3508],{},[171,3509,3510],{},"http:\u002F\u002Fip:3001",[139,3512,3514],{"id":3513},"_4-update-uptime-kuma","4. Update Uptime Kuma",[164,3516,3518],{"className":3233,"code":3517,"language":2675,"meta":169,"style":169},"cd uptime-kuma\n\ngit fetch --all\ngit checkout 2.5.0 --force\n\nnpm ci --omit dev\nnpm run download-dist\n\npm2 restart uptime-kuma\n",[171,3519,3520,3526,3530,3540,3553,3557,3570,3579,3583],{"__ignoreMap":169},[174,3521,3522,3524],{"class":176,"line":177},[174,3523,3432],{"class":2078},[174,3525,3435],{"class":188},[174,3527,3528],{"class":176,"line":236},[174,3529,2759],{"emptyLinePlaceholder":935},[174,3531,3532,3534,3537],{"class":176,"line":242},[174,3533,2712],{"class":180},[174,3535,3536],{"class":188}," fetch",[174,3538,3539],{"class":184}," --all\n",[174,3541,3542,3544,3547,3550],{"class":176,"line":248},[174,3543,2712],{"class":180},[174,3545,3546],{"class":188}," checkout",[174,3548,3549],{"class":1982}," 2.5.0",[174,3551,3552],{"class":184}," --force\n",[174,3554,3555],{"class":176,"line":254},[174,3556,2759],{"emptyLinePlaceholder":935},[174,3558,3559,3561,3564,3567],{"class":176,"line":2112},[174,3560,2447],{"class":180},[174,3562,3563],{"class":188}," ci",[174,3565,3566],{"class":184}," --omit",[174,3568,3569],{"class":188}," dev\n",[174,3571,3572,3574,3576],{"class":176,"line":2129},[174,3573,2447],{"class":180},[174,3575,2215],{"class":188},[174,3577,3578],{"class":188}," download-dist\n",[174,3580,3581],{"class":176,"line":2135},[174,3582,2759],{"emptyLinePlaceholder":935},[174,3584,3585,3587,3590],{"class":176,"line":3364},[174,3586,3403],{"class":180},[174,3588,3589],{"class":188}," restart",[174,3591,3435],{"class":188},[126,3593,3594,3595,3598,3599],{},"เลข version ตรง ",[171,3596,3597],{},"git checkout"," เปลี่ยนตามอันล่าสุดได้เลย ดูได้ที่ ",[292,3600,3603],{"href":3601,"rel":3602},"https:\u002F\u002Fgithub.com\u002Flouislam\u002Fuptime-kuma\u002Freleases",[296],"Releases",[1031,3605,3606],{},[126,3607,3608,3609,3614],{},"ถ้าอัปจาก 1.x มา 2.x อันนี้เป็น major version มี breaking changes อยู่ ทาง repo แนะนำให้สำรองข้อมูลก่อน\nแล้วอ่าน ",[292,3610,3613],{"href":3611,"rel":3612},"https:\u002F\u002Fgithub.com\u002Flouislam\u002Fuptime-kuma\u002Fwiki\u002FMigration-From-v1-To-v2",[296],"Migration From v1 To v2"," ให้จบก่อนนะ",[139,3616,3618],{"id":3617},"ref","Ref",[707,3620,3621,3626],{},[710,3622,3623],{},[292,3624,3221],{"href":3219,"rel":3625},[296],[710,3627,3628],{},[292,3629,3603],{"href":3601,"rel":3630},[296],[909,3632,3633],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}",{"title":169,"searchDepth":236,"depth":236,"links":3635},[3636,3637,3638,3639,3640,3641],{"id":3207,"depth":236,"text":3208},{"id":3229,"depth":236,"text":3230},{"id":3290,"depth":236,"text":3291},{"id":3408,"depth":236,"text":3409},{"id":3513,"depth":236,"text":3514},{"id":3617,"depth":236,"text":3618},"วิธีติดตั้ง Uptime Kuma บน Ubuntu แบบไม่ใช้ docker ด้วย nodejs กับ pm2 พร้อมวิธีอัปเดตเป็น version 2.x",{},[3645,3646,3647],"2025-08-26-xponology-on-old-pc.md","2025-11-09-nanokvm-kvm.md","2025-05-12-next-dns.md",{"title":3202,"description":3642},{"loc":8,"lastmod":9},"blogs\u002F2024-01-19-setup-uptime-kuma",[945],"2026-08-09","6GcdZfG3stUkJUSMGiwfW3HSU2Z9Ub7JZODCySaBkCM",{"id":3655,"title":3656,"body":3657,"date":21,"description":3831,"draft":932,"extension":933,"meta":3832,"navigation":935,"next":936,"ogTitle":3833,"path":20,"pin":932,"prev":936,"recommends":3834,"seo":3836,"sitemap":3837,"stem":3842,"tags":3843,"updated":936,"__hash__":3844},"content\u002Fblogs\u002F2025-04-15-ubuntu-pro.md","วิธีการติดตั้ง Ubuntu Version Pro แบบฟรี",{"type":123,"value":3658,"toc":3826},[3659,3662,3672,3676,3735,3745,3749,3763,3770,3773,3778,3783,3793,3798,3805,3808,3811],[126,3660,3661],{},"หลายคนอาจเคยเห็นว่า Ubuntu มีเวอร์ชัน Pro ให้ใช้งาน ไม่ว่าจะในหน้าจอติดตั้งระบบ หรือเป็นหน้าต่างแจ้งเตือนเมื่อเข้าสู่ระบบปฏิบัติการแล้ว",[126,3663,3664,3665,3668,3669],{},"ทาง Ubuntu เปิดให้ใช้งานเวอร์ชัน Pro ได้ฟรี สำหรับผู้ใช้แบบส่วนตัวสูงสุด ",[171,3666,3667],{},"5 active machines"," และสำหรับสมาชิก Ubuntu community สูงสุด ",[171,3670,3671],{},"50 active machines",[139,3673,3675],{"id":3674},"ความแตกต่างหลักระหว่าง-ubuntu-ปกติ-และ-ubuntu-pro","ความแตกต่างหลักระหว่าง Ubuntu ปกติ และ Ubuntu Pro",[592,3677,3678,3691],{},[595,3679,3680],{},[598,3681,3682,3685,3688],{},[601,3683,3684],{},"คุณสมบัติ",[601,3686,3687],{},"Ubuntu ปกติ",[601,3689,3690],{},"Ubuntu Pro (ฟรี)",[608,3692,3693,3704,3715,3724],{},[598,3694,3695,3698,3701],{},[613,3696,3697],{},"ระยะเวลารับอัปเดต",[613,3699,3700],{},"5 ปี",[613,3702,3703],{},"10 ปี",[598,3705,3706,3709,3712],{},[613,3707,3708],{},"Livepatch",[613,3710,3711],{},"-",[613,3713,3714],{},"✓",[598,3716,3717,3720,3722],{},[613,3718,3719],{},"การ hardening ระบบ",[613,3721,3711],{},[613,3723,3714],{},[598,3725,3726,3729,3732],{},[613,3727,3728],{},"จำนวนเครื่องที่รองรับ",[613,3730,3731],{},"ไม่จำกัด",[613,3733,3734],{},"5 เครื่อง (ส่วนตัว)",[1031,3736,3737],{},[126,3738,3739,3740,3744],{},"สามารถอ่านเพิ่มเติมได้ที่ ",[292,3741,3742],{"href":3742,"rel":3743},"https:\u002F\u002Fubuntu.com\u002Fpricing\u002Fpro",[296]," ตรง Ubuntu Pro for personal users",[139,3746,3748],{"id":3747},"ขั้นตอนการกดรับ-license","ขั้นตอนการกดรับ License",[812,3750,3751],{},[710,3752,3753,3754,3758,3759],{},"สมัคร account ที่ ",[292,3755,3756],{"href":3756,"rel":3757},"https:\u002F\u002Fubuntu.com",[296]," ให้เรียบร้อยจากนั้นไปที่หน้า ",[292,3760,3761],{"href":3761,"rel":3762},"https:\u002F\u002Fubuntu.com\u002Fpro",[296],[126,3764,3765],{},[3766,3767],"img",{"alt":3768,"src":3769},"Ubuntu Pro","\u002Fimages\u002F2025-04-15-ubuntu-pro\u002Fimage-1.png",[126,3771,3772],{},"แล้วกดที่ปุ่ม \"Get Ubuntu Pro now\" ได้เลยครับ",[812,3774,3775],{"start":236},[710,3776,3777],{},"จากนั้นเลือกเป็น \"Myself\" ได้เลยครับ จะเป็นการกดรับ license free กด continue to card ได้เลย",[126,3779,3780],{},[3766,3781],{"alt":3768,"src":3782},"\u002Fimages\u002F2025-04-15-ubuntu-pro\u002Fimage-2.png",[812,3784,3785],{"start":242},[710,3786,3787,3788,3792],{},"เมื่อเสร็จสิ้นขั้นตอนให้ไปยัง ",[292,3789,3790],{"href":3790,"rel":3791},"https:\u002F\u002Fubuntu.com\u002Fpro\u002Fdashboard",[296]," ตรงเมนู \"Your subscriptions\" จะเจอกับ Token ซึ่งสามารถนำไปใช้งานได้เลยครับ",[126,3794,3795],{},[3766,3796],{"alt":3768,"src":3797},"\u002Fimages\u002F2025-04-15-ubuntu-pro\u002Fimage-3.png",[126,3799,3800,3801,3804],{},"หากเป็นการติดตั้งระบบปฏิบัติการใหม่ สามารถกรอก Token ได้ในขั้นตอนติดตั้ง แต่หากติดตั้ง Ubuntu ไปแล้ว สามารถใช้คำสั่ง ",[171,3802,3803],{},"sudo pro attach \u003CTOKEN>"," เพื่อเปิดใช้งาน License ได้เลย",[3806,3807],"hr",{},[139,3809,3810],{"id":3810},"แหล่งข้อมูลเพิ่มเติม",[707,3812,3813,3820],{},[710,3814,3815],{},[292,3816,3819],{"href":3817,"rel":3818},"https:\u002F\u002Fubuntu.com\u002Flegal\u002Fubuntu-pro\u002Fpersonal",[296],"Ubuntu Pro for Personal Use",[710,3821,3822],{},[292,3823,3825],{"href":3742,"rel":3824},[296],"Ubuntu Pro Pricing",{"title":169,"searchDepth":236,"depth":236,"links":3827},[3828,3829,3830],{"id":3674,"depth":236,"text":3675},{"id":3747,"depth":236,"text":3748},{"id":3810,"depth":236,"text":3810},"วิธีขอและเปิดใช้ Ubuntu Pro ฟรีสำหรับ personal use สูงสุด 5 เครื่อง ได้อัปเดตความปลอดภัยยาว 10 ปี",{},"Ubuntu Pro Version",[3835,3191,3646],"2024-01-14-setup-ubuntu-server.md",{"title":3656,"description":3831},{"loc":20,"images":3838,"lastmod":21},[3839,3840,3841],{"loc":3769},{"loc":3782},{"loc":3797},"blogs\u002F2025-04-15-ubuntu-pro",[945],"elUfxkOeezYR2yU5HZWnSheM0uci3G9iW-DdAqrFawQ",{"id":3846,"title":3847,"body":3848,"date":24,"description":4629,"draft":932,"extension":933,"meta":4630,"navigation":935,"next":4631,"ogTitle":4632,"path":23,"pin":932,"prev":936,"recommends":4633,"seo":4635,"sitemap":4636,"stem":4643,"tags":4644,"updated":936,"__hash__":4645},"content\u002Fblogs\u002F2025-04-24-n8n-part-1.md","N8N วิธีการ Setup | Part 1",{"type":123,"value":3849,"toc":4618},[3850,3854,3857,3860,3864,3880,3883,3887,3910,3914,3926,4217,4227,4246,4249,4281,4298,4302,4309,4314,4476,4479,4542,4545,4552,4557,4560,4565,4568,4572,4578,4581,4586,4597,4602,4609,4615],[139,3851,3853],{"id":3852},"n8n-คืออะไร","N8N คืออะไร",[126,3855,3856],{},"คือ Platform สำหรับทำ workflow automation หรือพูดให้เข้าใจง่าย ๆ ก็คือพวกระบบอัตโนมัติต่าง ๆ นั้นแหละครับ ซึ่งจุดเด่นของเครื่องมือตัวนี้คือเป็น Open Source มีทั้ง version cloud และ self-hosted ให้ใช้งานสำหรับคนที่เป็นห่วงเรื่องความปลอดภัยของข้อมูลครับ อีกทั้งยังเป็น platform ที่อยู่ในรูปแบบของ Low Code หรือ No Code เลยก็ได้ (ในบาง workflows)",[126,3858,3859],{},"ซึ่งผมเองในฐานะของคนที่ชอบเขียนโปรแกรมอยู่แล้ว ต้องบอกเลยว่า \"ของดีย์\" ครับ ทำให้หลาย ๆ ไอเดียสามารถทำออกมาได้เลย ลดเวลาในการพัฒนาลงได้เยอะครับ ผมเองมองว่าการมีสกิล workflows ติดตัวไว้ถือเป็นข้อได้เปรียบนึงเลยครับ โดยซีรีย์นี้ตั้งใจว่าจะทำออกมาแบ่งเป็น EP ย่อย ๆ ครับแชร์ทริคต่าง ๆ ที่ได้ศึกษามา ยังไงก็ฝากติดตตามด้วยนะครับ เย่ ~",[139,3861,3863],{"id":3862},"requirements","Requirements",[707,3865,3866,3872,3877],{},[710,3867,3868,3869],{},"Docker version 25.x.x ขึ้นไป ",[171,3870,3871],{},"docker --version",[710,3873,3874,3875,303],{},"Docker Compose version 2.24.x ขึ้นไป (",[171,3876,2241],{},[710,3878,3879],{},"ความรู้พื้นฐาน (มาก ๆ) ของ docker cli",[139,3881,3882],{"id":3882},"วิธีการติดตั้ง",[153,3884,3886],{"id":3885},"_1-สร้าง-directory-และ-docker-compose-file-สำหรับทดสอบ","1. สร้าง Directory และ docker compose file สำหรับทดสอบ",[164,3888,3890],{"className":3233,"code":3889,"language":2675,"meta":169,"style":169},"mkdir n8n-labs\n\ncd n8n-labs\n",[171,3891,3892,3900,3904],{"__ignoreMap":169},[174,3893,3894,3897],{"class":176,"line":177},[174,3895,3896],{"class":180},"mkdir",[174,3898,3899],{"class":188}," n8n-labs\n",[174,3901,3902],{"class":176,"line":236},[174,3903,2759],{"emptyLinePlaceholder":935},[174,3905,3906,3908],{"class":176,"line":242},[174,3907,3432],{"class":2078},[174,3909,3899],{"class":188},[153,3911,3913],{"id":3912},"_2-สร้าง-docker-compose-file","2. สร้าง docker compose file",[164,3915,3917],{"className":3233,"code":3916,"language":2675,"meta":169,"style":169},"nano docker-compose.yml\n",[171,3918,3919],{"__ignoreMap":169},[174,3920,3921,3923],{"class":176,"line":177},[174,3922,2810],{"class":180},[174,3924,3925],{"class":188}," docker-compose.yml\n",[164,3927,3931],{"className":3928,"code":3929,"language":3930,"meta":169,"style":169},"language-yml shiki shiki-themes material-theme-lighter one-dark-pro github-dark","services:\n  n8n:\n    image: docker.n8n.io\u002Fn8nio\u002Fn8n\n    restart: unless-stopped\n    ports:\n      - '127.0.0.1:5678:5678'\n    volumes:\n      - n8n_data:\u002Fhome\u002Fnode\u002F.n8n\n      - n8n_local_files:\u002Ffiles\n    environment:\n      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}\n      - N8N_PORT=5678\n      - N8N_PROTOCOL=https\n      - NODE_ENV=production\n      - WEBHOOK_URL=https:\u002F\u002F${WEBHOOK_SUBDOMAIN}.${DOMAIN_NAME}\u002F\n      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}\n      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true\n\n  pg-vector:\n    image: pgvector\u002Fpgvector:pg17\n    restart: unless-stopped\n    environment:\n      POSTGRES_USER: \u003Cusername>\n      POSTGRES_PASSWORD: \u003Cpassword>\n      POSTGRES_DB: n8n-pgvector\n    ports:\n      - '127.0.0.1:5432:5432'\n    volumes:\n      - db-pgvector-data:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n\nvolumes:\n  n8n_data:\n  n8n_local_files:\n  db-data:\n  db-pgvector-data:\n","yml",[171,3932,3933,3940,3947,3957,3967,3974,3986,3993,4000,4007,4014,4021,4028,4035,4042,4050,4058,4066,4071,4079,4089,4098,4105,4116,4127,4138,4145,4157,4164,4172,4177,4185,4193,4201,4209],{"__ignoreMap":169},[174,3934,3935,3938],{"class":176,"line":177},[174,3936,3937],{"class":3020},"services",[174,3939,3024],{"class":455},[174,3941,3942,3945],{"class":176,"line":236},[174,3943,3944],{"class":3020},"  n8n",[174,3946,3024],{"class":455},[174,3948,3949,3952,3954],{"class":176,"line":242},[174,3950,3951],{"class":3020},"    image",[174,3953,471],{"class":455},[174,3955,3956],{"class":188}," docker.n8n.io\u002Fn8nio\u002Fn8n\n",[174,3958,3959,3962,3964],{"class":176,"line":248},[174,3960,3961],{"class":3020},"    restart",[174,3963,471],{"class":455},[174,3965,3966],{"class":188}," unless-stopped\n",[174,3968,3969,3972],{"class":176,"line":254},[174,3970,3971],{"class":3020},"    ports",[174,3973,3024],{"class":455},[174,3975,3976,3979,3981,3984],{"class":176,"line":2112},[174,3977,3978],{"class":455},"      -",[174,3980,373],{"class":372},[174,3982,3983],{"class":188},"127.0.0.1:5678:5678",[174,3985,379],{"class":372},[174,3987,3988,3991],{"class":176,"line":2129},[174,3989,3990],{"class":3020},"    volumes",[174,3992,3024],{"class":455},[174,3994,3995,3997],{"class":176,"line":2135},[174,3996,3978],{"class":455},[174,3998,3999],{"class":188}," n8n_data:\u002Fhome\u002Fnode\u002F.n8n\n",[174,4001,4002,4004],{"class":176,"line":3364},[174,4003,3978],{"class":455},[174,4005,4006],{"class":188}," n8n_local_files:\u002Ffiles\n",[174,4008,4009,4012],{"class":176,"line":3369},[174,4010,4011],{"class":3020},"    environment",[174,4013,3024],{"class":455},[174,4015,4016,4018],{"class":176,"line":3375},[174,4017,3978],{"class":455},[174,4019,4020],{"class":188}," N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}\n",[174,4022,4023,4025],{"class":176,"line":3390},[174,4024,3978],{"class":455},[174,4026,4027],{"class":188}," N8N_PORT=5678\n",[174,4029,4030,4032],{"class":176,"line":3395},[174,4031,3978],{"class":455},[174,4033,4034],{"class":188}," N8N_PROTOCOL=https\n",[174,4036,4037,4039],{"class":176,"line":3400},[174,4038,3978],{"class":455},[174,4040,4041],{"class":188}," NODE_ENV=production\n",[174,4043,4045,4047],{"class":176,"line":4044},15,[174,4046,3978],{"class":455},[174,4048,4049],{"class":188}," WEBHOOK_URL=https:\u002F\u002F${WEBHOOK_SUBDOMAIN}.${DOMAIN_NAME}\u002F\n",[174,4051,4053,4055],{"class":176,"line":4052},16,[174,4054,3978],{"class":455},[174,4056,4057],{"class":188}," GENERIC_TIMEZONE=${GENERIC_TIMEZONE}\n",[174,4059,4061,4063],{"class":176,"line":4060},17,[174,4062,3978],{"class":455},[174,4064,4065],{"class":188}," N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true\n",[174,4067,4069],{"class":176,"line":4068},18,[174,4070,2759],{"emptyLinePlaceholder":935},[174,4072,4074,4077],{"class":176,"line":4073},19,[174,4075,4076],{"class":3020},"  pg-vector",[174,4078,3024],{"class":455},[174,4080,4082,4084,4086],{"class":176,"line":4081},20,[174,4083,3951],{"class":3020},[174,4085,471],{"class":455},[174,4087,4088],{"class":188}," pgvector\u002Fpgvector:pg17\n",[174,4090,4092,4094,4096],{"class":176,"line":4091},21,[174,4093,3961],{"class":3020},[174,4095,471],{"class":455},[174,4097,3966],{"class":188},[174,4099,4101,4103],{"class":176,"line":4100},22,[174,4102,4011],{"class":3020},[174,4104,3024],{"class":455},[174,4106,4108,4111,4113],{"class":176,"line":4107},23,[174,4109,4110],{"class":3020},"      POSTGRES_USER",[174,4112,471],{"class":455},[174,4114,4115],{"class":188}," \u003Cusername>\n",[174,4117,4119,4122,4124],{"class":176,"line":4118},24,[174,4120,4121],{"class":3020},"      POSTGRES_PASSWORD",[174,4123,471],{"class":455},[174,4125,4126],{"class":188}," \u003Cpassword>\n",[174,4128,4130,4133,4135],{"class":176,"line":4129},25,[174,4131,4132],{"class":3020},"      POSTGRES_DB",[174,4134,471],{"class":455},[174,4136,4137],{"class":188}," n8n-pgvector\n",[174,4139,4141,4143],{"class":176,"line":4140},26,[174,4142,3971],{"class":3020},[174,4144,3024],{"class":455},[174,4146,4148,4150,4152,4155],{"class":176,"line":4147},27,[174,4149,3978],{"class":455},[174,4151,373],{"class":372},[174,4153,4154],{"class":188},"127.0.0.1:5432:5432",[174,4156,379],{"class":372},[174,4158,4160,4162],{"class":176,"line":4159},28,[174,4161,3990],{"class":3020},[174,4163,3024],{"class":455},[174,4165,4167,4169],{"class":176,"line":4166},29,[174,4168,3978],{"class":455},[174,4170,4171],{"class":188}," db-pgvector-data:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n",[174,4173,4175],{"class":176,"line":4174},30,[174,4176,2759],{"emptyLinePlaceholder":935},[174,4178,4180,4183],{"class":176,"line":4179},31,[174,4181,4182],{"class":3020},"volumes",[174,4184,3024],{"class":455},[174,4186,4188,4191],{"class":176,"line":4187},32,[174,4189,4190],{"class":3020},"  n8n_data",[174,4192,3024],{"class":455},[174,4194,4196,4199],{"class":176,"line":4195},33,[174,4197,4198],{"class":3020},"  n8n_local_files",[174,4200,3024],{"class":455},[174,4202,4204,4207],{"class":176,"line":4203},34,[174,4205,4206],{"class":3020},"  db-data",[174,4208,3024],{"class":455},[174,4210,4212,4215],{"class":176,"line":4211},35,[174,4213,4214],{"class":3020},"  db-pgvector-data",[174,4216,3024],{"class":455},[126,4218,4219,4220,847,4223,4226],{},"โดยในส่วนของ ",[171,4221,4222],{},"POSTGRES_USER",[171,4224,4225],{},"POSTGRES_PASSWORD"," ให้แก้ไขเป็นค่าที่ปลอดภัยได้เลย หรือจะ generate ด้วย openssl ก็ได้เช่นกันครับ",[164,4228,4230],{"className":3233,"code":4229,"language":2675,"meta":169,"style":169},"openssl rand -base64 32\n",[171,4231,4232],{"__ignoreMap":169},[174,4233,4234,4237,4240,4243],{"class":176,"line":177},[174,4235,4236],{"class":180},"openssl",[174,4238,4239],{"class":188}," rand",[174,4241,4242],{"class":184}," -base64",[174,4244,4245],{"class":1982}," 32\n",[126,4247,4248],{},"หน้าตาหลังจากแก้ไขจะเป็นประมาณนี้",[164,4250,4252],{"className":3928,"code":4251,"language":3930,"meta":169,"style":169},"environment:\n  POSTGRES_USER: username\n  POSTGRES_PASSWORD: VygpX7KBx2LsLTLoIk84YPV+gBsVZzgfMqVm+Kv0ltM=\n",[171,4253,4254,4261,4271],{"__ignoreMap":169},[174,4255,4256,4259],{"class":176,"line":177},[174,4257,4258],{"class":3020},"environment",[174,4260,3024],{"class":455},[174,4262,4263,4266,4268],{"class":176,"line":236},[174,4264,4265],{"class":3020},"  POSTGRES_USER",[174,4267,471],{"class":455},[174,4269,4270],{"class":188}," username\n",[174,4272,4273,4276,4278],{"class":176,"line":242},[174,4274,4275],{"class":3020},"  POSTGRES_PASSWORD",[174,4277,471],{"class":455},[174,4279,4280],{"class":188}," VygpX7KBx2LsLTLoIk84YPV+gBsVZzgfMqVm+Kv0ltM=\n",[126,4282,4283,4284,4286,4287,4290,4291,4290,4294,4297],{},"จากนั้น (หากใช้ ",[171,4285,2810],{},") แก้ไขไฟล์ให้กด ",[171,4288,4289],{},"CTRL + X"," -> ",[171,4292,4293],{},"Y",[171,4295,4296],{},"Enter"," จะเป็นการบันทึกและออกจากไฟล์",[153,4299,4301],{"id":4300},"_3-กำหนดค่าให้-env","3. กำหนดค่าให้ .env",[126,4303,4304,4305,4308],{},"สร้างไฟล์ ",[171,4306,4307],{},".env"," และทำการแก้ไขค่าต่าง ๆ",[1031,4310,4311],{},[126,4312,4313],{},"DOMAIN_NAME, SUBDOMAIN, WEBHOOK_SUBDOMAIN ในส่วนนี้อาจจะปล่อยเป็นค่า default แบบนี้ไปก่อนครับ",[164,4315,4317],{"className":3233,"code":4316,"language":2675,"meta":169,"style":169},"NODE_ENV=\"production\"\nN8N_PROTOCOL=\"http\" # or https\nN8N_DIAGNOSTICS_ENABLED=false\nGENERIC_TIMEZONE=\"Asia\u002FBangkok\"\nDOMAIN_NAME=localhost\nSUBDOMAIN=\nWEBHOOK_SUBDOMAIN=\nN8N_RUNNERS_ENABLED=true\n\nEXECUTIONS_DATA_PRUNE=true\nEXECUTIONS_DATA_MAX_AGE=168\nEXECUTIONS_DATA_PRUNE_MAX_COUNT=50000\n\nPG_USER=\u003Cusername>\nPG_PASSWORD=\u003Cpassword>\n",[171,4318,4319,4334,4351,4361,4374,4384,4392,4399,4409,4413,4422,4432,4442,4446,4462],{"__ignoreMap":169},[174,4320,4321,4324,4327,4329,4332],{"class":176,"line":177},[174,4322,4323],{"class":2094},"NODE_ENV",[174,4325,4326],{"class":1539},"=",[174,4328,468],{"class":372},[174,4330,4331],{"class":188},"production",[174,4333,2278],{"class":372},[174,4335,4336,4339,4341,4343,4346,4348],{"class":176,"line":236},[174,4337,4338],{"class":2094},"N8N_PROTOCOL",[174,4340,4326],{"class":1539},[174,4342,468],{"class":372},[174,4344,4345],{"class":188},"http",[174,4347,468],{"class":372},[174,4349,4350],{"class":3353}," # or https\n",[174,4352,4353,4356,4358],{"class":176,"line":242},[174,4354,4355],{"class":2094},"N8N_DIAGNOSTICS_ENABLED",[174,4357,4326],{"class":1539},[174,4359,4360],{"class":188},"false\n",[174,4362,4363,4366,4368,4370,4372],{"class":176,"line":248},[174,4364,4365],{"class":2094},"GENERIC_TIMEZONE",[174,4367,4326],{"class":1539},[174,4369,468],{"class":372},[174,4371,1671],{"class":188},[174,4373,2278],{"class":372},[174,4375,4376,4379,4381],{"class":176,"line":254},[174,4377,4378],{"class":2094},"DOMAIN_NAME",[174,4380,4326],{"class":1539},[174,4382,4383],{"class":188},"localhost\n",[174,4385,4386,4389],{"class":176,"line":2112},[174,4387,4388],{"class":2094},"SUBDOMAIN",[174,4390,4391],{"class":1539},"=\n",[174,4393,4394,4397],{"class":176,"line":2129},[174,4395,4396],{"class":2094},"WEBHOOK_SUBDOMAIN",[174,4398,4391],{"class":1539},[174,4400,4401,4404,4406],{"class":176,"line":2135},[174,4402,4403],{"class":2094},"N8N_RUNNERS_ENABLED",[174,4405,4326],{"class":1539},[174,4407,4408],{"class":188},"true\n",[174,4410,4411],{"class":176,"line":3364},[174,4412,2759],{"emptyLinePlaceholder":935},[174,4414,4415,4418,4420],{"class":176,"line":3369},[174,4416,4417],{"class":2094},"EXECUTIONS_DATA_PRUNE",[174,4419,4326],{"class":1539},[174,4421,4408],{"class":188},[174,4423,4424,4427,4429],{"class":176,"line":3375},[174,4425,4426],{"class":2094},"EXECUTIONS_DATA_MAX_AGE",[174,4428,4326],{"class":1539},[174,4430,4431],{"class":188},"168\n",[174,4433,4434,4437,4439],{"class":176,"line":3390},[174,4435,4436],{"class":2094},"EXECUTIONS_DATA_PRUNE_MAX_COUNT",[174,4438,4326],{"class":1539},[174,4440,4441],{"class":188},"50000\n",[174,4443,4444],{"class":176,"line":3395},[174,4445,2759],{"emptyLinePlaceholder":935},[174,4447,4448,4451,4453,4456,4459],{"class":176,"line":3400},[174,4449,4450],{"class":2094},"PG_USER",[174,4452,4326],{"class":1539},[174,4454,4455],{"class":2046},"\u003C",[174,4457,4458],{"class":188},"username",[174,4460,4461],{"class":2046},">\n",[174,4463,4464,4467,4469,4471,4474],{"class":176,"line":4044},[174,4465,4466],{"class":2094},"PG_PASSWORD",[174,4468,4326],{"class":1539},[174,4470,4455],{"class":2046},[174,4472,4473],{"class":188},"password",[174,4475,4461],{"class":2046},[126,4477,4478],{},"จากนั้นสามารถ start docker compose ได้เลยด้วยคำสั่ง",[164,4480,4482],{"className":3233,"code":4481,"language":2675,"meta":169,"style":169},"docker compose pull\n\n# [+] Pulling 15\u002F29\n# ⠧ pg-vector [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀] Pulling                              13.8s\n# ⠧ n8n [⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀] Pulling                                         13.8s\n\ndocker compose --env-file .env up --build -d\n# อย่าลืม --env-file flag นะครับ\n",[171,4483,4484,4493,4497,4502,4507,4512,4516,4537],{"__ignoreMap":169},[174,4485,4486,4488,4490],{"class":176,"line":177},[174,4487,2226],{"class":180},[174,4489,2229],{"class":188},[174,4491,4492],{"class":188}," pull\n",[174,4494,4495],{"class":176,"line":236},[174,4496,2759],{"emptyLinePlaceholder":935},[174,4498,4499],{"class":176,"line":242},[174,4500,4501],{"class":3353},"# [+] Pulling 15\u002F29\n",[174,4503,4504],{"class":176,"line":248},[174,4505,4506],{"class":3353},"# ⠧ pg-vector [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀] Pulling                              13.8s\n",[174,4508,4509],{"class":176,"line":254},[174,4510,4511],{"class":3353},"# ⠧ n8n [⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀] Pulling                                         13.8s\n",[174,4513,4514],{"class":176,"line":2112},[174,4515,2759],{"emptyLinePlaceholder":935},[174,4517,4518,4520,4522,4525,4528,4531,4534],{"class":176,"line":2129},[174,4519,2226],{"class":180},[174,4521,2229],{"class":188},[174,4523,4524],{"class":184}," --env-file",[174,4526,4527],{"class":188}," .env",[174,4529,4530],{"class":188}," up",[174,4532,4533],{"class":184}," --build",[174,4535,4536],{"class":184}," -d\n",[174,4538,4539],{"class":176,"line":2135},[174,4540,4541],{"class":3353},"# อย่าลืม --env-file flag นะครับ\n",[153,4543,4544],{"id":4544},"ทดสอบเปิดเข้าใช้งาน",[126,4546,4547,4548,4551],{},"จากนั้นเปิด browser แล้วไปที่ ",[171,4549,4550],{},"http:\u002F\u002Flocalhost:5678\u002Fsetup"," ได้เลยครับ",[126,4553,4554],{},[3766,4555],{"alt":169,"src":4556},"\u002Fimages\u002F2025-04-24-n8n-part-1\u002Fn8n-setup.png",[126,4558,4559],{},"โดยในขั้นตอนนี้เป็น optional ครับ แต่แนะนำให้เอากดรับมาครับ",[126,4561,4562],{},[3766,4563],{"alt":169,"src":4564},"\u002Fimages\u002F2025-04-24-n8n-part-1\u002Fpaid-features-for-free.png",[126,4566,4567],{},"เรียบร้อยครับ เพียงแค่นี้เราก็จะได้ N8N version self-hosted มาใช้งานแล้วครับ",[153,4569,4571],{"id":4570},"_4-ทดสอบเพิ่ม-pgvector-เข้าไปยัง-n8n","4. ทดสอบเพิ่ม PGVector เข้าไปยัง N8N",[126,4573,4574,4575],{},"ไปที่เมนู Credential\n",[3766,4576],{"alt":169,"src":4577},"\u002Fimages\u002F2025-04-24-n8n-part-1\u002Fn8n-credential-1.png",[126,4579,4580],{},"เลือกเป็น Postgres",[126,4582,4583],{},[3766,4584],{"alt":169,"src":4585},"\u002Fimages\u002F2025-04-24-n8n-part-1\u002Fn8n-credential-2.png",[126,4587,4588,4589,4592,4593,4596],{},"กรอกข้อมูล โดยผมจะทำการแก้ชื่อด้านซ้ายบนให้เป็น ",[171,4590,4591],{},"PG-Vector"," นะครับ ในช่องของ database ถ้า setup ตามที่ผมแนะนำไว้ก็สามารถใส่เป็น",[171,4594,4595],{},"pg-vector"," (service name ใน docker-compose) และใส่ username, password จากไฟล์ .env และ Database เอามาจากไฟล์ docker-compose ได้เลยครับ",[126,4598,4599],{},[3766,4600],{"alt":169,"src":4601},"\u002Fimages\u002F2025-04-24-n8n-part-1\u002Fn8n-credential-3.png",[126,4603,4604,4605,4608],{},"ถ้ากด Save แล้วขึ้น ",[171,4606,4607],{},"Connection Tested Successfully"," แสดงว่าใช้งานได้แล้วครับ โดยตัว PG Vector อันนี้จะเป็นตัว Postgres ที่มีการเปิดใช้งาน extension vector ซึ่งเดี๋ยวเราจะเอามาใช้ในการเล่นเกี่ยว LLM ต่อไปนะครับ",[126,4610,4611,4612],{},"สามารถอ่าน Part 2 ต่อได้เลย\n",[292,4613,4614],{"href":29},"N8N Part 2",[909,4616,4617],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s0Prt, html code.shiki .s0Prt{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#85E89D}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}",{"title":169,"searchDepth":236,"depth":236,"links":4619},[4620,4621,4622],{"id":3852,"depth":236,"text":3853},{"id":3862,"depth":236,"text":3863},{"id":3882,"depth":236,"text":3882,"children":4623},[4624,4625,4626,4627,4628],{"id":3885,"depth":242,"text":3886},{"id":3912,"depth":242,"text":3913},{"id":4300,"depth":242,"text":4301},{"id":4544,"depth":242,"text":4544},{"id":4570,"depth":242,"text":4571},"วิธี self-hosted N8N ด้วย docker compose อย่างง่าย พร้อมต่อ PGVector ไว้ใช้กับงาน LLM ในภายหลัง",{},"2025-04-28-n8n-part-2.md","Awesome N8N",[4634,939],"2025-05-10-n8n-with-telegram-notify.md",{"title":3847,"description":4629},{"loc":23,"images":4637,"lastmod":24},[4638,4639,4640,4641,4642],{"loc":4556},{"loc":4564},{"loc":4577},{"loc":4585},{"loc":4601},"blogs\u002F2025-04-24-n8n-part-1",[944],"aLiJnB6fTsYhfkyOxJPZE_Mo8Lzzx6DFkMhK9VPFSXg",{"id":4647,"title":4648,"body":4649,"date":30,"description":5400,"draft":932,"extension":933,"meta":5401,"navigation":935,"next":936,"ogTitle":4632,"path":29,"pin":932,"prev":5402,"recommends":5403,"seo":5404,"sitemap":5405,"stem":5427,"tags":5428,"updated":936,"__hash__":5429},"content\u002Fblogs\u002F2025-04-28-n8n-part-2.md","N8N วิธีการการใช้งานเบื้องต้น | Part 2",{"type":123,"value":4650,"toc":5394},[4651,4657,4660,4670,4674,4678,4683,4686,4691,4694,4698,4701,4712,4717,4720,4723,4728,4731,4736,4739,4744,4747,4767,4772,4779,4784,4787,4792,4795,4800,4803,4868,4871,4922,4925,4931,5010,5013,5018,5021,5331,5334,5339,5342,5348,5355,5360,5363,5368,5374,5380,5383,5388,5391],[126,4652,4653,4654],{},"สำหรับใครที่ยังไม่ได้อ่าน Part 1 นะครับ สามารถไปอ่านได้ที่ ",[292,4655,4656],{"href":23},"N8N Part 1",[126,4658,4659],{},"โดยวันนี้ผมจะพามาลองเล่น workflow ในแบบ basic ๆ กันก่อนนะครับ เผื่อให้สามารถเข้าใจการทำงานในเบื้องต้นได้",[126,4661,4662,4663,4666,4667],{},"โดยโจทย์ในครั้งนี้คือ ",[390,4664,4665],{},"\"ค้นหา URLs ต่าง ๆ ของ domain ที่ต้องการโดยใช้ Wayback machine\""," ถ้านึกภาพไม่ออกคือการทำแบบนี้แหละครับ แต่เราจะทำให้มันเป็น workflow เพื่อนำไปต่อยอดในอนาคตนะครับ\n",[3766,4668],{"alt":169,"src":4669},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-4.png",[139,4671,4673],{"id":4672},"เริ่มต้นการสร้าง-workflows","เริ่มต้นการสร้าง workflows",[153,4675,4677],{"id":4676},"ทำการสร้าง-workflow-ใหม่โดยการกดที่ปุ่มขวาบน-create-workflow-ได้เลยครับ","ทำการสร้าง workflow ใหม่โดยการกดที่ปุ่มขวาบน (\"Create Workflow\") ได้เลยครับ",[126,4679,4680],{},[3766,4681],{"alt":169,"src":4682},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage.png",[126,4684,4685],{},"จากนั้นจะพบกับ UI หน้าตาโล่ง ๆ แบบนี้",[126,4687,4688],{},[3766,4689],{"alt":169,"src":4690},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-1.png",[126,4692,4693],{},"โดยเมื่อกดปุ่ม \"+\" กลางจอหรือมุมขวาบนแล้วจะพบกับ Trigger Node ครับ (ภายใน N8N เราจะเรียกเครื่องมือแต่ละตัวว่า Node นะครับ)",[153,4695,4697],{"id":4696},"อธิบายคร่าว-ๆ-ของ-trigger-node-ประมาณนี้ครับ","อธิบายคร่าว ๆ ของ Trigger Node ประมาณนี้ครับ",[126,4699,4700],{},"Trigger Node คือจุดเริ่มต้นของ workflow ซึ่งสามารถทำได้หลายวิธีด้วยกันขึ้นอยู่กับจุดประสงค์ของ workflow นั้น ๆ ครับ เช่นหากเป็นประเภท Scheduler จะใช้ประเภท \"On a scheduler\" หากเป็นประเภท Webhook ที่รอรับสัญญาณจากแหล่งอื่นจะใช้เป็น \"On webhook call\" ครับ ยังมีอีกหลาย ๆ ตัวที่น่าสนใจเช่น",[707,4702,4703,4706,4709],{},[710,4704,4705],{},"On chat message: Node นี้จะเป็นการสร้างหน้า chat ui ขึ้นมาให้ครับ เหมาะสำหรับการนำมาใช้งานกับ AI Agent นั้นเอง",[710,4707,4708],{},"On app event: Node นี้จะเป็นการรับ trigger จาก application อื่น ๆ ที่นำมาเชื่อมต่อครับ เช่น notion, telegram, airtable ซึ่งจำเป็นต้องเชื่อมต่อกันให้เรียบร้อยก่อนใช้งาน",[710,4710,4711],{},"Trigger manual: Node นี้เป็นการสร้างปุ่มขึ้นมาให้กดครับ เหมาะสำหรับการใช้งานที่จำเป็นต้องกรอกข้อมูลก่อน หรือ ไม่ได้อยากทำให้มี external trigger มาครับ",[126,4713,4714],{},[3766,4715],{"alt":169,"src":4716},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-2.png",[126,4718,4719],{},"ซึ่งอันนี้เป็นแค่เพียงเบื้องต้นนะครับ จริง ๆ แล้ว N8N ยังสามารถทำอะไรได้มากกว่านั้นอีก (มากกกก) ไปกันต่อเลยครับ",[126,4721,4722],{},"โดยผมจะเริ่มจาก Trigger เบื้องต้นอย่าง \"Trigger manually\" ละกันครับ สามารถกดเลือกได้เลยครับ เมื่อเลือกแล้วจะมี Node โผล่มากลางจอแบบนี้ครับ",[126,4724,4725],{},[3766,4726],{"alt":169,"src":4727},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-3.png",[126,4729,4730],{},"จากนั้นให้กดปุ่ม \"+\" ที่อยู่ขวามือของ Node เพื่อเพิ่มการทำงานขั้นต่อไปครับ เมื่อกดแล้วจะเพิ่มกับเครื่องมือต่าง ๆ ที่สามารถนำมาใช้ต่อได้นะครับ \"ซึ่งมีเยอะมากกกก\"",[126,4732,4733],{},[3766,4734],{"alt":169,"src":4735},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-5.png",[126,4737,4738],{},"โดยให้เราเลือกเป็น \"HTTP Request\" ครับ",[126,4740,4741],{},[3766,4742],{"alt":169,"src":4743},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-7.png",[126,4745,4746],{},"จากนั้นจะพบกับหน้าต่างที่โผล่ขึ้นมาซึ่งจะแบ่งเป็น 3 ส่วนหลัก ๆ คือ",[812,4748,4749,4755,4761],{},[710,4750,4751,4754],{},[174,4752,4753],{},"ซ้าย"," Input: เป็นส่วนที่ไว้ใช้แสดงผลข้อมูลที่มาจาก workflows การหน้าครับ",[710,4756,4757,4760],{},[174,4758,4759],{},"กลาง"," Settings: เป็นการตั้งค่าของ Node นั้น ๆ ซึ่งจะขึ้นอยู่กับว่าเป็น Node อะไร ในกรณีจะมี \"Method\", \"URL\", \"Authentication\" และอื่น ๆ ตามด้านล่างเลยครับ ซึ่งก็คือรูปแบบการ Call HTTP request ปกติเลย",[710,4762,4763,4766],{},[174,4764,4765],{},"ขวา"," Output: เป็นส่วนที่ไว้ใช้แสดงผลข้อมูลที่ได้จาก Node นี้ครับ",[126,4768,4769],{},[3766,4770],{"alt":169,"src":4771},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-6.png",[126,4773,4774,4775,4778],{},"กลับมาที่ Wayback machine สักแป้บนึงครับ ให้เราค้นหา request ที่จะนำมาใช้งาน ซึ่งในกรณีนี้จะเป็น ",[171,4776,4777],{},"https:\u002F\u002Fweb.archive.org\u002Fweb\u002Ftimemap\u002Fjson"," ครับ",[126,4780,4781],{},[3766,4782],{"alt":169,"src":4783},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-9.png",[126,4785,4786],{},"กรอกข้อมูลต่าง ๆ ได้เลย โดยที่ส่วนของ URL แนะนำให้ใช้แค่ URL นะครับ แล้วแบ่งเอา Parameter ลงมาใส่ข้างล่างแทน แบบในรูปเลยครับ (แนะนำว่าให้ปรับ Limit เป็นค่าน้อย ๆ จากเดิน 10000 อาจจะลดลงเหลือ 30 ก็ได้ครับ) เสร็จแล้วกดปุ่ม Test Step ได้เลย ถ้าถูกต้องด้านขวามือจะมีข้อมูลขึ้นมาแบบนี้ครับ",[126,4788,4789],{},[3766,4790],{"alt":169,"src":4791},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-10.png",[126,4793,4794],{},"โดยที่ Output จะดูข้อมูลได้ 3 รูปแบบได้แก่ Table, JSON, Schema ซึ่งการทำงานจริง ๆ ของ N8N จะทำงานภายใต้ Object Array ครับ",[126,4796,4797],{},[3766,4798],{"alt":169,"src":4799},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-11.png",[126,4801,4802],{},"อันนี้ถ้าดูดี ๆ มันจะเป็นการ return มาแบบแปลก ๆ นะครับ ปกติแล้วมันควรจะ return มาเป็น json ในรูปแบบ",[164,4804,4806],{"className":446,"code":4805,"language":448,"meta":169,"style":169},"[{\n\"original\": \"http:\u002F\u002Fexample.com:80\u002F\",\n\"mimetype\": \"text\u002Fhtml\",\n\"...\"\n}]\n",[171,4807,4808,4813,4834,4854,4863],{"__ignoreMap":169},[174,4809,4810],{"class":176,"line":177},[174,4811,4812],{"class":455},"[{\n",[174,4814,4815,4817,4820,4822,4824,4826,4829,4831],{"class":176,"line":236},[174,4816,468],{"class":461},[174,4818,4819],{"class":465},"original",[174,4821,468],{"class":461},[174,4823,471],{"class":455},[174,4825,2272],{"class":372},[174,4827,4828],{"class":188},"http:\u002F\u002Fexample.com:80\u002F",[174,4830,468],{"class":372},[174,4832,4833],{"class":455},",\n",[174,4835,4836,4838,4841,4843,4845,4847,4850,4852],{"class":176,"line":242},[174,4837,468],{"class":461},[174,4839,4840],{"class":465},"mimetype",[174,4842,468],{"class":461},[174,4844,471],{"class":455},[174,4846,2272],{"class":372},[174,4848,4849],{"class":188},"text\u002Fhtml",[174,4851,468],{"class":372},[174,4853,4833],{"class":455},[174,4855,4856,4858,4861],{"class":176,"line":248},[174,4857,468],{"class":461},[174,4859,4860],{"class":465},"...",[174,4862,2278],{"class":461},[174,4864,4865],{"class":176,"line":254},[174,4866,4867],{"class":455},"}]\n",[126,4869,4870],{},"แต่กรณีนี้ return มาเป็น",[164,4872,4874],{"className":446,"code":4873,"language":448,"meta":169,"style":169},"[[\"original\", \"mimetype\", \"...\"], [\"value\"...]]\n",[171,4875,4876],{"__ignoreMap":169},[174,4877,4878,4881,4883,4885,4887,4890,4892,4894,4896,4898,4900,4902,4904,4907,4909,4911,4914,4916,4919],{"class":176,"line":177},[174,4879,4880],{"class":455},"[[",[174,4882,468],{"class":372},[174,4884,4819],{"class":188},[174,4886,468],{"class":372},[174,4888,4889],{"class":455},",",[174,4891,2272],{"class":372},[174,4893,4840],{"class":188},[174,4895,468],{"class":372},[174,4897,4889],{"class":455},[174,4899,2272],{"class":372},[174,4901,4860],{"class":188},[174,4903,468],{"class":372},[174,4905,4906],{"class":455},"],",[174,4908,1536],{"class":455},[174,4910,468],{"class":372},[174,4912,4913],{"class":188},"value",[174,4915,468],{"class":372},[174,4917,4860],{"class":4918},"sg798",[174,4920,4921],{"class":455},"]]\n",[126,4923,4924],{},"ซึ่งมันเอาไปใช้ต่อม่ายได้ครับ '-' ดังนั้นให้กด \"+\" ด้านขวาแล้วเลือก Node \"Code\" เข้ามาช่วยได้เลยครับ",[126,4926,4927,4928],{},"ให้ลองเอา Code นี้ไปใส่\n",[3766,4929],{"alt":169,"src":4930},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-12.png",[164,4932,4936],{"className":4933,"code":4934,"language":4935,"meta":169,"style":169},"language-js shiki shiki-themes material-theme-lighter one-dark-pro github-dark","for (const item of $input.all()) {\n  console.log(item)\n}\nreturn $input.all()\n","js",[171,4937,4938,4973,4992,4996],{"__ignoreMap":169},[174,4939,4940,4943,4946,4950,4954,4958,4962,4964,4968,4971],{"class":176,"line":177},[174,4941,4942],{"class":1532},"for",[174,4944,4945],{"class":1542}," (",[174,4947,4949],{"class":4948},"sOHk9","const",[174,4951,4953],{"class":4952},"sUzmo"," item",[174,4955,4957],{"class":4956},"s_AEr"," of",[174,4959,4961],{"class":4960},"sU9mH"," $input",[174,4963,2079],{"class":455},[174,4965,4967],{"class":4966},"suMxZ","all",[174,4969,4970],{"class":1542},"()) ",[174,4972,456],{"class":455},[174,4974,4975,4978,4980,4983,4987,4990],{"class":176,"line":236},[174,4976,4977],{"class":4960},"  console",[174,4979,2079],{"class":455},[174,4981,4982],{"class":4966},"log",[174,4984,4986],{"class":4985},"sbHgf","(",[174,4988,4989],{"class":2094},"item",[174,4991,2126],{"class":4985},[174,4993,4994],{"class":176,"line":242},[174,4995,480],{"class":455},[174,4997,4998,5001,5003,5005,5007],{"class":176,"line":248},[174,4999,5000],{"class":1532},"return",[174,5002,4961],{"class":4960},[174,5004,2079],{"class":455},[174,5006,4967],{"class":4966},[174,5008,5009],{"class":1542},"()\n",[126,5011,5012],{},"ก่อนกดปุ่มให้กด F12 เพื่อเปิด browser console เพื่อดูผลของ console.log ครับ",[126,5014,5015],{},[3766,5016],{"alt":169,"src":5017},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-13.png",[126,5019,5020],{},"โดยอันนี้แหละที่เราจะเอามาใช้ต่อได้ เอา Code อันนี้ไปใส่",[164,5022,5024],{"className":4933,"code":5023,"language":4935,"meta":169,"style":169},"\u002F\u002F Retrieve all data from the input\nconst inputItems = $input.all()\n\n\u002F\u002F Extract the headers from the first item\nconst headers = inputItems[0].json || []\n\n\u002F\u002F Initialize an array to store the new items\nconst newItems = []\n\n\u002F\u002F Iterate over each old item, starting from the second item since the first is the headers\nfor (let i = 1; i \u003C inputItems.length; i++) {\n  const item = inputItems[i].json || []\n  const obj = {} \u002F\u002F Use a plain JavaScript object\n\n  \u002F\u002F Map each value to its corresponding header\n  for (let j = 0; j \u003C headers.length; j++) {\n    obj[headers[j]] = item[j]\n  }\n\n  \u002F\u002F Add the new object to the newItems array\n  newItems.push(obj)\n}\n\n\u002F\u002F Return the JSON array of objects\nreturn newItems\n",[171,5025,5026,5031,5049,5053,5058,5088,5092,5097,5108,5112,5117,5162,5188,5203,5207,5212,5251,5280,5285,5289,5294,5311,5315,5319,5324],{"__ignoreMap":169},[174,5027,5028],{"class":176,"line":177},[174,5029,5030],{"class":3353},"\u002F\u002F Retrieve all data from the input\n",[174,5032,5033,5035,5038,5041,5043,5045,5047],{"class":176,"line":236},[174,5034,4949],{"class":4948},[174,5036,5037],{"class":4952}," inputItems",[174,5039,5040],{"class":1539}," =",[174,5042,4961],{"class":4960},[174,5044,2079],{"class":455},[174,5046,4967],{"class":4966},[174,5048,5009],{"class":1542},[174,5050,5051],{"class":176,"line":242},[174,5052,2759],{"emptyLinePlaceholder":935},[174,5054,5055],{"class":176,"line":248},[174,5056,5057],{"class":3353},"\u002F\u002F Extract the headers from the first item\n",[174,5059,5060,5062,5065,5067,5069,5072,5075,5078,5080,5082,5085],{"class":176,"line":254},[174,5061,4949],{"class":4948},[174,5063,5064],{"class":4952}," headers",[174,5066,5040],{"class":1539},[174,5068,5037],{"class":2094},[174,5070,5071],{"class":1542},"[",[174,5073,5074],{"class":1982},"0",[174,5076,5077],{"class":1542},"]",[174,5079,2079],{"class":455},[174,5081,448],{"class":2094},[174,5083,5084],{"class":1539}," ||",[174,5086,5087],{"class":1542}," []\n",[174,5089,5090],{"class":176,"line":2112},[174,5091,2759],{"emptyLinePlaceholder":935},[174,5093,5094],{"class":176,"line":2129},[174,5095,5096],{"class":3353},"\u002F\u002F Initialize an array to store the new items\n",[174,5098,5099,5101,5104,5106],{"class":176,"line":2135},[174,5100,4949],{"class":4948},[174,5102,5103],{"class":4952}," newItems",[174,5105,5040],{"class":1539},[174,5107,5087],{"class":1542},[174,5109,5110],{"class":176,"line":3364},[174,5111,2759],{"emptyLinePlaceholder":935},[174,5113,5114],{"class":176,"line":3369},[174,5115,5116],{"class":3353},"\u002F\u002F Iterate over each old item, starting from the second item since the first is the headers\n",[174,5118,5119,5121,5123,5126,5129,5131,5134,5137,5139,5142,5144,5146,5150,5152,5154,5157,5160],{"class":176,"line":3375},[174,5120,4942],{"class":1532},[174,5122,4945],{"class":1542},[174,5124,5125],{"class":4948},"let",[174,5127,5128],{"class":2094}," i",[174,5130,5040],{"class":1539},[174,5132,5133],{"class":1982}," 1",[174,5135,5136],{"class":455},";",[174,5138,5128],{"class":2094},[174,5140,5141],{"class":1539}," \u003C",[174,5143,5037],{"class":4960},[174,5145,2079],{"class":455},[174,5147,5149],{"class":5148},"sVJsf","length",[174,5151,5136],{"class":455},[174,5153,5128],{"class":2094},[174,5155,5156],{"class":1539},"++",[174,5158,5159],{"class":1542},") ",[174,5161,456],{"class":455},[174,5163,5164,5167,5169,5171,5173,5175,5178,5180,5182,5184,5186],{"class":176,"line":3390},[174,5165,5166],{"class":4948},"  const",[174,5168,4953],{"class":4952},[174,5170,5040],{"class":1539},[174,5172,5037],{"class":2094},[174,5174,5071],{"class":4985},[174,5176,5177],{"class":2094},"i",[174,5179,5077],{"class":4985},[174,5181,2079],{"class":455},[174,5183,448],{"class":2094},[174,5185,5084],{"class":1539},[174,5187,5087],{"class":4985},[174,5189,5190,5192,5195,5197,5200],{"class":176,"line":3395},[174,5191,5166],{"class":4948},[174,5193,5194],{"class":4952}," obj",[174,5196,5040],{"class":1539},[174,5198,5199],{"class":455}," {}",[174,5201,5202],{"class":3353}," \u002F\u002F Use a plain JavaScript object\n",[174,5204,5205],{"class":176,"line":3400},[174,5206,2759],{"emptyLinePlaceholder":935},[174,5208,5209],{"class":176,"line":4044},[174,5210,5211],{"class":3353},"  \u002F\u002F Map each value to its corresponding header\n",[174,5213,5214,5217,5219,5221,5224,5226,5229,5231,5233,5235,5237,5239,5241,5243,5245,5247,5249],{"class":176,"line":4052},[174,5215,5216],{"class":1532},"  for",[174,5218,4945],{"class":4985},[174,5220,5125],{"class":4948},[174,5222,5223],{"class":2094}," j",[174,5225,5040],{"class":1539},[174,5227,5228],{"class":1982}," 0",[174,5230,5136],{"class":455},[174,5232,5223],{"class":2094},[174,5234,5141],{"class":1539},[174,5236,5064],{"class":4960},[174,5238,2079],{"class":455},[174,5240,5149],{"class":5148},[174,5242,5136],{"class":455},[174,5244,5223],{"class":2094},[174,5246,5156],{"class":1539},[174,5248,5159],{"class":4985},[174,5250,456],{"class":455},[174,5252,5253,5256,5258,5261,5263,5266,5269,5271,5273,5275,5277],{"class":176,"line":4060},[174,5254,5255],{"class":2094},"    obj",[174,5257,5071],{"class":4985},[174,5259,5260],{"class":2094},"headers",[174,5262,5071],{"class":4985},[174,5264,5265],{"class":2094},"j",[174,5267,5268],{"class":4985},"]] ",[174,5270,4326],{"class":1539},[174,5272,4953],{"class":2094},[174,5274,5071],{"class":4985},[174,5276,5265],{"class":2094},[174,5278,5279],{"class":4985},"]\n",[174,5281,5282],{"class":176,"line":4068},[174,5283,5284],{"class":455},"  }\n",[174,5286,5287],{"class":176,"line":4073},[174,5288,2759],{"emptyLinePlaceholder":935},[174,5290,5291],{"class":176,"line":4081},[174,5292,5293],{"class":3353},"  \u002F\u002F Add the new object to the newItems array\n",[174,5295,5296,5299,5301,5304,5306,5309],{"class":176,"line":4091},[174,5297,5298],{"class":4960},"  newItems",[174,5300,2079],{"class":455},[174,5302,5303],{"class":4966},"push",[174,5305,4986],{"class":4985},[174,5307,5308],{"class":2094},"obj",[174,5310,2126],{"class":4985},[174,5312,5313],{"class":176,"line":4100},[174,5314,480],{"class":455},[174,5316,5317],{"class":176,"line":4107},[174,5318,2759],{"emptyLinePlaceholder":935},[174,5320,5321],{"class":176,"line":4118},[174,5322,5323],{"class":3353},"\u002F\u002F Return the JSON array of objects\n",[174,5325,5326,5328],{"class":176,"line":4129},[174,5327,5000],{"class":1532},[174,5329,5330],{"class":2094}," newItems\n",[126,5332,5333],{},"ใน code จะมี warning ของ interface อยู่นะครับ แต่มองข้ามไปได้ กดรันได้เลยฮะ ถ้าถูกต้องตรงฝั่งขวามือเราจะได้ Output หน้าตาเป็นแบบนี้ครับ ถือว่าถูกต้องและใช้งานต่อได้",[126,5335,5336],{},[3766,5337],{"alt":169,"src":5338},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-14.png",[126,5340,5341],{},"ซึ่งต่อไปก็ขึ้นอยู่กับเราว่าจะเอาข้อมูลจาก workflow นี้ไปทำอะไรต่อ เช่นนำไปเก็บใน Database, นำไปใช้วิเคราะห์ต่อ, นำไป filter ข้อมูลที่สนใจอันนี้ขึ้นอยู่กับจุดประสงค์แล้วครับ",[126,5343,5344,5345],{},"บนเส้นเมื่อรันแล้วจะเจอกับเลขอยู่นะครับ ซึ่งหมายถึงจำนวนข้อมูลปกติแล้ว N8N จะทำการ Loop ในข้อมูลแต่ละชุดให้เลยครับ จากด้านซ้ายมีข้อมูล 31 Object (รวม header) เอามาแปลงเป็นข้อมูลด้านขวาซึ่งจะเหลือ 30 Object ครับ\n",[3766,5346],{"alt":169,"src":5347},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-15.png",[126,5349,5350,5351,5354],{},"ต่อไปผมจะลองใช้งาน Filter ดูนะครับ โดยที่จะ filter ",[171,5352,5353],{},"mimetype: text\u002Fhtml"," ออกมาอย่างเดียว เลือกเป็น Data transformation และ Filter",[126,5356,5357],{},[3766,5358],{"alt":169,"src":5359},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-16.png",[126,5361,5362],{},"เลือกเป็น Schema แล้วดูตรง Node ที่ชื่อว่า \"Code\" ซึ่งเป็น Node ก่อนหน้า ในที่นี้เราสามารถ drag & drop ข้อมูลที่เราต้องการได้เลยครับ ให้เลือก \"mimetype\" ลากมาวางตรง \"value1\"",[126,5364,5365],{},[3766,5366],{"alt":169,"src":5367},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-17.png",[126,5369,5370,5371],{},"ส่วน OP: เลือกเป็น \"is equal to\" และ value ใส่เป็น \"text\u002Fhtml\" แบบในรูปครับ\n",[3766,5372],{"alt":169,"src":5373},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-18.png",[126,5375,5376,5377],{},"เมื่อกด \"Test Step\" จะพบว่าข้อมูลจะถูกแยกเป็น 2 ส่วนคือ\"Kept\" (เก็บไว้) และ \"Discarded\" (เอาทิ้ง) ซึ่งจะเป็นตามเงื่อนไขที่เราตั้งไว้ครับ\n",[3766,5378],{"alt":169,"src":5379},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-19.png",[126,5381,5382],{},"ปลายเส้นก็จะเหลือข้อมูล 1 item ตามที่เรา filter ไว้เลยครับ เย่",[126,5384,5385],{},[3766,5386],{"alt":169,"src":5387},"\u002Fimages\u002F2025-04-28-n8n-part-2\u002Fimage-20.png",[126,5389,5390],{},"การใช้งาน N8N ก็จะมีประมาณนี้ครับ ไม่ยากไม่ง่ายจนเกินไปเนอะ ไว้มาต่อกัน EP 3 นะครับ",[909,5392,5393],{},"html pre.shiki code .s36IK, html code.shiki .s36IK{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sOHk9, html code.shiki .sOHk9{--shiki-light:#9C3EDA;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .sUzmo, html code.shiki .sUzmo{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#79B8FF}html pre.shiki code .s_AEr, html code.shiki .s_AEr{--shiki-light:#39ADB5;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .sU9mH, html code.shiki .sU9mH{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#E1E4E8}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .suMxZ, html code.shiki .suMxZ{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sbHgf, html code.shiki .sbHgf{--shiki-light:#E53935;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .sVJsf, html code.shiki .sVJsf{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sObbn, html code.shiki .sObbn{--shiki-light:#39ADB5;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sVeMc, html code.shiki .sVeMc{--shiki-light:#9C3EDA;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sg798, html code.shiki .sg798{--shiki-light:#90A4AE;--shiki-light-font-style:inherit;--shiki-default:#FFFFFF;--shiki-default-font-style:inherit;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}",{"title":169,"searchDepth":236,"depth":236,"links":5395},[5396],{"id":4672,"depth":236,"text":4673,"children":5397},[5398,5399],{"id":4676,"depth":242,"text":4677},{"id":4696,"depth":242,"text":4697},"พาสร้าง workflow แรกใน N8N ด้วยโจทย์ดึง URLs ของ domain ที่ต้องการจาก Wayback Machine",{},"2025-04-24-n8n-part-1.md",[4634],{"title":4648,"description":5400},{"loc":29,"images":5406,"lastmod":30},[5407,5408,5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426],{"loc":4669},{"loc":4682},{"loc":4690},{"loc":4716},{"loc":4727},{"loc":4735},{"loc":4743},{"loc":4771},{"loc":4783},{"loc":4791},{"loc":4799},{"loc":4930},{"loc":5017},{"loc":5338},{"loc":5347},{"loc":5359},{"loc":5367},{"loc":5373},{"loc":5379},{"loc":5387},"blogs\u002F2025-04-28-n8n-part-2",[944],"UbbL0GLr3jBjHa0OdYnfLe_l-Lw_ErvFt0whirlah_s",{"id":5431,"title":5432,"body":5433,"date":36,"description":5639,"draft":932,"extension":933,"meta":5640,"navigation":935,"next":936,"ogTitle":5641,"path":35,"pin":932,"prev":936,"recommends":5642,"seo":5644,"sitemap":5645,"stem":5657,"tags":5658,"updated":936,"__hash__":5659},"content\u002Fblogs\u002F2025-05-12-next-dns.md","ผมย้ายจาก Pihole & Adguard มาใช้ NextDNS",{"type":123,"value":5434,"toc":5626},[5435,5440,5444,5447,5450,5453,5457,5462,5473,5476,5480,5483,5487,5490,5493,5497,5500,5503,5506,5511,5514,5517,5523,5526,5529,5534,5537,5548,5551,5557,5560,5565,5569,5574,5577,5581,5584,5589,5593,5596,5601,5603,5606,5609,5616,5623],[126,5436,5437],{},[3766,5438],{"alt":169,"src":5439},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-7cc8fbe7-61fd-422c-90fd-f1f87ff3201e.jpg",[139,5441,5443],{"id":5442},"nextdns-คือ","NextDNS คือ",[126,5445,5446],{},"DNS Server ที่สามารถช่วยในการป้องกัน security threads, block โฆษณา หรือ block การ tracking ของ website หรือ application ต่าง ๆ โดยที่เราสามารถตั้งค่าได้ว่าในแต่ละ device จะใช้ policy ใดในการป้องกัน",[126,5448,5449],{},"โดยวิธีการทำงานตัว NextDNS จะมี list ของ domain ที่เป็นอันตราย (สามารถใช้ Blacklist มาตรฐานทั่ว ๆ ไปของ Adguard หรือ PiHole ได้) เมื่อมีการพยายาม query ข้อมูลที่เป็นอันตรายจาก domain ที่อยู่ใน blacklist ตัว NextDNS ก็จะทำการ block คำขอดังกล่าวแทน",[126,5451,5452],{},"วิธีการใช้งานตั้งค่าจะคล้าย ๆ กับ Pihole หรือ Adguard เลยครับ แต่ต่างตรงที่เราไม่ต้อง self-hosted เอง, สามารถจัดการเองได้บน website \"my.nextdns.io\" ครับ",[139,5454,5456],{"id":5455},"pricing","Pricing",[126,5458,5459],{},[3766,5460],{"alt":169,"src":5461},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-21282f92-db55-4b79-aa63-67fc9aa7303a.jpg",[126,5463,5464,5468,5469,5472],{},[5465,5466,5467],"em",{},"ข้อมูล ณ วันที่ 12\u002F5\u002F68","\nจะมีให้ใช้ 4 Plan หลัก ๆ ด้วยกันโดยที่มี version free ให้ใช้ด้วยครับ สามารถตั้งค่าได้เหมือนกับ version เสียตัง แต่จะแตกต่างตรงที่หากครบ 300,000 queries ต่อเดือนแล้วหลังจากนั้น",[390,5470,5471],{},"จะไม่มีการ block query"," (จะกลายเป็นเหมือน DNS ธรรมดาทั่ว ๆ ไป) เลยไม่ต้องกังวลไปนะครับว่าหลังจากครบโควต้าฟรีแล้วจะใช้งาน DNS ไม่ได้",[126,5474,5475],{},"ส่วนตัวผมเลือกเป็น Version Pro ครับ ปีละ 590 บาท (ทดลองใช้ตัวฟรีประมาณ 1 สัปดาห์ก็ตัดสินใจจ่ายเงินเลยครับ)",[139,5477,5479],{"id":5478},"ควรเลือก-plan-ไหนดี","ควรเลือก Plan ไหนดี",[126,5481,5482],{},"สำหรับผมแล้ว 300,000 queries ต่อเดือน บอกเลยครับว่า \"ไม่พอ\" 5555 เลยตัดสินใจ subscription เป็นตัว pro แทน แต่ก็แนะนำว่าให้ลองใช้ดูก่อนก็ได้ครับ ว่าเข้ากับ lifestyle ของตัวเองรึเปล่า ถ้าถูกใจค่อยจ่ายตังก็ได้ครับ เพราะตัว free มี featureเหมือนกับตัว pro หรือตัวเสียตังเลย",[139,5484,5486],{"id":5485},"เอาเงินค่า-subscription-ไปเช่า-server-แล้ว-self-hosted-เองจะดีกว่ามั้ย","เอาเงินค่า subscription ไปเช่า server แล้ว self-hosted เองจะดีกว่ามั้ย",[126,5488,5489],{},"เครื่อง server 1 ปีในราคา 590 บาทถ้าถามว่ามีมั้ย ก็ต้องบอกว่าพอจะหาได้ครับ ผมเองก็เป็นสาย Self-hosted, Home Lab ที่ชอบการ self-hosted อะไรหลาย ๆ อย่าง แต่ผมมีความคิดนึงครับว่าจะมีอยู่ไม่กี่อย่างที่จะไม่ self-hosted เองได้แก่ Email Server, Bitwarden (password manager) และ DNS เพราะสิ่งเหล่านี้การดูแลรักษาให้ใช้งานได้และปลอดภัยถือว่าเป็น challenge มากครับ ถ้าใช้งานไม่ได้ขึ้นมางานหยาบทันที ดังนั้นยอมเสียตังหน่อยเพื่อใช้ความ stable ตรงนี้ดีกว่าครับ (อันนี้มุมมองผมนะ)",[126,5491,5492],{},"แล้วก็เคยมีประสบการณ์ที่ Internal ช้าเพราะว่า Setup Pihole & Adguard ไม่ดีทำให้จังหวะ query มันแปลก ๆ กว่าจะหาเหตุผลเจอว่าเป็นที่การตั้งค่าของตัวเอง ก็โทษ ISP อยู่หลายวัน 55555 (อันนี้ยอมรับว่าเป็น skill issue ของตัวเอง) แต่ก็อยากแชร์เป็น use-case ให้ฟังครับ",[139,5494,5496],{"id":5495},"dns-over-https","DNS over HTTPS",[126,5498,5499],{},"อันนี้เป็นอีกเหตุผลนึงที่ผมย้ายมาใช้ NextDNS เพราะว่ามี DoH ให้ใช้ อธิบายให้เห็นภาพง่าย ๆ ให้มองว่าถ้าเราใช้ DNS แบบปกติทางผู้ให้บริการ internal หรือผู้ดูแลระบบจะสามารถดู DNS query ได้ (DNS query จะไม่ได้มีการเข้ารหัสไว้) ซึ่งการมาใช้ DoH จะทำให้มี Privacy ในส่วนนี้มากยิ่งขึ้น จะเป็นการ encryption DNS query อีกทั้งยังสามารถป้องกันการโดน DNS Proxy จากผู้ดูแลได้อีกด้วย (สำหรับคนที่กังวลในเรื่อง Privacy แบบผมอันนี้คือจุดสำคัญเลยครับ)",[139,5501,5502],{"id":5502},"วิธีการใช้งาน",[126,5504,5505],{},"ต้องบอกว่าสามารถใช้งานได้ในแทบทุกอุปกรณ์เลย ส่วนตัวผมเองใช้งานบน Windows, MacOS, IPAD OS, iOS โดยจะมีการตั้งค่าหลายวิธีเลยครับ แต่แนะนำว่าให้ใช้วิธีการติดตั้ง Application ดีกว่า ตัวอย่างเช่น iOS",[126,5507,5508],{},[3766,5509],{"alt":169,"src":5510},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-44fe4e0e-4f38-4ed5-abd5-c165444b4de7.jpg",[126,5512,5513],{},"ซึ่งสามารถใช้งานได้ 2 วิธีคือการลง Profile กับติดตั้ง Application บอกตรง ๆ ว่าผมไม่กล้าเลือกการติดตั้งโดยใช้ Profile ครับ เลยเลือกเป็น Download Application จาก App Store แทน",[126,5515,5516],{},"วิธีการใช้งานง่ายมากจริง ๆ อ่านตรงข้างล่างก็ทำตามได้แล้วครับ",[126,5518,5519,5520],{},"ผมเองใช้งานทั้งในรูปแบบของการติดตั้งบน end devices และติดตั้งบน router ที่บ้านเลยครับ แต่ถ้าเป็นการติดตั้งบน router ที่ไม่ได้รองรับการ setup next dns (อุุปกรณ์ที่รองรับเช่น Mikrotik, Tailscale, pfSense) จำเป็นต้องตั้งค่า DNS แบบปกติ (เอา IP มาใส่) แล้ว Update ตรง \"Linked IP\"\n",[3766,5521],{"alt":169,"src":5522},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-5da350b0-f339-429e-a108-edfefb194df2.jpg",[126,5524,5525],{},"ให้ IP เป็นของบ้านเรา แล้วจะสามารถใช้ Profile นั้น ๆ ได้ จะใช้เป็นตั้งค่า DDNS หรือทำ scheduler เพื่อไป update ip ก็ได้ครับ (ผมใช้ n8n ทำ workflows ให้ loop fetch เรื่อย ๆ)",[139,5527,5528],{"id":5528},"ป้องกันอะไรได้บ้าง",[126,5530,5531],{},[3766,5532],{"alt":169,"src":5533},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-0eae9706-37a8-4bc3-ab47-0e7f86206438.jpg",[126,5535,5536],{},"ภายใน Tab Security จะมี options ให้ตั้งค่าได้ครับว่า Profile นี้จะให้มีการป้องกันอะไรบ้าง เช่น",[707,5538,5539,5542,5545],{},[710,5540,5541],{},"Threat Intelligence Feeds: ป้องกัน domain ที่เป็นอันตรายเช่น Phishing, c2 server",[710,5543,5544],{},"DNS Rebinding Protection: ป้องกัน DNS ประเภทที่ Mapping เป็น Private IP",[710,5546,5547],{},"Typosquatting Protection: ป้องกัน domain ประเภทที่เจตนาเล่นกับการพิมพ์ผิด เช่น gooogle.com เป็นต้น (เว็บจริงคือ google.com)",[126,5549,5550],{},"และอื่น ๆ อีกตั้งค่าได้เยอะประมาณนึงเลยครับ",[126,5552,5553,5554],{},"เลือก Blacklists เองได้ เหมือนกับ Adguard & Pihole เลย\n",[3766,5555],{"alt":169,"src":5556},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-1d87500f-04aa-4aaa-b6f8-d46c4f0b7da4.jpg",[126,5558,5559],{},"มี Parental Control ใช้สำหรับการสร้าง Profile เพื่อป้องกันเด็ก ๆ ที่บ้านดูในสิ่งที่ไม่ควรจะดูได้ สามารถ block การเข้าถึง application ต่าง ๆ ได้ ตั้งเวลาในการเข้าใช้งาน domain ต่าง ๆ ได้ครับ",[126,5561,5562],{},[3766,5563],{"alt":169,"src":5564},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-890aa801-ef39-44e6-bfa4-d13f15d97025.jpg",[139,5566,5568],{"id":5567},"รองรับหลาย-profile","รองรับหลาย Profile",[126,5570,5571],{},[3766,5572],{"alt":169,"src":5573},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-76b242e0-e379-4af6-ad5e-75eec5ac5c51.jpg",[126,5575,5576],{},"ในบางกรณีจะนำไปใช้ในการควบคุมการเข้าถึงของบุคคลอื่น ๆ เช่นผู้สูงอายุที่บ้าน, เด็ก ๆ ที่บ้าน ทาง NextDNS เองก็มีการให้ตั้งค่า Profile ได้เช่นเดียวกัน โดยที่แต่ละ Profile จะมี ID ของตัวเองและตั้งค่าแยกกันโดยอิสระ ในเครื่องที่ต้องการใช้ Profile อื่นก็ให้นำ ID ใน Tab Setup ไปใส่ได้เลยครับ",[139,5578,5580],{"id":5579},"ดู-query-logs-ได้","ดู query logs ได้",[126,5582,5583],{},"สามารถดู Logs การ query domain ต่าง ๆ ได้ครับ สิ่งจะเห็นทุก ๆ อุปกรณ์ที่ใช้ Profile ID นี้ แต่ตรงนี้สามารถปิดได้นะครับ (ปกติก็ผมจะปิดไว้)",[126,5585,5586],{},[3766,5587],{"alt":169,"src":5588},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-aaeef8ce-564a-4afb-abb2-e9fdbbd29f9b.jpg",[139,5590,5592],{"id":5591},"server-มีที่ไหนบ้าง","Server มีที่ไหนบ้าง",[126,5594,5595],{},"มีหลาย Server มากครับโดยใกล้สุดคืออยู่ที่กรุงเทพ ซึ่ง Ping เพียงแค่ \"7ms\" น้อยมาก ๆ อันนี้เลยเป็นอีกเหตุผลที่ผมเลือกใช้",[126,5597,5598],{},[3766,5599],{"alt":169,"src":5600},"\u002Fimages\u002F2025-05-12-next-dns\u002Fimages-509d5eaf-58e3-46b7-a425-01b7b562443d.jpg",[139,5602,1370],{"id":1370},[126,5604,5605],{},"ผมใช้งานมาได้ประมาณ 1 เดือนแล้วครับ ตอนนี้ก็เอา Adgaurd ออกจาก Home Server แล้ว จากที่ใช้มายังไม่เจอเหตุการณ์ที่ Server Down แล้วทำให้ใช้งานไม่ได้เลยครับ ส่วนตัวให้ 9\u002F10 หัก 1 คะแนนตรงที่ ถ้ามี Custom DNS record ให้ใช้จะดีเลยครับ แต่อันนี้ไม่มี",[126,5607,5608],{},"สนใจสมัครได้ที่",[126,5610,5611,5612],{},"(affiliate link): ",[292,5613,5614],{"href":5614,"rel":5615},"https:\u002F\u002Fnextdns.io\u002F?from=2ggah5wn",[296],[126,5617,5618,5619],{},"(link ปกติ): ",[292,5620,5621],{"href":5621,"rel":5622},"https:\u002F\u002Fmy.nextdns.io\u002F",[296],[126,5624,5625],{},"กดสมัครผ่าน affiliate link เพื่อเป็นกำลังใจเล็ก ๆ น้อย ๆ ได้นะครับ ~",{"title":169,"searchDepth":236,"depth":236,"links":5627},[5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638],{"id":5442,"depth":236,"text":5443},{"id":5455,"depth":236,"text":5456},{"id":5478,"depth":236,"text":5479},{"id":5485,"depth":236,"text":5486},{"id":5495,"depth":236,"text":5496},{"id":5502,"depth":236,"text":5502},{"id":5528,"depth":236,"text":5528},{"id":5567,"depth":236,"text":5568},{"id":5579,"depth":236,"text":5580},{"id":5591,"depth":236,"text":5592},{"id":1370,"depth":236,"text":1370},"การมี DNS ที่ช่วยในการ Block โฆษณาหรือการ Tracking ในยุคสมัยนี้ถือว่าเป็นสิ่งที่ควรจะมี",{},"NextDNS",[3645,5643],"2026-08-07-node-exporter-mtls-basic-auth.md",{"title":5432,"description":5639},{"loc":35,"images":5646,"lastmod":36},[5647,5648,5649,5650,5651,5652,5653,5654,5655,5656],{"loc":5439},{"loc":5461},{"loc":5510},{"loc":5522},{"loc":5533},{"loc":5556},{"loc":5564},{"loc":5573},{"loc":5588},{"loc":5600},"blogs\u002F2025-05-12-next-dns",[945],"sxUZtkO0oB2nb7GGeZp2crf4j8DdXX4NWgCucmDyUBk",{"id":5661,"title":5662,"body":5663,"date":39,"description":5881,"draft":932,"extension":933,"meta":5882,"navigation":935,"next":936,"ogTitle":5883,"path":38,"pin":932,"prev":936,"recommends":5884,"seo":5885,"sitemap":5886,"stem":5897,"tags":5898,"updated":936,"__hash__":5899},"content\u002Fblogs\u002F2025-05-18-from-old-notebook-to-home-lab-server.md","เปลี่ยน Notebook (เก่า) ที่ไม่ได้ใช้งานเป็น Home Lab Server",{"type":123,"value":5664,"toc":5874},[5665,5670,5677,5681,5684,5704,5710,5720,5725,5728,5731,5749,5754,5765,5770,5776,5781,5784,5788,5804,5809,5812,5828,5832,5835,5837,5840,5843,5863,5868,5871],[126,5666,5667],{},[3766,5668],{"alt":169,"src":5669},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-f67e4b1b-db83-40d3-82ed-3fbdc5562404.jpg",[126,5671,5672,5673,5676],{},"สวัสดีครับ พอดีผมมีโปรเจคนึงที่ต้องการใช้งาน Server ขนาดเล็ก ๆ เครื่องนึง กำลังจะหาซื้อเครื่อง Mini PC ใหม่มาเพิ่มพอดี แต่โปรเจคนี้ก็ยังไม่มั่นใจว่าจะไปต่อได้แค่ไหนก่อนที่จะซื้อ hardware มาใหม่ เลยจะลองหยิบเอา Notebook เครื่องเก่ามาลองรันดูก่อนครับ ไหน ๆ ก็ละเลยมาเขียนเป็นบทความสั้น ๆ เอาไว้แชร์เป็นไอเดียสำหรับคนที่ต้องการจะลองเล่น Home Lab แต่ยังไม่อยากจะซื้อเครื่องใหม่ จริง ๆ แล้ว ",[390,5674,5675],{},"notebook"," นายเองก็เป็นได้นะ server อะ !",[139,5678,5680],{"id":5679},"ข้อดีของการนำ-notebook-มาใช้งาน","ข้อดีของการนำ notebook มาใช้งาน",[126,5682,5683],{},"หลาย ๆ คนคงจะคุ้นชินกับการใช้งาน notebook ในแบบปกติคือการใช้งาน windows ทั่ว ๆ ไป แต่ก็อาจจะมีหลาย ๆ คนที่เป็น advanced user ขึ้นมาหน่อยจับมาลง Linux ตัวต่าง ๆ ใช้งาน วันนี้จะลองพามาเปลี่ยนจาก notebook ให้กลายเป็น server ขนาดเล็ก ๆ กันครับ แล้วมันเหมาะสมยังไง",[707,5685,5686,5689,5698,5701],{},[710,5687,5688],{},"มีแบตเตอร์รี่ในตัว ปกติแล้ว server หรือ home server ที่ดีควรจะมี UPS เพื่อช่วยสำรองไฟในกรณีที่ไฟตกหรือไฟดับจะช่วยทำให้อุปกรณ์เสียหายได้ยากขึ้น ซึ่ง notebook (ในสภาพปกติ) จะมีแบตเตอร์รี่ในตัวอยู่แล้ว",[710,5690,5691,5692,5695],{},"กินไฟน้อย ถ้าเป็น notebook ที่ไม่ใช้ gaming notebook นะครับ ปกติแล้วจะกินไฟน้อย อันนี้คือจังหวะที่กำลังชาร์จแบต + idle อยู่นะครับกินไฟอยู่ที่ประมาณ 30W เอง (อันนี้ใช้ performance mode ถ้าปรับเป็น balanced mode จะลงไปอยู่ที่ราว ๆ 15 W) (แต่ก็เยอะถ้าเทียบกับตระกูล mini PC ที่มี CPU N100) ",[5465,5693,5694],{},"เดี๋ยวจะมาอัพเดทอีกทีหลังผ่านไป 1 เดือนนะครับว่ากินไฟไปกี่หน่วย",[3766,5696],{"alt":169,"src":5697},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-661534a0-e4a4-4d14-9238-67f04d5de3a7.jpg",[710,5699,5700],{},"มีจอ, trackpad, keyboard ในตัว เวลาเครื่องมีปัญหาก็จะสามารถตรวจสอบได้เลย ไม่ต้องหาอุปกรณ์มาต่อเพิ่ม",[710,5702,5703],{},"ประหยัดค่าใช้จ่าย หลาย ๆ คนอยากจะเล่น Home Lab เป็นงานอดิเรกนะครับ ซึ่งการเอาอุปกรณ์ที่มีอยู่แล้วมาใช้งานก็จะช่วยประหยัดไปได้อีก",[126,5705,5706,5707],{},"ตอนที่ไม่ได้มีการใช้งานเปิดเครื่องทิ้งไว้เฉย ๆ กินไฟ 3W เอง (น้อยมากก)\n",[3766,5708],{"alt":169,"src":5709},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-0bafd825-77ca-4f2c-b5ac-8ab9394dfb8f.jpg",[126,5711,5712,5713,5716,5717,5719],{},"ผมขอข้ามการติดตั้ง OS ไปนะครับ (ผมติดตั้งเป็น Ubuntu version 24 ไปกดรับ version pro ได้นะ ",[292,5714,5715],{"href":20},"วิธีรับ Ubuntu Pro",") เพราะทำแบบปกติทั่ว ๆ ไปเลยไม่ได้มีอะไรผิดปกติ แนะนำว่าให้เสียบสายแลนแทนการใช้งาน Wifi นะครับ เผื่อความ stable ของการใช้งาน หลังจากนั้นก็สามารถใช้ ",[171,5718,360],{}," เพื่อเชื่อมต่อเข้าไปได้เลย (IP address แนะนำให้ fixed ไว้ตอนติดตั้งนะครับ ไม่แนะนำให้ใช้ DHCP จะปวดหัวเอาทีหลัง)",[126,5721,5722],{},[3766,5723],{"alt":169,"src":5724},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-1.png",[139,5726,5727],{"id":5727},"วิธีการทำให้หน้าจอของเครื่องดับ",[126,5729,5730],{},"ปกติแล้วในการใช้งาน ubuntu server จะไม่ได้ใช้งานหน้าจอหรืออุปกรณ์โดยตรงนะครับ ซึ่งตรงนี้เราจะสามารถปิดการใช้หลาย ๆ function ออกไปได้ ซึ่งในการปิดหน้าจอสามารถทำได้ตามนี้เลยครับ",[164,5732,5734],{"className":3233,"code":5733,"language":2675,"meta":169,"style":169},"sudo vim \u002Fetc\u002Fdefault\u002Fgrub # หรือจะใช้ nano ก็ได้\n",[171,5735,5736],{"__ignoreMap":169},[174,5737,5738,5740,5743,5746],{"class":176,"line":177},[174,5739,403],{"class":180},[174,5741,5742],{"class":188}," vim",[174,5744,5745],{"class":188}," \u002Fetc\u002Fdefault\u002Fgrub",[174,5747,5748],{"class":3353}," # หรือจะใช้ nano ก็ได้\n",[126,5750,5751],{},[3766,5752],{"alt":169,"src":5753},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-33c75f2a-a1f7-4294-a2d8-7b769330b6c6.jpg",[126,5755,5756,5757,5760,5761,5764],{},"โดยเพิ่ม ",[171,5758,5759],{},"consoleblank=120"," ไปยัง ",[171,5762,5763],{},"GRUB_CMDLINE_LINUX_DEFAULT="," สามารถปรับเวลาที่ต้องการได้เลย หน่วยเป็นวินาที",[126,5766,5767],{},[3766,5768],{"alt":169,"src":5769},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-fd057b5b-b310-4d8c-b7e0-088c6481403f.jpg",[126,5771,5772,5773],{},"จากนั้นออกมาที่ terminal เหมือมเดิมแล้วรัน ",[171,5774,5775],{},"sudo update-grub",[126,5777,5778],{},[3766,5779],{"alt":169,"src":5780},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-cad0302a-9626-4746-99da-7ef8acb21a57.jpg",[126,5782,5783],{},"จากนั้น reboot เครื่องแล้วรอตามเวลาที่ตั้งไว้ได้เลย ว่าหน้าจอจะดับหรือไม่ ของผมตั้งไว้ 120 ก็คือรอ 2 นาทีครับ",[139,5785,5787],{"id":5786},"ตรวจสอบว่า-sleep-mode-ถูกปิดใช้งานอยู่","ตรวจสอบว่า sleep mode ถูกปิดใช้งานอยู่",[164,5789,5791],{"className":3233,"code":5790,"language":2675,"meta":169,"style":169},"sudo systemctl status sleep.target\n",[171,5792,5793],{"__ignoreMap":169},[174,5794,5795,5797,5799,5801],{"class":176,"line":177},[174,5796,403],{"class":180},[174,5798,2188],{"class":188},[174,5800,1913],{"class":188},[174,5802,5803],{"class":188}," sleep.target\n",[126,5805,5806],{},[3766,5807],{"alt":169,"src":5808},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-0f23e13d-d614-4174-852e-6257096028a1.jpg",[126,5810,5811],{},"วิธีการปิดใช้งาน",[164,5813,5815],{"className":3233,"code":5814,"language":2675,"meta":169,"style":169},"sudo systemctl mask sleep.target\n",[171,5816,5817],{"__ignoreMap":169},[174,5818,5819,5821,5823,5826],{"class":176,"line":177},[174,5820,403],{"class":180},[174,5822,2188],{"class":188},[174,5824,5825],{"class":188}," mask",[174,5827,5803],{"class":188},[139,5829,5831],{"id":5830},"วิธีการปิดไฟ-black-light-ของ-keyboard","วิธีการปิดไฟ black light ของ keyboard",[126,5833,5834],{},"อันนี้จะขึ้นอยู่กับแต่ละรุ่นนะครับว่ารองรับการปิดใช้มั้ย ต้องเข้าไปดูใน bios เลยครับ ซึ่งของผมอันนี้ไม่รองรับ ต้องเดินไปกดปิดไฟหน้าเครื่องเอง (sad) ไว้จะมาลองหาวิธีอีกทีครับ",[139,5836,1370],{"id":1370},[126,5838,5839],{},"อันนี้ก็เป็นไอเดียนะครับว่าเราสามารถจับเอา notebook มาทำเป็น home server ขนาดเล็ก ๆ ได้ แต่อาจจะต้องปรับเปลี่ยนการตั้งค่านิดหน่อยเพื่อให้เหมาะสมกับการเป็น server จากนี้ก็ขึ้นอยู่กับจุดประสงค์ว่าจะเอาไปทำอะไรต่อ เช่น ลง docker + portainer ทำเป็น web server หรือจะลองลง proxmox ก็ได้นะ ผมมีเครื่อง notebook ที่ลองลง proxmox ไว้เหมือนกัน",[126,5841,5842],{},"สิ่งที่ทำเพิ่มได้",[707,5844,5845,5848,5851,5854,5857,5860],{},[710,5846,5847],{},"ติดตั้ง docker",[710,5849,5850],{},"ติดตั้ง zsh เพื่อปรับแต่ง terminal",[710,5852,5853],{},"ลง license เพื่อใช้งาน ubuntu pro (เคยเขียนบทความไว้แล้ว)",[710,5855,5856],{},"ติดตั้ง tailscale เพื่อใช้งานเครื่องนี้จากภายนอก",[710,5858,5859],{},"ติดตั้ง coder เพื่อทำเป็น remote dev server",[710,5861,5862],{},"ทำระบบ backup",[126,5864,5865],{},[3766,5866],{"alt":169,"src":5867},"\u002Fimages\u002F2025-05-18-from-old-notebook-to-home-lab-server\u002Fimages-ff8a1e4b-de92-477b-9e8a-a93b64ee8878.jpg",[126,5869,5870],{},"ขอบคุณที่อ่านจนจบครับบ เย่ ~",[909,5872,5873],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":169,"searchDepth":236,"depth":236,"links":5875},[5876,5877,5878,5879,5880],{"id":5679,"depth":236,"text":5680},{"id":5727,"depth":236,"text":5727},{"id":5786,"depth":236,"text":5787},{"id":5830,"depth":236,"text":5831},{"id":1370,"depth":236,"text":1370},"อยากลองเล่น Home Lab แต่ไม่อยากซื้ออุปกรณ์ใหม่ ลองเอา notebook เครื่องเก่ามาลองใช้ก่อนได้นะ",{},"Home Lab Server",[3190,3835],{"title":5662,"description":5881},{"loc":38,"images":5887,"lastmod":39},[5888,5889,5890,5891,5892,5893,5894,5895,5896],{"loc":5669},{"loc":5697},{"loc":5709},{"loc":5724},{"loc":5753},{"loc":5769},{"loc":5780},{"loc":5808},{"loc":5867},"blogs\u002F2025-05-18-from-old-notebook-to-home-lab-server",[945],"jOjIc1GZrPYK2T-u74e6j9YW8I1VzKCGqw_k734YUsI",{"id":5901,"title":5902,"body":5903,"date":45,"description":6012,"draft":932,"extension":933,"meta":6013,"navigation":935,"next":936,"ogTitle":6014,"path":44,"pin":932,"prev":936,"recommends":6015,"seo":6018,"sitemap":6019,"stem":6026,"tags":6027,"updated":3652,"__hash__":6028},"content\u002Fblogs\u002F2025-08-18-ollama-desktop-ui.md","Ollama มี UI ให้ใช้แล้ว",{"type":123,"value":5904,"toc":6005},[5905,5910,5913,5917,5924,5928,5938,5943,5949,5953,5961,5969,5975,5979,5985,5988,5990],[126,5906,5907],{},[3766,5908],{"alt":169,"src":5909},"\u002Fimages\u002F2025-08-18-ollama-desktop-ui\u002Fimages-3de58dcb-c7b8-4c8e-8fb6-fd713de8d854.jpg",[126,5911,5912],{},"วันนี้ผมเพิ่งมาสังเกตว่า Ollama มี Desktop Application ให้ใช้งานแล้ว (ผมติดตั้ง version 0.11.4 บน macos) โดยหน้าตาของ UI จะมีความ minimal เหมือนกับ LLM Chat ทั่ว ๆ ไปเลยครับ",[139,5914,5916],{"id":5915},"ollama-คืออะไร","Ollama คืออะไร",[126,5918,5919,5920],{},"โดย Ollama คือเครื่องมือสำหรับใช้ในการ run llm ในรูปแบบ local (ใช้ hardware ของผู้ใช้งานโดยตรง) มีหลาย model ให้ใช้งาน เช่น Deepseek, gemma, Llama หรือ model อื่น ๆ สามารถดูได้ที่ ",[292,5921,5922],{"href":5922,"rel":5923},"https:\u002F\u002Follama.com\u002Fsearch",[296],[139,5925,5927],{"id":5926},"ที่ชอบคือไม่ต้องเปิด-cli-แล้ว","ที่ชอบคือไม่ต้องเปิด cli แล้ว",[126,5929,5930,5931,5934,5935],{},"โดยข้อดีที่ผมชอบเลยก็คือ ก่อนหน้านี้ตอนที่ต้องการทดสอบ model บางตัว ก็จำเป็นต้องใช้งานผ่าน cli โดยที่รัน ",[171,5932,5933],{},"ollama run gemma3:270m"," แต่ตอนนี้สะดวกขึ้นมาก เพียงแค่ ",[171,5936,5937],{},"ollama pull gemma3:270m",[126,5939,5940],{},[3766,5941],{"alt":169,"src":5942},"\u002Fimages\u002F2025-08-18-ollama-desktop-ui\u002Fimages-1350f112-92ce-4af4-b0d7-8731d4364dea.jpg",[126,5944,5945,5946],{},"จากนั้นก็จะสามารถเลือก model ผ่าน ollama UI และใช้งานได้เลย ทำให้การทดสอบทำได้ง่ายขึ้น\n",[3766,5947],{"alt":169,"src":5948},"\u002Fimages\u002F2025-08-18-ollama-desktop-ui\u002Fimages-d010a3a3-8228-4438-8686-a8c7fb7330c3.jpg",[139,5950,5952],{"id":5951},"features-ที่เพิ่มเข้ามา","Features ที่เพิ่มเข้ามา",[126,5954,5955,5956,5960],{},"ผมเลยไปตามอ่านดู release ก็ไปเจอกับ ",[292,5957,5958],{"href":5958,"rel":5959},"https:\u002F\u002Follama.com\u002Fblog\u002Fnew-app",[296]," โดยสรุป features ไว้คร่าว ๆ ตามนี้",[707,5962,5963,5966],{},[710,5964,5965],{},"Chat with file: ส่งไฟล์เพื่อไปถาม chat เช่นส่ง PDF ให้สรุป",[710,5967,5968],{},"กำหนด context length ได้",[126,5970,5971,5974],{},[3766,5972],{"alt":169,"src":5973},"\u002Fimages\u002F2025-08-18-ollama-desktop-ui\u002Fimages-8f00489f-216e-414d-b4e6-49bf74ade823.jpg","\nส่วนอื่น ๆ ก็เป็น chat UI ทั่ว ๆ ไปเลยนะครับ (อนาคตน่าจะมีอะไรให้ลองเล่นมากกว่านี้)",[139,5976,5978],{"id":5977},"turbo-beta","Turbo (Beta)",[126,5980,5981,5982],{},"อีกอย่างคือเห็นว่ามี Turbo (Beta) เข้ามาแล้วด้วย โดยมีราคาอยู่ที่ 20$ ต่อเดือน (ข้อมูลวันที่ 18\u002F8\u002F68) โดย Turbo คือการที่จากเดิม ollama จะเป็นการใช้งาน self-hardware หรือเครื่องของผู้ใช้งานเป็นคนทำงานใช่มั้ยครับ แต่ Turbo คือการที่จะไปใช้ Server ของทาง Ollama เพื่อทำงานใน model ที่มีขนาดใหญ่ขึ้นนั้นเอง\n",[3766,5983],{"alt":169,"src":5984},"\u002Fimages\u002F2025-08-18-ollama-desktop-ui\u002Fimages-74485b02-c1a5-4067-aab2-467400bff2aa.jpg",[126,5986,5987],{},"ต้องคอยติดตามต่อไปว่าจะมีอะไรที่น่าสนใจหรือมีอะไรอัพเดทต่ออีกบ้างครับ ~",[139,5989,3618],{"id":3617},[707,5991,5992,5999],{},[710,5993,5994],{},[292,5995,5998],{"href":5996,"rel":5997},"https:\u002F\u002Follama.com",[296],"ollama.com",[710,6000,6001],{},[292,6002,6004],{"href":5958,"rel":6003},[296],"Ollama new app",{"title":169,"searchDepth":236,"depth":236,"links":6006},[6007,6008,6009,6010,6011],{"id":5915,"depth":236,"text":5916},{"id":5926,"depth":236,"text":5927},{"id":5951,"depth":236,"text":5952},{"id":5977,"depth":236,"text":5978},{"id":3617,"depth":236,"text":3618},"Ollama ออก Desktop Application พร้อม Chat UI มาให้ใช้แล้ว ไม่ต้องรัน model ผ่าน cli อีกต่อไป",{},"Ollama New Desktop Application",[6016,6017],"2026-02-08-nanobot-ai-agent.md","2025-10-03-typhoon-ai-n8n.md",{"title":5902,"description":6012},{"loc":44,"images":6020,"lastmod":45},[6021,6022,6023,6024,6025],{"loc":5909},{"loc":5942},{"loc":5948},{"loc":5973},{"loc":5984},"blogs\u002F2025-08-18-ollama-desktop-ui",[944],"D6998yXIWaU5EA1sfK0Tm5odAcosoKqKnWLvwIOwXtM",{"id":6030,"title":6031,"body":6032,"date":48,"description":6463,"draft":932,"extension":933,"meta":6464,"navigation":935,"next":936,"ogTitle":6465,"path":47,"pin":932,"prev":936,"recommends":6466,"seo":6467,"sitemap":6468,"stem":6510,"tags":6511,"updated":936,"__hash__":6512},"content\u002Fblogs\u002F2025-08-26-xponology-on-old-pc.md","ติดตั้ง Xpenology บน PC เครื่องเก่ากัน",{"type":123,"value":6033,"toc":6455},[6034,6038,6041,6044,6047,6051,6054,6068,6071,6076,6079,6087,6090,6093,6103,6108,6111,6116,6127,6130,6133,6146,6151,6170,6175,6178,6182,6185,6190,6193,6198,6201,6206,6209,6214,6217,6222,6225,6230,6233,6238,6241,6246,6249,6254,6257,6262,6265,6270,6273,6278,6283,6286,6291,6294,6299,6302,6307,6310,6314,6322,6327,6330,6335,6340,6345,6348,6353,6358,6363,6366,6371,6374,6379,6382,6387,6392,6395,6400,6403,6408,6413,6416,6421,6424,6429,6432,6437,6441],[139,6035,6037],{"id":6036},"xpenology-คืออะไร","Xpenology คืออะไร?",[126,6039,6040],{},"Xpenology เป็นส่วนของซอฟต์แวร์แบบ “bootloader” ที่ทำให้ระบบปฏิบัติการของ Synology ซึ่งเรียกว่า DSM (DiskStation Manager) สามารถรันบน hardware ทั่วไปได้ แทนที่จะต้องใช้เฉพาะเครื่อง NAS ของ Synology เท่านั้น",[126,6042,6043],{},"DSM เป็นระบบปฏิบัติการที่ Synology พัฒนาบน Linux ออกแบบมาเพื่อทำงานบนเครื่อง NAS มีฟีเจอร์ที่จำเป็นสำหรับการเก็บข้อมูล แชร์ไฟล์ steaming และอื่น ๆ อีกมากมาย",[126,6045,6046],{},"ซึ่งการติดตั้ง Xpenology พูดง่าย ๆ คือการที่จะทำให้เราสามารถใช้งาน Synology OS บน Hardware ทั่ว ๆ ไปได้นั่นเอง โดยในวันนี้ผมจะมาติดตั้งบน PC เครื่องเก่ากันนะครับ",[139,6048,6050],{"id":6049},"hardware-วันนี้","Hardware วันนี้",[126,6052,6053],{},"โดยเครื่องนี้จะเป็น",[707,6055,6056,6059,6062,6065],{},[710,6057,6058],{},"CPU: I3 7100",[710,6060,6061],{},"Ram: 8GB DDR4",[710,6063,6064],{},"HDD: 1TB 2 ลูก",[710,6066,6067],{},"SSD: 256GB สำหรับติดตั้ง OS",[126,6069,6070],{},"โดย PC เครื่องนี้ผมซื้อมือ 2 มาจาก facebook marketplace โดยตอนซื้อมาจะมีแค่ CPU, RAM, HDD 1 ลูก โดยเงื่อนไขของการทำ DIY NAS ของผมคือต้องใส่ HDD อย่างน้อยได้ 2 ลูก เพื่อทำ RAID 1 (RAID Software ก็ได้)",[126,6072,6073],{},[3766,6074],{"alt":169,"src":6075},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-e8de1f9e-b6b3-4964-9299-d404f3f70541.jpg",[126,6077,6078],{},"ปัญหาต่อมาคืออยากจะใช้ SSD เพื่อทำให้ OS ทำงานได้ไวขึ้น มี 2 ทางเลือกครับ (บอร์ดรุ่นเก่าไม่มีช่อง M.2 ให้เสียบ sadddd)",[707,6080,6081,6084],{},[710,6082,6083],{},"ซื้อ SSD แบบ SATA มาเสียบเพิ่ม เพราะช่อง SATA มี 4 ช่อง (ใช้ไปแล้ว 2)",[710,6085,6086],{},"ซื้อตัวแปร PCI-E เป็น M.2 แล้วเสียบ SSD แบบ M.2",[126,6088,6089],{},"ตอนแรกทางเลือกแรกคือทางเลือกที่ดีสำหรับผม แต่แล้วเมื่อตรวจสอบสายไฟจาก POWER แล้วก็ทำให้น้ำตาไหล เพราะว่ามีสายไฟสำหรับ HDD แค่ 2 ช่อง (ใช้ครบแล้ว) เลยทำให้ต้องไปทางเลือกที่ 2 นั่นก็คือซื้อ PCE to M.2",[126,6091,6092],{},"สิ่งที่ลุ้นและขี้เกียจก็คือซื้อมาแล้ว Mainboard จะรองรับมั้ย ซึ่งตามหลัก Engineer ก็คือต้องเปิด Datasheet เพื่อหาข้อมูล แต่ไม่ทำ (5555) ซื้อเลย ได้ไม่ได้ค่อยว่ากันอีกที เพราะตั้งใจจะทำ DIY อยู่แล้ว เลยไปเจอใน shopee มาครับเป็นตัวนี้",[126,6094,6095,6098,6099],{},[390,6096,6097],{},"JEYI PCIe X4 to M.2 NVMe",": ",[292,6100,6101],{"href":6101,"rel":6102},"https:\u002F\u002Fs.shopee.co.th\u002FVwlrEE0hL",[296],[126,6104,6105],{},[3766,6106],{"alt":169,"src":6107},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-1183b11d-997c-413e-aa3a-f0caf0a40d9d.jpg",[126,6109,6110],{},"เมื่อประกอบ SSD เข้าไปจะหน้าตาประมาณนี้ครับ",[126,6112,6113],{},[3766,6114],{"alt":169,"src":6115},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-43be6af3-b251-4c21-86fd-37d63fa4d4aa.jpg",[707,6117,6118,6121,6124],{},[710,6119,6120],{},"โดย Adapter ตัวนี้จะเสียบลงไปที่ช่อง PCI-E ได้ทั้ง x4 x8 x16 เลย",[710,6122,6123],{},"SSD ตัวนี้เป็น M.2 NVME Gen 4 ความเร็วก็คือวิ่งได้ที่ระดับ Gen 4 เลยครับ",[710,6125,6126],{},"รองรับ mainboard ในหลาย ๆ รุ่นจากที่ลองหาข้อมูลดูนะครับ ตัวอย่างผมซื้อมาใช้กับ Asrock H11M-K รุ่นค่อนข้างเก่าเลย แต่ก็ยังใช้งานได้",[126,6128,6129],{},"ต่อไปมาเริ่มติดตั้ง OS กันครับ ~",[139,6131,6132],{"id":6132},"เตรียมการก่อนเริ่มติดตั้ง",[812,6134,6135],{},[710,6136,6137,6138,6142,6143],{},"download img จาก ",[292,6139,6140],{"href":6140,"rel":6141},"https:\u002F\u002Fgithub.com\u002FAuxXxilium\u002Farc\u002Freleases\u002F",[296]," โดยเลือกเป็น .img.zip นะครับ โดยในตัวอย่างผมติดตั้งเป็น version ",[5465,6144,6145],{},"2.6.5",[126,6147,6148],{},[3766,6149],{"alt":169,"src":6150},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-d9342298-65c4-4b3d-925d-b18be0afcfdb.jpg",[812,6152,6153,6164],{"start":236},[710,6154,6155,6156,6160,6161],{},"สำหรับโปรแกรมที่ใช้การสร้าง bootloader ผมจะใช้เป็น ตัวนี้นะครับ สามารถโหลดได้จาก ",[292,6157,6158],{"href":6158,"rel":6159},"https:\u002F\u002Fetcher.balena.io",[296]," ผมใช้ตัวนี้เป็นประจำ หากมีเครื่องมือตัวอื่นที่ถนัดก็สามารถใช้ได้เหมือนกัน",[3766,6162],{"alt":169,"src":6163},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-be9017e4-edbe-41bc-8b98-67ae7ec9e1f2.jpg",[710,6165,6166,6167],{},"ต้องมี Flashdrive ขนาด 4GB++ ด้วยนะครับ โดยเลือก image เป็น ARC ส่วนของ Target Drive ก็เลือกเป็น Flashdrive แล้วนั่งรอได้เลย ",[3766,6168],{"alt":169,"src":6169},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-a68d5af0-d0c5-46e5-92f6-e5b6cb141946.jpg",[126,6171,6172],{},[3766,6173],{"alt":169,"src":6174},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-dce47f43-fc8c-41e3-880b-ee970b3c54ce.jpg",[126,6176,6177],{},"เมื่อเสร็จแล้วสามารถนำไปเสียบกับ PC แล้วเลือกให้ Boot จาก Flashdrive ได้เลย (วิธีการขึ้นอยู่กับ Hardware โดยปกติก็เข้า bios แล้วปรับให้ boot จาก flashdrive ก่อนได้เลย)",[139,6179,6181],{"id":6180},"ติดตั้ง-xpenology","ติดตั้ง Xpenology",[126,6183,6184],{},"ของผมจะเป็น Mainboard ASUS เมื่อเข้ามา Bios ได้แล้วให้กด F8 แล้วเลือก Flashdrive",[126,6186,6187],{},[3766,6188],{"alt":169,"src":6189},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-a9e1330c-551a-48b3-9be2-44cef6cfc9af.jpg",[126,6191,6192],{},"กด Arc Config Mode เพื่อเริ่มการตั้งค่าได้เลย (ผมเองก็ยังมือใหม่นะ ลองผิดลองถูกมาหลายรอบเหมือนกัน 5555)",[126,6194,6195],{},[3766,6196],{"alt":169,"src":6197},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-684d99e1-c4dc-4992-929c-1f2c43c233d3.jpg",[126,6199,6200],{},"Choose Model",[126,6202,6203],{},[3766,6204],{"alt":169,"src":6205},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-103a577d-9d02-497d-b32e-f0134880c992.jpg",[126,6207,6208],{},"ผมจะเลือกเป็น DS920+ (แนะนำให้เลือกเป็นตัวที่มี + จะทำอะไรได้เยอะกว่า)",[126,6210,6211],{},[3766,6212],{"alt":169,"src":6213},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-4ec24e02-3a07-4e8d-9715-ade4c1fc5a13.jpg",[126,6215,6216],{},"ขั้นตอนนี้ผมจะเลือกเป็น No นะเพื่อดูการตั้งค่าเพิ่มเติม",[126,6218,6219],{},[3766,6220],{"alt":169,"src":6221},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-50b1276f-aebd-4e3d-b2d8-c2e422ac2d65.jpg",[126,6223,6224],{},"เลือกเป็น \"Use random SN\u002FMac (Reduced DSM Features)\"",[126,6226,6227],{},[3766,6228],{"alt":169,"src":6229},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-168b3668-464c-4bdc-b74a-55377d806109.jpg",[126,6231,6232],{},"ติดตั้ง Addons ผมจะเลือกเป็น default ไปเลยครับ",[126,6234,6235],{},[3766,6236],{"alt":169,"src":6237},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-86186fc1-f851-4d02-b009-3ad9ca1bf2cb.jpg",[126,6239,6240],{},"ในส่วนของ Power option จะเลือกเป็น conservative ตามคำแนะนำเลย เพราะจะ balance ระหว่าง performance และการประหยัดไฟ แต่ถ้าใครอยากประหยัดไฟสุด ๆ ก็เลือกเป็น powersave ได้เหมือนกันนะ",[126,6242,6243],{},[3766,6244],{"alt":169,"src":6245},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-7d83a70d-3bea-40d7-9c1a-1fcbc8417e19.jpg",[126,6247,6248],{},"ผมจะยังไม่ build ครับ จะไปแก้ไขการตั้งค่าเพิ่มเติมอีกนิด",[126,6250,6251],{},[3766,6252],{"alt":169,"src":6253},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-adab944f-3d00-4f12-ab3c-cb24e08f2fee.jpg",[126,6255,6256],{},"จากนั้นผมจะ Format Disk ตัวหลักสำหรับลง OS ไป โดยเลือกในหัวข้อ \"Show Loader Options\" แล้วไปที่ \"Format Disks\"",[126,6258,6259],{},[3766,6260],{"alt":169,"src":6261},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-9fa91ef7-7702-473e-afd2-9001bf83ea29.jpg",[126,6263,6264],{},"เลือก drive ที่ต้องการ format ในที่นี้ผมจะ format \u002Fdev\u002Fnvme0 นะครับ",[126,6266,6267],{},[3766,6268],{"alt":169,"src":6269},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-ccd646d7-e3cb-4478-a9af-43162f3393c2.jpg",[126,6271,6272],{},"จากนั้นผมจะทำการ Clone bootloader จาก flashdrive ไปยัง SSD ที่ได้มีการ format ในขั้นตอนก่อนหน้า",[126,6274,6275],{},[3766,6276],{"alt":169,"src":6277},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-972237ff-6eb8-4809-b141-86dd087ac4a2.jpg",[126,6279,6280],{},[3766,6281],{"alt":169,"src":6282},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-a2e1e489-d07d-45c1-a477-aaf84a95f1cf.jpg",[126,6284,6285],{},"จากนั้นก็นั่งรอระบบทำการ Clone ให้ครับ",[126,6287,6288],{},[3766,6289],{"alt":169,"src":6290},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-81d93c17-e52b-4e7c-ba52-f6a58d8a456e.jpg",[126,6292,6293],{},"เมื่อเสร็จแล้วก็ให้ถอด flashdrive ออกได้เลยย แล้วก็ reboot ได้เลยครับ",[126,6295,6296],{},[3766,6297],{"alt":169,"src":6298},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-baf17eec-c164-4342-a35c-06d5f8d2fc14.jpg",[126,6300,6301],{},"ระบบจะ boot แล้วกลับมาหน้านี้ (อย่าลืมถอด flashdrive ก่อนนะ ไม่งั้นอาจจะยังเป็นการ boot จาก flashdrive อยู่)",[126,6303,6304],{},[3766,6305],{"alt":169,"src":6306},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-55c9740c-54ab-4047-bf63-3d32566019f5.jpg",[126,6308,6309],{},"ถ้ายังใช้ไม่ได้ให้กด Arc Config Mode -> Build อีกทีดูนะครับ",[139,6311,6313],{"id":6312},"setup-synology","Setup Synology",[126,6315,6316,6317,6321],{},"เปิด Browser เข้าไปที่ ",[292,6318,6319],{"href":6319,"rel":6320},"http:\u002F\u002Ffinds.synology.com\u002F",[296]," จากนั้นจะเจอกับ synology เครื่องใหม่ของเราครับ ตรง model name อาจจะยังไม่ตรงอยู่ไม่เป็นไร",[126,6323,6324],{},[3766,6325],{"alt":169,"src":6326},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-f8a9ccd4-c797-4619-8fef-2f3ebcb2b754.jpg",[126,6328,6329],{},"จากนั้นก็ Next Next Next",[126,6331,6332],{},[3766,6333],{"alt":169,"src":6334},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-53c51d89-810e-4606-8fb5-9a9764e17bd5.jpg",[126,6336,6337],{},[3766,6338],{"alt":169,"src":6339},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-5d0ad6a6-f349-4b30-8e49-a72a2d74576c.jpg",[126,6341,6342],{},[3766,6343],{"alt":169,"src":6344},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-466bd21f-e423-4a16-860c-f83d875cc79f.jpg",[126,6346,6347],{},"แล้วก็นั่งรอแบบ จ๊อง จ๊อง",[126,6349,6350],{},[3766,6351],{"alt":169,"src":6352},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-fde692f4-1653-4fb8-a25d-45f786e58ea1.jpg",[126,6354,6355],{},[3766,6356],{"alt":169,"src":6357},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-b0d91faa-8ab0-42b5-ba03-36dd055ec016.jpg",[126,6359,6360],{},[3766,6361],{"alt":169,"src":6362},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-04e06b92-7e9c-498a-a82b-3d35afd09afa.jpg",[126,6364,6365],{},"ตรงนี้ก็ตั้ง user\u002Fpassword ได้เลย บาง step ผมจะข้าม ๆ ไปนะ ใช้ sense ได้เลยครับ",[126,6367,6368],{},[3766,6369],{"alt":169,"src":6370},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-af6b4954-f9d3-4073-896d-35efcbf2acff.jpg",[126,6372,6373],{},"ต่อมาจะเป็นการตั้งค่า storage นะ",[126,6375,6376],{},[3766,6377],{"alt":169,"src":6378},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-41946753-83ef-4480-b1c7-394b639a4540.jpg",[126,6380,6381],{},"โดยผมจะเลือกเป็น RAID 1 คือ 2 ลูก mirror กัน",[126,6383,6384],{},[3766,6385],{"alt":169,"src":6386},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-a7392138-9df9-499e-8feb-3f4c0febc9f9.jpg",[126,6388,6389],{},[3766,6390],{"alt":169,"src":6391},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-a7b843e5-fdf7-4fc6-905f-f385b3e7ca26.jpg",[126,6393,6394],{},"ขั้นตอนนี้จะเป็นการตรวจสอบสภาพของ HDD แนะนำให้ทำก่อนก็ดีครับ จะได้มั่นใจว่าข้อมูลจะไม่หาย",[126,6396,6397],{},[3766,6398],{"alt":169,"src":6399},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-2df346bb-85da-430e-8746-fd2fe051f056.jpg",[126,6401,6402],{},"โดยความจุของ RAID 1 จะเป็นไปตามขนาดของ Disk ที่เล็กที่สุด ให้กดปุ่ม Max เพื่อตั้งค่าได้เลย",[126,6404,6405],{},[3766,6406],{"alt":169,"src":6407},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-31528bb1-07aa-4938-919f-b54efcc45b23.jpg",[126,6409,6410],{},[3766,6411],{"alt":169,"src":6412},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-f7f0e1e1-2a27-4835-91a5-3460b11d78fb.jpg",[126,6414,6415],{},"ตรงนี้แนะนำให้เปิด Disk Encryption ด้วยครับ",[126,6417,6418],{},[3766,6419],{"alt":169,"src":6420},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-b5ee381d-566a-4e8c-9295-056fbd02ebe7.jpg",[126,6422,6423],{},"แล้วรอนั่งรอตัวระบบทำการตรวจสอบ Health ของ Disk ครับ",[126,6425,6426],{},[3766,6427],{"alt":169,"src":6428},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-c1934bff-cdb7-47de-89ea-cfa4e381613b.jpg",[126,6430,6431],{},"เรียบร้อยแล้วครับ เพียงเท่านี้เราก็จะมี Synology ใช้บน Hardware ที่เราเลือกเองได้ ผิดถูกตรงไหนขออภัยด้วยครับ หวังว่าจะพอเป็นแนวทางให้ได้ หากต้องการใช้งานจริงจังแนะนำอ่าน Docs ของทาง Xpenology เพิ่มเติมจะได้ข้อมูลที่แม่นยำมากยิ่งขึ้นฮะ",[126,6433,6434],{},[3766,6435],{"alt":169,"src":6436},"\u002Fimages\u002F2025-08-26-xponology-on-old-pc\u002Fimages-12cdc78c-2d2e-4b00-9fac-a475d6b2404a.jpg",[139,6438,6440],{"id":6439},"references","References",[707,6442,6443,6449],{},[710,6444,6445],{},[292,6446,6447],{"href":6447,"rel":6448},"https:\u002F\u002Fgithub.com\u002FAuxXxilium\u002Farc",[296],[710,6450,6451],{},[292,6452,6453],{"href":6453,"rel":6454},"https:\u002F\u002Fxpenology.org\u002F",[296],{"title":169,"searchDepth":236,"depth":236,"links":6456},[6457,6458,6459,6460,6461,6462],{"id":6036,"depth":236,"text":6037},{"id":6049,"depth":236,"text":6050},{"id":6132,"depth":236,"text":6132},{"id":6180,"depth":236,"text":6181},{"id":6312,"depth":236,"text":6313},{"id":6439,"depth":236,"text":6440},"วิธีลง Xpenology เพื่อให้ Synology DSM รันบน PC เครื่องเก่า กลายเป็น NAS ไว้ใช้เองที่บ้าน",{},"How To Setup Xpenology",[5643],{"title":6031,"description":6463},{"loc":47,"images":6469,"lastmod":48},[6470,6471,6472,6473,6474,6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,6508,6509],{"loc":6075},{"loc":6107},{"loc":6115},{"loc":6150},{"loc":6163},{"loc":6169},{"loc":6174},{"loc":6189},{"loc":6197},{"loc":6205},{"loc":6213},{"loc":6221},{"loc":6229},{"loc":6237},{"loc":6245},{"loc":6253},{"loc":6261},{"loc":6269},{"loc":6277},{"loc":6282},{"loc":6290},{"loc":6298},{"loc":6306},{"loc":6326},{"loc":6334},{"loc":6339},{"loc":6344},{"loc":6352},{"loc":6357},{"loc":6362},{"loc":6370},{"loc":6378},{"loc":6386},{"loc":6391},{"loc":6399},{"loc":6407},{"loc":6412},{"loc":6420},{"loc":6428},{"loc":6436},"blogs\u002F2025-08-26-xponology-on-old-pc",[945],"gGZH5UL3ZflPGqnVh78rQMJkFFZ9op05OMOC9phQn9s",{"id":6514,"title":6515,"body":6516,"date":54,"description":6617,"draft":932,"extension":933,"meta":6618,"navigation":935,"next":936,"ogTitle":6619,"path":53,"pin":932,"prev":936,"recommends":6620,"seo":6621,"sitemap":6622,"stem":6626,"tags":6627,"updated":936,"__hash__":6628},"content\u002Fblogs\u002F2025-09-19-chuwi-minibook-x.md","Chuwi Minibook X Linux แบบพกพาง่าย",{"type":123,"value":6517,"toc":6612},[6518,6521,6526,6529,6533,6536,6547,6550,6553,6556,6561,6566,6580,6585,6596,6603,6606,6609],[126,6519,6520],{},"เบื่อไหมกับการที่ต้องพก Notebook ขนาดใหญ่ไปไหนมาไหนแล้วมันไม่สะดวก หรือจะเป็นการที่อยากได้ Notebook ขนาดเล็ก ๆ เอาไว้พกพาไปใช้งาน (ขำ ๆ) วันนี้ผมเจอ Notebook รุ่นนึงมานำเสนอครับ นั่นก็คืออออ \"Chuwi minibook X\" นั่นเอง",[126,6522,6523],{},[3766,6524],{"alt":169,"src":6525},"\u002Fimages\u002F2025-09-19-chuwi-minibook-x\u002Fpreview.jpg",[126,6527,6528],{},"เอาจริง ๆ ผมเองก็เพิ่งเคยได้ยินชื่อแบรนนี้เมื่อไม่กี่วันก่อนมาจากใน Reddit ครับ ด้วยความที่กำลังมองหา Notebook ขนาดเล็ก เอามาลง Linux เพื่อใช้งานตอนที่ไม่ได้จริงจังมาก ก็เลยได้ยินคนในกลุ่มแนะนำรุ่นนี้มา เลยลองมาหาข้อมูลดูก็พบว่ามีขายในไทยด้วย !!",[139,6530,6532],{"id":6531},"spec","Spec",[126,6534,6535],{},"สิ่งที่ทำให้ผมตัดสินใจซื้อคือตัว CPU ครับ ส่วนตัวผมเองชอบ CPU ตระกูล N ของ Intel อยู่แล้ว เช่น N95, N100, N150 ซึ่งเป็น CPU ที่ประหยัดพลังงาน แต่ก็ยังคงประสิทธิภาพไว้อยู่ (ผมมี Mini PC ที่เป็น N100 รันอยู่ปีกว่าแล้วครับนิ่ง ๆ เลย) โดย Notebook รุ่นนี้ที่ผมได้มาเป็น Spec",[707,6537,6538,6541,6544],{},[710,6539,6540],{},"CPU: N150",[710,6542,6543],{},"Ram: 16GB",[710,6545,6546],{},"SSD: 512GB",[126,6548,6549],{},"จริง ๆ Spec ลองไปดูใน website ก็ได้นะครับ ในส่วนอื่น ๆ อีกอย่างที่ผมชอบคือขนาดเพียง 10\" นิด ๆ แต่มี Keyboard + Trackpad มาให้ด้วย รุ่นนี้เป็นจอ Touch Screen พลิกกลับไปเป็น Tablet ได้ด้วยนะะ",[139,6551,6552],{"id":6552},"รีวิวส่วนตัว",[126,6554,6555],{},"จากที่ผมลองใช้งานมานะครับ ผมขอสรุปเป็นข้อดีข้อเสียดังนี้",[126,6557,6558],{},[3766,6559],{"alt":169,"src":6560},"\u002Fimages\u002F2025-09-19-chuwi-minibook-x\u002Fbtop.jpg",[126,6562,6563],{},[390,6564,6565],{},"ข้อดี",[707,6567,6568,6571,6574,6577],{},[710,6569,6570],{},"ขนาดเล็ก พกพาง่าย",[710,6572,6573],{},"CPU N150 ทำงานได้ค่อนข้างดี เหมาะกับงานที่ไม่ได้หนักมาก",[710,6575,6576],{},"มี Keyboard และ Trackpad ซึ่งความรู้สึกในการใช้งานคือดีเลย ไม่ก๊องแก๊ง",[710,6578,6579],{},"Port การเชื่อมต่อ Type-C ชาร์จได้ ต่อจอได้ (ผมลองเสียบกับจอ Dell ของผมที่เป็น Type C แบบ one-wire ใช้งานได้ปกติ)",[126,6581,6582],{},[390,6583,6584],{},"ข้อเสีย",[707,6586,6587,6590,6593],{},[710,6588,6589],{},"นิ้วเบียด พิมพ์ผิดบ่อย ด้วยความที่ keyboard ขนาดเล็กครับ ฝั่งซ้ายมันจะเล็ก (zone: Tab, Capslock, Shift) เลยทำให้จังหวะแรกที่พิมพ์ผมมักพิมพ์ผิดบ่อย ๆ",[710,6591,6592],{},"เครื่องร้อนง่าย (แต่พอเปลี่ยนซิริโคลนแล้วดีขึ้นนะครับ)",[710,6594,6595],{},"UI ตอน Boot จะบัค ถ้าเอามาลง Linux",[126,6597,6598,6599],{},"แต่โดยรวม ๆ ผมให้ 8\u002F10 ครับ ตอนที่ตัดสินใจซื้อมาจริง ๆ แล้วก็ไม่ได้คาดหวังว่ามันจะออกมา perfect หรอกครับ แต่แค่นี้ผมก็รู้สึกไม่ผิดหวังแล้ว ราคาใน Shopee ปกติจะอยู่ที่ประมาณ 12XXX บาทครับ แต่ผมได้ช่วง Flash Sell + 9.9 มาเหลือประมาณ 89XX บาท (ถูกมากกก) ผมกดจากอันนี้ฮะ ",[292,6600,6601],{"href":6601,"rel":6602},"https:\u002F\u002Fs.shopee.co.th\u002FqaEfmoOmu",[296],[139,6604,6605],{"id":6605},"สุดท้าย",[126,6607,6608],{},"ความตั้งใจของผมคือเอาพกติดกระเป๋าเอาไว้ใช้งานตอนออกไปข้างนอก เผื่อต้อง remote ไปทำอะไรที่มันด่วน ๆ จะได้ทำได้เลย เพราะเครื่องนี้น้ำหนักประมาณ 1KG ครับ เบามาก ก่อนหน้านี้เคยลองซื้อ IPAD Mini 7 + Keyboard Case มา แต่ก็ไม่ไหวพกพาไม่สะดวกเลยครับ พอมาเจอตัวนี้ ง่ายขึ้นเยอะะะะ",[126,6610,6611],{},"ตัดสินใจลงเป็น Linux Ubuntu เอาไว้ ต้องมานั่ง Custom พอสมควรเลยเช่น Tablet mode, Touch Screen ใช้เวลาพอสมควรเลย แต่ก็สนุกดีครับ หาอะไรลองเล่นไปเรื่อยยยย ~",{"title":169,"searchDepth":236,"depth":236,"links":6613},[6614,6615,6616],{"id":6531,"depth":236,"text":6532},{"id":6552,"depth":236,"text":6552},{"id":6605,"depth":236,"text":6605},"รีวิว Notebook พกพาขนาดเล็กกก เอามาเป็นเครื่องไว้ใช้งานสำหรับ Remote โดยการติดตั้ง Ubuntu Desktop",{},"Chuwi Miniboox X",[3835,3190],{"title":6515,"description":6617},{"loc":53,"images":6623,"lastmod":54},[6624,6625],{"loc":6525},{"loc":6560},"blogs\u002F2025-09-19-chuwi-minibook-x",[945],"39crprPELFtWcQ2lmFA-1U4ieVYB8bbvP_cU5cdUFwY",{"id":6630,"title":6631,"body":6632,"date":57,"description":6835,"draft":932,"extension":933,"meta":6836,"navigation":935,"next":4631,"ogTitle":6837,"path":56,"pin":932,"prev":5402,"recommends":6838,"seo":6839,"sitemap":6840,"stem":6850,"tags":6851,"updated":936,"__hash__":6852},"content\u002Fblogs\u002F2025-10-03-typhoon-ai-n8n.md","วิธีการนำ Typhoon AI มาใช้งานใน N8N",{"type":123,"value":6633,"toc":6830},[6634,6638,6641,6644,6648,6715,6719,6722,6736,6741,6746,6751,6756,6761,6766,6771,6776,6782,6787,6792,6797,6802,6808,6811,6817,6822,6825],[139,6635,6637],{"id":6636},"typhoon-ai-คืออะไร","Typhoon AI คืออะไร",[126,6639,6640],{},"Typhoon AI มีการพัฒนาในส่วนของ API ในรูปแบบของ Openai compatible api ซึ่งเป็นมาตรฐานของการพัฒนา API ของ AI ในปัจจุบันอยู่แล้วครับ นั่นหมายความว่าถ้าเดิม ๆ ใช้ของ OpenAI ได้ ก็จะสามารถเปลี่ยนมาใช้ของตัวอื่นได้ด้วยเช่นเดียวกัน โดยทำแค่เพียงเปลี่ยน URL ที่ใช้ในการเชื่อมต่อ",[126,6642,6643],{},"ด้วยความที่ model นี้สามารถนำมาใช้ได้ฟรีก็แนะนำว่าไม่ควรนำมาใช้ในเชิงพาณิชย์ นะครับ",[139,6645,6647],{"id":6646},"ข้อจำกัดในปัจจุบัน-update-311068","ข้อจำกัดในปัจจุบัน (update 31\u002F10\u002F68)",[592,6649,6650,6674],{},[595,6651,6652],{},[598,6653,6654,6659,6664,6669],{},[601,6655,6656],{},[390,6657,6658],{},"Model",[601,6660,6661],{},[390,6662,6663],{},"Context Window",[601,6665,6666],{},[390,6667,6668],{},"Requests per Second",[601,6670,6671],{},[390,6672,6673],{},"Requests per Minute",[608,6675,6676,6690,6702],{},[598,6677,6678,6681,6684,6687],{},[613,6679,6680],{},"typhoon-v2.5-30b-a3b-instruct",[613,6682,6683],{},"128K tokens",[613,6685,6686],{},"5",[613,6688,6689],{},"200",[598,6691,6692,6695,6698,6700],{},[613,6693,6694],{},"typhoon-v2.1-12b-instruct",[613,6696,6697],{},"56K tokens",[613,6699,6686],{},[613,6701,6689],{},[598,6703,6704,6707,6709,6712],{},[613,6705,6706],{},"typhoon-ocr",[613,6708,3711],{},[613,6710,6711],{},"2",[613,6713,6714],{},"20",[139,6716,6718],{"id":6717},"วิธีการนำมาใช้งานใน-n8n","วิธีการนำมาใช้งานใน N8N",[126,6720,6721],{},"มาเริ่มกันเลยฮะ",[812,6723,6724],{},[710,6725,6726,6727,6731,6732],{},"สมัคร User ที่ ",[292,6728,6729],{"href":6729,"rel":6730},"https:\u002F\u002Fplayground.opentyphoon.ai\u002F",[296]," เพื่อขอใช้ API Key (ตรงนี้ Free นะ) โดยจะมี Rate limit และเงื่อนไขการใช้งานเพิ่มเติมแนะนำให้อ่านต่อที่ ",[292,6733,6734],{"href":6734,"rel":6735},"https:\u002F\u002Fdocs.opentyphoon.ai\u002Fen\u002Frate-limits\u002F",[296],[126,6737,6738],{},[3766,6739],{"alt":169,"src":6740},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-1.png",[812,6742,6743],{"start":236},[710,6744,6745],{},"จากนั้นสามารถ Copy API Key ไว้ได้เลยฮะ ตามรูปนี้เลย",[126,6747,6748],{},[3766,6749],{"alt":169,"src":6750},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-2.png",[812,6752,6753],{"start":242},[710,6754,6755],{},"กลับมาที่ N8N ของเราแล้วกด \"Create Credential\"",[126,6757,6758],{},[3766,6759],{"alt":169,"src":6760},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-3.png",[812,6762,6763],{"start":248},[710,6764,6765],{},"โดยเลือกเป็น \"OpenAi\" ได้เลยครับ",[126,6767,6768],{},[3766,6769],{"alt":169,"src":6770},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-4.png",[812,6772,6773],{"start":254},[710,6774,6775],{},"นำ API Key ที่ Copy ไว้มาใส่ และแก้ตรง Base URL ให้เป็น",[164,6777,6780],{"className":6778,"code":6779,"language":529},[527],"https:\u002F\u002Fapi.opentyphoon.ai\u002Fv1\n",[171,6781,6779],{"__ignoreMap":169},[126,6783,6784],{},[3766,6785],{"alt":169,"src":6786},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-6.png",[812,6788,6789],{"start":2112},[710,6790,6791],{},"จากนั้นเวลาจะใช้งานก็สามารถเลือกเป็น \"OpenAI Chat Model\" ได้เลย",[126,6793,6794],{},[3766,6795],{"alt":169,"src":6796},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-5.png",[812,6798,6799],{"start":2129},[710,6800,6801],{},"ตรง \"Credential to connect with\" ให้เลือกเป็น typhoon ที่เราสร้างในขั้นตอนที่ 5 และเลือก Model โดยใช้ \"By ID\" และกรอกเป็น",[164,6803,6806],{"className":6804,"code":6805,"language":529},[527],"typhoon-v2.1-12b-instruct\n",[171,6807,6805],{"__ignoreMap":169},[126,6809,6810],{},"หรือ",[164,6812,6815],{"className":6813,"code":6814,"language":529},[527],"typhoon-v2.5-30b-a3b-instruct\n",[171,6816,6814],{"__ignoreMap":169},[126,6818,6819],{},[3766,6820],{"alt":169,"src":6821},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-7.png",[126,6823,6824],{},"เรียบร้อยย เพียงแค่นี้เราก็จะสามารถใช้งาน typhoon AI ด้วย N8N ได้แล้วคับ Enjoy ฮะะ",[126,6826,6827],{},[3766,6828],{"alt":169,"src":6829},"\u002Fimages\u002F2025-10-03-typhoon-ai-n8n\u002Ftyphoon-8.png",{"title":169,"searchDepth":236,"depth":236,"links":6831},[6832,6833,6834],{"id":6636,"depth":236,"text":6637},{"id":6646,"depth":236,"text":6647},{"id":6717,"depth":236,"text":6718},"วันนี้จะมาแนะนำวิธีการนำ Typhoon AI ซึ่งเป็น AI ของคนไทย มาใช้งานใน N8N",{},"Typhoon AI With N8N",[4634],{"title":6631,"description":6835},{"loc":56,"images":6841,"lastmod":57},[6842,6843,6844,6845,6846,6847,6848,6849],{"loc":6740},{"loc":6750},{"loc":6760},{"loc":6770},{"loc":6786},{"loc":6796},{"loc":6821},{"loc":6829},"blogs\u002F2025-10-03-typhoon-ai-n8n",[944],"eU5CqbkKsBk_AfzAdsEixec5dvCLAbkAyr_rXgWE70w",{"id":6854,"title":6855,"body":6856,"date":60,"description":6932,"draft":932,"extension":933,"meta":6933,"navigation":935,"next":936,"ogTitle":6934,"path":59,"pin":932,"prev":936,"recommends":936,"seo":6935,"sitemap":6936,"stem":6937,"tags":6938,"updated":936,"__hash__":6939},"content\u002Fblogs\u002F2025-10-30-3d-printer-bambu-lab-a1.md","มือใหม่หัดเล่น 3D Printer (bambu lab a1) ปริ้นอะไรดี ?",{"type":123,"value":6857,"toc":6922},[6858,6862,6866,6874,6877,6881,6889,6892,6895,6903,6906,6910,6914],[139,6859,6861],{"id":6860},"แนะนำของที่ต้องมี-ด้วยการซื้อ","แนะนำของที่ต้องมี (ด้วยการซื้อ)",[139,6863,6865],{"id":6864},"_3d-printer-bambu-lab-a1","3D Printer Bambu Lab A1",[707,6867,6868],{},[710,6869,6870],{},[292,6871,6872],{"href":6872,"rel":6873},"https:\u002F\u002Fs.shopee.co.th\u002F6psUuYdq3G",[296],[126,6875,6876],{},"แนะนำตัวนี้เพราะว่า Plate มีขนาดถึง 26x26x26 เป็นขนาดที่พอเหมาะ ไม่เล็กและไม่ใหญ่จนเกินไป (ถ้าไปตัวเล็กกว่านี้จะพิมพ์อะไรได้น้อยกว่า)",[153,6878,6880],{"id":6879},"เส้น-3d-esun-pla","เส้น 3D ESun PLA",[707,6882,6883],{},[710,6884,6885],{},[292,6886,6887],{"href":6887,"rel":6888},"https:\u002F\u002Fs.shopee.co.th\u002F2g2vwxaUCS",[296],[126,6890,6891],{},"ลองเปลี่ยนมาหลายรุ่นแล้ว สุดท้ายก็มาจบที่ตัวนี้ครับ (มี profile บน bambu lab ด้วยนะเอออ)",[153,6893,6894],{"id":6894},"หัวพิมพ์สำรอง",[707,6896,6897],{},[710,6898,6899],{},[292,6900,6901],{"href":6901,"rel":6902},"https:\u002F\u002Fs.shopee.co.th\u002FgHrZLuAGC",[296],[126,6904,6905],{},"อันนี้ผมซื้อเอาไว้สำรองครับ เผื่อหัวหลักมีปัญหา เลยลองเอารุ่นทดแทนมาใช้ (ไม่ใช่ของแท้)",[139,6907,6909],{"id":6908},"ป้ายยา-model-3d-ที่เคยพิมพ์มา","ป้ายยา Model 3D ที่เคยพิมพ์มา",[153,6911,6913],{"id":6912},"นกฮูกสำหรับวางแว่นสุด-cute","นกฮูกสำหรับวางแว่นสุด Cute",[707,6915,6916],{},[710,6917,6918],{},[292,6919,6920],{"href":6920,"rel":6921},"https:\u002F\u002Fmakerworld.com\u002Fen\u002Fmodels\u002F580423-owl-glasses-holder",[296],{"title":169,"searchDepth":236,"depth":236,"links":6923},[6924,6925,6929],{"id":6860,"depth":236,"text":6861},{"id":6864,"depth":236,"text":6865,"children":6926},[6927,6928],{"id":6879,"depth":242,"text":6880},{"id":6894,"depth":242,"text":6894},{"id":6908,"depth":236,"text":6909,"children":6930},[6931],{"id":6912,"depth":242,"text":6913},"รวม item ที่ควรมีและ model ที่เคยพิมพ์จริงจากการเล่น 3D Printer Bambu Lab A1",{},"Bambu Lab A1",{"title":6855,"description":6932},{"loc":59,"lastmod":60},"blogs\u002F2025-10-30-3d-printer-bambu-lab-a1",[945],"Ygx1WYHhAT4I3YOm1Ts-Q0-ngpLzG_ZbYFxiYFMtbK0",{"id":6941,"title":6942,"body":6943,"date":69,"description":7020,"draft":932,"extension":933,"meta":7021,"navigation":935,"next":936,"ogTitle":7022,"path":68,"pin":932,"prev":936,"recommends":7023,"seo":7025,"sitemap":7026,"stem":7032,"tags":7033,"updated":3652,"__hash__":7034},"content\u002Fblogs\u002F2025-11-09-nanokvm-kvm.md","รีวิว nanokvm - kvm ขนาดเล็กพกพาง่าย",{"type":123,"value":6944,"toc":7013},[6945,6952,6957,6961,6964,6967,6970,6973,6976,6979,6982,6987,6992,6995,6998,7003,7005],[126,6946,6947,6948],{},"แวะมาป้ายยา item สำหรับสาย homelab ที่มีชื่อว่า nanovkm usb ",[292,6949,6950],{"href":6950,"rel":6951},"https:\u002F\u002Fwiki.sipeed.com\u002Fhardware\u002Fen\u002Fkvm\u002FNanoKVM_USB\u002Fintroduction.html",[296],[126,6953,6954],{},[3766,6955],{"alt":169,"src":6956},"\u002Fimages\u002F2025-11-09-nanokvm-kvm\u002Fnano_kvm_01.jpg",[139,6958,6960],{"id":6959},"nanokvm-usb-คืออะไร","NanoKVM USB คืออะไร",[126,6962,6963],{},"โดยความสามารถของอุปกรณ์ตัวนี้คือการเชื่อมสามารถใช้ type C 1 เส้น ในการแสดงผลภาพและส่ง mouse keyboard ของ macbook ไปยังเครื่องปลายทางได้ครับ",[139,6965,6966],{"id":6966},"วิธีการต่อ",[126,6968,6969],{},"ฝั่ง Host: เสียบ type C 1 เส้นเข้ากับอุปกรณ์ เช่น notebook, macbook ได้เลย",[126,6971,6972],{},"ฝั่ง Target: เสียบ HDMI, USB เพื่อส่งภาพและ virtual mouse keyboard ไปยังเครื่องปลายทาง",[139,6974,6975],{"id":6975},"ราคาและการสั่งซื้อ",[126,6977,6978],{},"โดยอุปกรณ์นี้ผมได้มาในราคาประมาณ 1200 บาท สามารถสั่งเว็บตรงของทางผู้ผลิตได้เลย ใช้เวลาจัดส่งประมาณ 2-3 สัปดาห์ครับ หลังจากได้ที่มาชอบมากกก เพราะทำให้ตอนที่ต้อง connect minipc, server, raspberry pi ไม่จำเป็นต้องเสียบหน้าจออีกต่อไป สามารถใช้ macbook ควบคุมได้เลย",[126,6980,6981],{},"จริง ๆ ยังมีอีกหลายรุ่นนะครับ แต่ผมกดรุ่นนี้มาเพราะรูปทรง + features เหมาะกับการใช้งานของผมพอดี",[126,6983,6984],{},[3766,6985],{"alt":169,"src":6986},"\u002Fimages\u002F2025-11-09-nanokvm-kvm\u002Fnano_kvm_02.jpg",[126,6988,6989],{},[3766,6990],{"alt":169,"src":6991},"\u002Fimages\u002F2025-11-09-nanokvm-kvm\u002Fnano_kvm_03.jpg",[139,6993,6994],{"id":6994},"หน้าตาตอนใช้งาน",[126,6996,6997],{},"สามารถใช้งานผ่าน web browser ได้เลย",[126,6999,7000],{},[3766,7001],{"alt":169,"src":7002},"\u002Fimages\u002F2025-11-09-nanokvm-kvm\u002Fnano_kvm_web.jpg",[139,7004,3618],{"id":3617},[707,7006,7007],{},[710,7008,7009],{},[292,7010,7012],{"href":6950,"rel":7011},[296],"NanoKVM USB - Sipeed Wiki",{"title":169,"searchDepth":236,"depth":236,"links":7014},[7015,7016,7017,7018,7019],{"id":6959,"depth":236,"text":6960},{"id":6966,"depth":236,"text":6966},{"id":6975,"depth":236,"text":6975},{"id":6994,"depth":236,"text":6994},{"id":3617,"depth":236,"text":3618},"รีวิว NanoKVM USB ตัวเล็ก ๆ ที่ใช้ type C เส้นเดียวคุม minipc, server, raspberry pi ได้โดยไม่ต้องเสียบจอ",{},"NanoKVM",[7024],"2025-10-30-3d-printer-bambu-lab-a1.md",{"title":6942,"description":7020},{"loc":68,"images":7027,"lastmod":69},[7028,7029,7030,7031],{"loc":6956},{"loc":6986},{"loc":6991},{"loc":7002},"blogs\u002F2025-11-09-nanokvm-kvm",[945],"ZUJj07Xb_3ZN0IqV4881THOwQb9PNiljmDKt5SGiNlQ",{"id":7036,"title":7037,"body":7038,"date":89,"description":7111,"draft":932,"extension":933,"meta":7112,"navigation":935,"next":936,"ogTitle":7113,"path":88,"pin":932,"prev":936,"recommends":936,"seo":7114,"sitemap":7115,"stem":7116,"tags":7117,"updated":3652,"__hash__":7118},"content\u002Fblogs\u002F2026-02-08-glm-4-7.md","GLM-4.7 มาแล้ว! โมเดลใหม่จาก Zhipu AI ที่เคลมว่าแรงแซง SOTA ทุกค่าย",{"type":123,"value":7039,"toc":7107},[7040,7051,7058,7062,7088,7091,7094],[126,7041,7042,7043,7046,7047,7050],{},"ช่วงนี้วงการ LLM แข่งกันดุเดือดมาก ล่าสุดทาง ",[390,7044,7045],{},"Zhipu AI"," ก็ไม่ยอมน้อยหน้า ปล่อยตัว ",[390,7048,7049],{},"GLM-4.7"," ออกมาท้าชนรุ่นพี่ในตลาดแบบไม่เกรงใจใคร",[126,7052,7053,7054,7057],{},"เท่าที่ลองส่องดูใน Blog และ Benchmark ที่เขาปล่อยมา รอบนี้เขาเน้นเรื่อง ",[390,7055,7056],{},"\"Super-high Intelligence\""," หรือความฉลาดในการแก้ปัญหาซับซ้อน (Complex Reasoning) แบบก้าวกระโดดครับ",[139,7059,7061],{"id":7060},"มีอะไรน่าสนใจบ้าง","มีอะไรน่าสนใจบ้าง?",[707,7063,7064,7070,7076,7082],{},[710,7065,7066,7069],{},[390,7067,7068],{},"Reasoning เทพขึ้น:"," ตัวนี้ถูกเทรนมาให้จัดการกับ Logic ยากๆ ได้ดีขึ้นมาก ฟีลคล้ายๆ กับพวกโมเดลตระกูล o1\u002FReasoning ของฝั่งตะวันตก",[710,7071,7072,7075],{},[390,7073,7074],{},"Coding เก่งขึ้น:"," สำหรับชาว Dev อย่างเรา นี่คือ Key Feature เลย GLM-4.7 เข้าใจ Context ของ Codebase และช่วย Debug หรือ Refactor ได้แม่นยำกว่ารุ่น 4.0 เดิมเยอะ",[710,7077,7078,7081],{},[390,7079,7080],{},"Universal Capability:"," ทำได้รอบด้านทั้ง Text, Code, Vision และ Function Calling ที่เสถียรขึ้นมาก เหมาะเอาไปต่อกับ Agent สุดๆ",[710,7083,7084,7087],{},[390,7085,7086],{},"Cost-effective:"," จุดขายของค่ายนี้คือความคุ้มค่า ประสิทธิภาพระดับ SOTA (State-of-the-Art) แต่ราคา API มักจะเป็นมิตรกว่าค่ายใหญ่ๆ ฝั่ง US",[139,7089,7090],{"id":7090},"ความรู้สึกส่วนตัว",[126,7092,7093],{},"ส่วนตัวผมเชียร์ค่าย GLM มาสักพักเพราะชอบความ \"Open\" และความเร็วในการตอบสนอง รอบนี้ถือว่าอัปเกรดมาน่ากลัวมาก ใครที่ทำพวก AI Agent หรือกำลังหา Model ทางเลือกที่ฉลาดแต่ประหยัด Token แนะนำให้ลองไปต่อ API เล่นดูครับ",[1031,7095,7096],{},[126,7097,7098,7101,7102],{},[390,7099,7100],{},"อ่านรายละเอียดเต็มๆ:"," ",[292,7103,7106],{"href":7104,"rel":7105},"https:\u002F\u002Fz.ai\u002Fblog\u002Fglm-4.7",[296],"Zhipu AI Blog - GLM-4.7",{"title":169,"searchDepth":236,"depth":236,"links":7108},[7109,7110],{"id":7060,"depth":236,"text":7061},{"id":7090,"depth":236,"text":7090},"สรุปจุดเด่น GLM-4.7 โมเดลล่าสุดจาก Zhipu AI ที่ยกระดับ Reasoning และ Coding ไปอีกขั้นในราคาที่จับต้องได้",{},"GLM-4.7 Review",{"title":7037,"description":7111},{"loc":88,"lastmod":89},"blogs\u002F2026-02-08-glm-4-7",[944],"UO7H5s6Y0Y4dWj1sLTybOzm9Cg-rTW7Vp_lVtQNIW9o",{"id":7120,"title":7121,"body":7122,"date":89,"description":7168,"draft":932,"extension":933,"meta":7169,"navigation":935,"next":936,"ogTitle":7170,"path":91,"pin":932,"prev":936,"recommends":936,"seo":7171,"sitemap":7172,"stem":7173,"tags":7174,"updated":7175,"__hash__":7176},"content\u002Fblogs\u002F2026-02-08-kimi-k2-5.md","Kimi K2.5: สรุปสั้น ๆ ว่ามีอะไรใหม่",{"type":123,"value":7123,"toc":7164},[7124,7127,7131,7151,7154,7157],[126,7125,7126],{},"Moonshot AI เปิดตัว Kimi K2.5 ผมไปอ่านข้อมูลเปิดตัวและลองใช้งานคร่าว ๆ เลยสรุปจุดที่น่าสนใจไว้ตรงนี้",[139,7128,7130],{"id":7129},"มีอะไรใหม่ใน-k25","มีอะไรใหม่ใน K2.5",[707,7132,7133,7139,7145],{},[710,7134,7135,7138],{},[390,7136,7137],{},"Reasoning:"," Moonshot AI เน้นความสามารถในการทำงานที่ต้องคิดและใช้เครื่องมือหลายขั้นตอน",[710,7140,7141,7144],{},[390,7142,7143],{},"Long Context:"," Kimi ยังรองรับงานอ่านเอกสารยาว เหมาะกับการสรุปหรือถามข้อมูลจากไฟล์หลายหน้า",[710,7146,7147,7150],{},[390,7148,7149],{},"Coding:"," ผมลองให้เขียนสคริปต์ Python และช่วยดูโค้ด รุ่นนี้ยังเป็นอีกตัวเลือกสำหรับใช้เป็นผู้ช่วยเขียนโค้ด",[139,7152,7153],{"id":7153},"เหมาะกับใคร",[126,7155,7156],{},"คนที่ใช้ Kimi อ่านเอกสารอยู่แล้วอาจลอง K2.5 กับไฟล์ที่ใช้ประจำ ส่วนคนเขียนโค้ดก็ลองส่งงานที่เคยให้โมเดลรุ่นก่อนทำ เพื่อดูว่าคำตอบตรงกับงานของตัวเองแค่ไหน",[126,7158,7159],{},[292,7160,7163],{"href":7161,"rel":7162},"https:\u002F\u002Fwww.kimi.ai\u002Fblog\u002Fkimi-k2-5",[296],"รายละเอียดจาก Moonshot AI",{"title":169,"searchDepth":236,"depth":236,"links":7165},[7166,7167],{"id":7129,"depth":236,"text":7130},{"id":7153,"depth":236,"text":7153},"สรุปจุดที่น่าสนใจของ Kimi K2.5 สำหรับงานอ่านเอกสารและเขียนโค้ด",{},"Kimi k2.5 Review",{"title":7121,"description":7168},{"loc":91,"lastmod":89},"blogs\u002F2026-02-08-kimi-k2-5",[944],"2026-10-18","P57YN1tnNf8-wLSE75UqavwGCzW2ogpqcXb1bhr6J14",{"id":7178,"title":7179,"body":7180,"date":89,"description":7272,"draft":932,"extension":933,"meta":7273,"navigation":935,"next":936,"ogTitle":7274,"path":93,"pin":932,"prev":936,"recommends":936,"seo":7275,"sitemap":7276,"stem":7277,"tags":7278,"updated":7175,"__hash__":7279},"content\u002Fblogs\u002F2026-02-08-n8n-skills.md","n8n-skills: สรุปสั้น ๆ ว่าช่วย Claude เขียน Workflow ยังไง",{"type":123,"value":7181,"toc":7267},[7182,7185,7193,7196,7232,7234,7237,7240,7254,7260],[126,7183,7184],{},"เวลาให้ AI ช่วยออกแบบ workflow ใน n8n ผมเจอทั้ง expression ที่เขียนผิดและการตั้งค่า node ที่ต้องกลับมาแก้เอง",[126,7186,7187,7192],{},[292,7188,7191],{"href":7189,"rel":7190},"https:\u002F\u002Fgithub.com\u002Fczlonkowski\u002Fn8n-skills",[296],"n8n-skills ของ czlonkowski"," เป็นชุดคำแนะนำสำหรับ Claude Code ที่รวบรวมเรื่องที่ใช้บ่อยเวลาเขียน workflow",[139,7194,7195],{"id":7195},"มีอะไรในชุดนี้",[707,7197,7198,7214,7220,7226],{},[710,7199,7200,7203,7204,843,7207,847,7210,7213],{},[390,7201,7202],{},"Expression Syntax:"," อธิบายการใช้ตัวแปรอย่าง ",[171,7205,7206],{},"$json",[171,7208,7209],{},"$node",[171,7211,7212],{},"$json.body"," สำหรับข้อมูลจาก Webhook",[710,7215,7216,7219],{},[390,7217,7218],{},"Workflow Patterns:"," มีแนวทางสำหรับงานอย่างรับ Webhook เรียก API และจัดการข้อมูลในฐานข้อมูล",[710,7221,7222,7225],{},[390,7223,7224],{},"Validation:"," ช่วยอ่าน error ที่ได้จากการตรวจ workflow",[710,7227,7228,7231],{},[390,7229,7230],{},"Node Configuration:"," อธิบายค่าที่ต้องตั้งใน node ตาม operation ที่เลือก",[139,7233,7153],{"id":7153},[126,7235,7236],{},"คนที่ใช้ Claude Code ช่วยสร้างหรือแก้ workflow ใน n8n โดยเฉพาะเวลาติดปัญหาเรื่อง expression หรือค่าของ node",[139,7238,7239],{"id":7239},"วิธีเริ่มใช้",[126,7241,7242,7243,7248,7249],{},"โปรเจกต์นี้ใช้ร่วมกับ ",[292,7244,7247],{"href":7245,"rel":7246},"https:\u002F\u002Fgithub.com\u002Fczlonkowski\u002Fn8n-mcp",[296],"n8n-mcp"," ให้ตั้งค่า MCP server ก่อน แล้วติดตั้ง plugin ใน Claude Code ตาม ",[292,7250,7253],{"href":7251,"rel":7252},"https:\u002F\u002Fgithub.com\u002Fczlonkowski\u002Fn8n-skills#installation",[296],"README",[164,7255,7258],{"className":7256,"code":7257,"language":529,"meta":169},[527],"\u002Fplugin install czlonkowski\u002Fn8n-skills\n",[171,7259,7257],{"__ignoreMap":169},[126,7261,7262,7263,7266],{},"ถ้าใช้ Claude.ai ให้ดาวน์โหลดโฟลเดอร์ skill ที่ต้องการจาก ",[171,7264,7265],{},"skills\u002F"," บีบเป็น ZIP แล้วอัปโหลดผ่าน Settings → Capabilities → Skills",{"title":169,"searchDepth":236,"depth":236,"links":7268},[7269,7270,7271],{"id":7195,"depth":236,"text":7195},{"id":7153,"depth":236,"text":7153},{"id":7239,"depth":236,"text":7239},"รู้จัก n8n-skills ชุดคำแนะนำสำหรับใช้ Claude Code ช่วยเขียนและแก้ Workflow ใน n8n",{},"n8n-skills",{"title":7179,"description":7272},{"loc":93,"lastmod":89},"blogs\u002F2026-02-08-n8n-skills",[944],"iDp34oxfQ843QWQ_owAi2f_0h0_9Nd4pFUOEQgXBmsQ",{"id":7281,"title":7282,"body":7283,"date":89,"description":7388,"draft":932,"extension":933,"meta":7389,"navigation":935,"next":936,"ogTitle":7390,"path":95,"pin":932,"prev":936,"recommends":7391,"seo":7392,"sitemap":7393,"stem":7394,"tags":7395,"updated":3652,"__hash__":7396},"content\u002Fblogs\u002F2026-02-08-nanobot-ai-agent.md","ลองเล่น Nanobot - AI Agent ไซส์มินิ (Python 4,000 บรรทัด)",{"type":123,"value":7284,"toc":7383},[7285,7295,7299,7305,7333,7337,7347,7350,7370,7372,7375],[126,7286,7287,7288,4778],{},"ช่วงนี้กระแส AI Agent มาแรงมาก แต่หลายตัวมักจะมาพร้อมกับ Framework ที่ใหญ่เทอะทะ หรือ Setup ยุ่งยากจนท้อไปก่อน วันนี้เลยอยากมาป้ายยาโปรเจกต์หนึ่งที่ไปเจอมา ชื่อว่า ",[390,7289,7290],{},[292,7291,7294],{"href":7292,"rel":7293},"https:\u002F\u002Fgithub.com\u002FHKUDS\u002Fnanobot",[296],"HKUDS\u002Fnanobot",[139,7296,7298],{"id":7297},"ทำไมถึงน่าสนใจ","ทำไมถึงน่าสนใจ?",[126,7300,7301,7302,4778],{},"จุดขายหลักของเจ้า Nanobot คือความ ",[390,7303,7304],{},"\"Ultra-lightweight\"",[707,7306,7307,7317,7327],{},[710,7308,7309,7312,7313,7316],{},[390,7310,7311],{},"Codebase เล็กมาก:"," Core logic ทั้งหมดเขียนด้วย Python แค่ประมาณ ",[390,7314,7315],{},"4,000 บรรทัด"," เท่านั้น (เคลมว่าเล็กกว่าคู่แข่ง 99%) ซึ่งเหมาะมากสำหรับคนที่อยากแกะโค้ดมาศึกษา หรือเอาไปโมต่อเอง",[710,7318,7319,7322,7323,7326],{},[390,7320,7321],{},"Local First:"," สาย Self-host หรือคนใช้ Mac M1\u002FM2 น่าจะชอบ เพราะมันรองรับ ",[390,7324,7325],{},"Ollama"," ในตัว ไม่ต้องต่อ API นอกเสมอไป รัน Model ในเครื่องได้เลยฟรีๆ",[710,7328,7329,7332],{},[390,7330,7331],{},"Extensible:"," โครงสร้างมันออกแบบมาให้เราเขียน Skill เพิ่มง่ายมาก อยากให้มันทำอะไรเฉพาะทางก็แค่เขียน Python Function แปะเข้าไป",[139,7334,7336],{"id":7335},"ลองเล่นแล้วเป็นไง","ลองเล่นแล้วเป็นไง?",[126,7338,7339,7340,400,7343,7346],{},"ความรู้สึกแรกคือ \"คลีน\" ครับ ติดตั้งผ่าน ",[171,7341,7342],{},"pip",[171,7344,7345],{},"uv"," แป๊บเดียวเสร็จ สั่งงานผ่าน CLI ได้เลย หรือจะเชื่อมกับ Chat App อย่าง Telegram\u002FDiscord ก็ได้",[126,7348,7349],{},"Use case ที่น่าเอาไปทำต่อ:",[812,7351,7352,7358,7364],{},[710,7353,7354,7357],{},[390,7355,7356],{},"Personal Assistant:"," ให้ช่วยสรุปข่าว หรือแจ้งเตือนสิ่งที่ต้องทำ",[710,7359,7360,7363],{},[390,7361,7362],{},"Coding Buddy:"," ให้ช่วยเจน Code เล็กๆ น้อยๆ หรือ Refactor code",[710,7365,7366,7369],{},[390,7367,7368],{},"Monitor Task:"," สั่งให้เฝ้ากราฟหุ้น\u002FCrypto แล้วแจ้งเตือนเมื่อถึงราคาที่ตั้งไว้",[139,7371,1370],{"id":1370},[126,7373,7374],{},"ใครกำลังมองหา AI Agent Framework ที่ เบา และ คุมได้ 100% แนะนำให้ลอง clone มาเล่นดูครับ ถือว่าเป็นจุดเริ่มต้นที่ดีสำหรับคนที่อยากเข้าใจการทำงานของ Agentic Workflow แบบไม่ต้องปวดหัวกับ Library ที่ซับซ้อนเกินไป",[126,7376,7377,7101,7380],{},[390,7378,7379],{},"Repo:",[292,7381,7292],{"href":7292,"rel":7382},[296],{"title":169,"searchDepth":236,"depth":236,"links":7384},[7385,7386,7387],{"id":7297,"depth":236,"text":7298},{"id":7335,"depth":236,"text":7336},{"id":1370,"depth":236,"text":1370},"รีวิว Nanobot AI Agent ที่เคลมว่าเล็กพริกขี้หนู เขียนด้วย Python เพียวๆ ปรับแต่งง่าย",{},"Review HKUDS Nanobot",[939],{"title":7282,"description":7388},{"loc":95,"lastmod":89},"blogs\u002F2026-02-08-nanobot-ai-agent",[944],"mWvs6aVmRLJjC5q6_VIpwq_uRPv_19vzIig-ouFxQR8",{"id":7398,"title":7399,"body":7400,"date":98,"description":7444,"draft":932,"extension":933,"meta":7445,"navigation":935,"next":936,"ogTitle":7446,"path":97,"pin":932,"prev":936,"recommends":936,"seo":7447,"sitemap":7448,"stem":7449,"tags":7450,"updated":7175,"__hash__":7451},"content\u002Fblogs\u002F2026-02-12-glm-5.md","GLM-5 เปิดตัวแล้ว: สรุปสั้น ๆ สำหรับงาน Coding และ AI Agent",{"type":123,"value":7401,"toc":7440},[7402,7405,7409,7427,7430,7433],[126,7403,7404],{},"Z.ai เปิดตัว GLM-5 ต่อจาก GLM-4.7 รอบนี้ผู้พัฒนาเน้นงานเขียนโค้ด การให้เหตุผล และงาน AI agent ที่ต้องทำหลายขั้นตอน",[139,7406,7408],{"id":7407},"ไฮไลท์ของ-glm-5","ไฮไลท์ของ GLM-5",[707,7410,7411,7416,7422],{},[710,7412,7413,7415],{},[390,7414,7137],{}," Z.ai รายงานว่า GLM-5 ทำคะแนนดีกว่า GLM-4.7 ในการทดสอบหลายรายการ โดยเฉพาะงานที่ต้องวางแผนและใช้เครื่องมือ",[710,7417,7418,7421],{},[390,7419,7420],{},"Coding และ Tool Use:"," รุ่นนี้เน้นการทำงานกับ codebase และการเรียกใช้เครื่องมือ ซึ่งน่าสนใจสำหรับคนที่ใช้ AI agent ช่วยพัฒนาโปรเจกต์",[710,7423,7424,7426],{},[390,7425,7143],{}," ผู้พัฒนาระบุว่าโมเดลรองรับงานที่ต้องอ่านบริบทยาว เช่น โค้ดหลายไฟล์ในโปรเจกต์เดียว",[139,7428,7429],{"id":7429},"ความเห็นส่วนตัว",[126,7431,7432],{},"ผมติดตามโมเดลของ Z.ai มาสักพักแล้ว GLM-5 เป็นอีกตัวที่อยากลองกับงาน Coding และ Agent โดยเฉพาะงานที่ต้องให้โมเดลอ่านโค้ดหลายไฟล์ก่อนลงมือแก้",[126,7434,7435],{},[292,7436,7439],{"href":7437,"rel":7438},"https:\u002F\u002Fz.ai\u002Fblog\u002Fglm-5",[296],"รายละเอียดจาก Z.ai",{"title":169,"searchDepth":236,"depth":236,"links":7441},[7442,7443],{"id":7407,"depth":236,"text":7408},{"id":7429,"depth":236,"text":7429},"สรุปจุดที่น่าสนใจของ GLM-5 สำหรับงาน Coding และ AI Agent",{},"GLM-5 Review",{"title":7399,"description":7444},{"loc":97,"lastmod":98},"blogs\u002F2026-02-12-glm-5",[944],"XBADlM6Jw2MsBX5SOsBPxrmxLQiq2xYyuZ17PfUM_LM",{"id":7453,"title":7454,"body":7455,"date":104,"description":9226,"draft":932,"extension":933,"meta":9227,"navigation":935,"next":936,"ogTitle":9228,"path":106,"pin":932,"prev":936,"recommends":9229,"seo":9231,"sitemap":9232,"stem":9235,"tags":9236,"updated":936,"__hash__":9237},"content\u002Fblogs\u002F2026-08-03-grafana-alloy-loki.md","ลองใช้ Grafana Alloy เก็บ log เข้า Loki",{"type":123,"value":7456,"toc":9213},[7457,7459,7466,7473,7476,7490,7494,7497,7500,7503,7521,7527,7529,7532,7594,7597,7612,7623,7626,7659,7663,7669,7776,7798,7801,7841,7844,7861,7864,7949,7960,7964,7970,7975,7987,7991,7994,8098,8101,8104,8118,8193,8212,8215,8257,8260,8484,8490,8543,8549,8552,8558,8561,8611,8617,8621,8628,8659,8666,8741,8747,8750,8774,8778,8785,8884,8887,9096,9108,9111,9114,9117,9157,9159,9162,9165,9171,9173,9210],[139,7458,3208],{"id":3207},[126,7460,7461,7462,7465],{},"สวัสดีครับ พอดีที่บ้านผมมี container รันอยู่หลายตัว แล้วเวลาจะดู log ทีก็ต้อง ",[171,7463,7464],{},"docker logs"," ไล่ทีละตัว ซึ่งพอมันเยอะขึ้นเรื่อย ๆ ก็เริ่มไม่ไหวแล้วครับ เลยคิดว่าถึงเวลารวม log ไว้ที่เดียวสักที",[126,7467,7468,7469,7472],{},"ตัวที่คนใช้กันมานานคือ Promtail แต่พอไปเปิดเอกสารดูก็เจอบรรทัดนี้ครับ \"Promtail is end of life (EOL) as of March 2, 2026\" คือหมดอายุไปตั้งแต่ต้นปีแล้ว ไม่มี update ไม่มี security fix อีกต่อไป (Grafana Agent ก็หมดอายุไปก่อนหน้านั้นตั้งแต่ 1 พฤศจิกายน 2025 เหมือนกัน) ตัวที่ Grafana ให้ย้ายไปคือ ",[390,7470,7471],{},"Alloy"," ผมเลยข้ามไปลองตัวนี้เลยดีกว่า",[126,7474,7475],{},"บทความนี้ผมรันจริงทั้งหมดบนเครื่องตัวเองด้วย docker นะครับ output ที่แปะไว้ก๊อปมาจาก terminal ตรง ๆ ไม่ได้พิมพ์ขึ้นมาเอง เวอร์ชันที่ใช้คือ Alloy v1.18.0 กับ Loki 3.7.4",[126,7477,7478,7479,7482,7483,400,7486,7489],{},"ของที่ต้องมีก่อนคือ docker กับ ",[171,7480,7481],{},"jq"," (เอาไว้อ่าน JSON ที่ Loki ตอบกลับมา ถ้ายังไม่มีก็ ",[171,7484,7485],{},"brew install jq",[171,7487,7488],{},"apt install jq",") แล้วก็ต้องมี port 3100 กับ 12345 ว่างอยู่ด้วย",[139,7491,7493],{"id":7492},"alloy-คืออะไร","Alloy คืออะไร",[126,7495,7496],{},"Alloy คือ distribution ของ OpenTelemetry Collector ที่ Grafana ทำขึ้นมาเองครับ (OpenTelemetry Collector คือตัวกลางมาตรฐานที่คอยรับข้อมูลพวก log, metrics, traces จากที่นึงแล้วส่งต่อไปอีกที่นึง) เอาไว้เก็บ log, metrics, traces แล้วก็ profiles ส่งไปยังปลายทางที่เราต้องการ พูดง่าย ๆ คือของเดิมที่เคยแยกเป็น Promtail (log) กับ Prometheus agent (metrics) ตอนนี้รวมมาอยู่ในตัวเดียวแล้ว",[126,7498,7499],{},"ที่ผมชอบคือมันเขียน config เป็นก้อน ๆ เรียกว่า component แล้วเอา output ของก้อนนึงต่อเข้า input ของอีกก้อนได้เลย ไม่ได้เขียนเป็น YAML ก้อนใหญ่ ๆ ที่ต้องมานั่งไล่ว่า key ไหนอยู่ใต้ key ไหน เดี๋ยวจะได้เห็นกันครับ",[126,7501,7502],{},"เช็คเวอร์ชันได้แบบนี้",[164,7504,7506],{"className":3233,"code":7505,"language":2675,"meta":169,"style":169},"docker run --rm grafana\u002Falloy:latest --version\n",[171,7507,7508],{"__ignoreMap":169},[174,7509,7510,7512,7514,7516,7519],{"class":176,"line":177},[174,7511,2226],{"class":180},[174,7513,2215],{"class":188},[174,7515,2218],{"class":184},[174,7517,7518],{"class":188}," grafana\u002Falloy:latest",[174,7520,2442],{"class":184},[164,7522,7525],{"className":7523,"code":7524,"language":529},[527],"alloy, version v1.18.0 (branch: HEAD, revision: a435563)\n  build user:       root@buildkitsandbox\n  build date:       2026-07-20T09:02:30Z\n  go version:       go1.26.5\n  platform:         linux\u002Farm64\n  tags:             gore2regex,netgo,embedalloyui,promtail_journal_enabled\n",[171,7526,7524],{"__ignoreMap":169},[139,7528,3882],{"id":3882},[126,7530,7531],{},"ผมยก Loki ขึ้นมาก่อนเพื่อให้มีปลายทางให้ส่ง แล้วค่อยตาม Alloy ทีหลัง สร้าง network ให้สองตัวคุยกันได้ด้วย",[164,7533,7535],{"className":3233,"code":7534,"language":2675,"meta":169,"style":169},"docker network create alloy-net\n\ndocker run -d --name loki-demo \\\n  --network alloy-net \\\n  -p 3100:3100 \\\n  grafana\u002Floki:latest\n",[171,7536,7537,7550,7554,7569,7579,7589],{"__ignoreMap":169},[174,7538,7539,7541,7544,7547],{"class":176,"line":177},[174,7540,2226],{"class":180},[174,7542,7543],{"class":188}," network",[174,7545,7546],{"class":188}," create",[174,7548,7549],{"class":188}," alloy-net\n",[174,7551,7552],{"class":176,"line":236},[174,7553,2759],{"emptyLinePlaceholder":935},[174,7555,7556,7558,7560,7562,7564,7567],{"class":176,"line":242},[174,7557,2226],{"class":180},[174,7559,2215],{"class":188},[174,7561,1986],{"class":184},[174,7563,3478],{"class":184},[174,7565,7566],{"class":188}," loki-demo",[174,7568,2005],{"class":2004},[174,7570,7571,7574,7577],{"class":176,"line":248},[174,7572,7573],{"class":184},"  --network",[174,7575,7576],{"class":188}," alloy-net",[174,7578,2005],{"class":2004},[174,7580,7581,7584,7587],{"class":176,"line":254},[174,7582,7583],{"class":184},"  -p",[174,7585,7586],{"class":188}," 3100:3100",[174,7588,2005],{"class":2004},[174,7590,7591],{"class":176,"line":2112},[174,7592,7593],{"class":188},"  grafana\u002Floki:latest\n",[126,7595,7596],{},"Loki ใช้เวลาบูตพอสมควรครับ ของผมรอไป 17 วินาทีกว่าจะพร้อมรับ query เช็คได้แบบนี้",[164,7598,7600],{"className":3233,"code":7599,"language":2675,"meta":169,"style":169},"curl -s http:\u002F\u002Flocalhost:3100\u002Fready\n",[171,7601,7602],{"__ignoreMap":169},[174,7603,7604,7606,7609],{"class":176,"line":177},[174,7605,2380],{"class":180},[174,7607,7608],{"class":184}," -s",[174,7610,7611],{"class":188}," http:\u002F\u002Flocalhost:3100\u002Fready\n",[126,7613,7614,7615,7618,7619,7622],{},"ถ้ายังไม่พร้อมจะได้ ",[171,7616,7617],{},"Ingester not ready: waiting for 15s after being ready"," กลับมา รอจนกว่าจะขึ้นคำว่า ",[171,7620,7621],{},"ready"," แล้วค่อยไปต่อ",[126,7624,7625],{},"จากนั้นเตรียมโฟลเดอร์กับไฟล์ log ตัวอย่างที่จะให้ Alloy อ่าน",[164,7627,7629],{"className":3233,"code":7628,"language":2675,"meta":169,"style":169},"mkdir -p ~\u002Falloy\u002Flogs\necho '{\"level\":\"info\",\"msg\":\"service started\"}' > ~\u002Falloy\u002Flogs\u002Fapp.log\n",[171,7630,7631,7641],{"__ignoreMap":169},[174,7632,7633,7635,7638],{"class":176,"line":177},[174,7634,3896],{"class":180},[174,7636,7637],{"class":184}," -p",[174,7639,7640],{"class":188}," ~\u002Falloy\u002Flogs\n",[174,7642,7643,7646,7648,7651,7654,7656],{"class":176,"line":236},[174,7644,7645],{"class":2078},"echo",[174,7647,373],{"class":372},[174,7649,7650],{"class":188},"{\"level\":\"info\",\"msg\":\"service started\"}",[174,7652,7653],{"class":372},"'",[174,7655,2047],{"class":2046},[174,7657,7658],{"class":188}," ~\u002Falloy\u002Flogs\u002Fapp.log\n",[139,7660,7662],{"id":7661},"เขียน-config","เขียน config",[126,7664,4304,7665,7668],{},[171,7666,7667],{},"~\u002Falloy\u002Fconfig.alloy"," ขึ้นมาครับ จะใช้ editor เปิดเขียนเองก็ได้ หรือก๊อปทั้งก้อนนี้ไปวางใน terminal เลยก็ได้",[164,7670,7672],{"className":3233,"code":7671,"language":2675,"meta":169,"style":169},"cat > ~\u002Falloy\u002Fconfig.alloy \u003C\u003C'EOF'\nlocal.file_match \"applog\" {\n  path_targets = [{\n    __path__ = \"\u002Fvar\u002Flog\u002Fdemo\u002F*.log\",\n    job      = \"demo-app\",\n    host     = \"homelab\",\n  }]\n}\n\nloki.source.file \"applog\" {\n  targets    = local.file_match.applog.targets\n  forward_to = [loki.write.default.receiver]\n}\n\nloki.write \"default\" {\n  endpoint {\n    url = \"http:\u002F\u002Floki-demo:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\"\n  }\n}\nEOF\n",[171,7673,7674,7688,7693,7698,7703,7708,7713,7718,7722,7726,7731,7736,7741,7745,7749,7754,7759,7764,7768,7772],{"__ignoreMap":169},[174,7675,7676,7678,7680,7683,7685],{"class":176,"line":177},[174,7677,1446],{"class":180},[174,7679,2047],{"class":2046},[174,7681,7682],{"class":188}," ~\u002Falloy\u002Fconfig.alloy",[174,7684,2053],{"class":2046},[174,7686,7687],{"class":2056},"'EOF'\n",[174,7689,7690],{"class":176,"line":236},[174,7691,7692],{"class":188},"local.file_match \"applog\" {\n",[174,7694,7695],{"class":176,"line":242},[174,7696,7697],{"class":188},"  path_targets = [{\n",[174,7699,7700],{"class":176,"line":248},[174,7701,7702],{"class":188},"    __path__ = \"\u002Fvar\u002Flog\u002Fdemo\u002F*.log\",\n",[174,7704,7705],{"class":176,"line":254},[174,7706,7707],{"class":188},"    job      = \"demo-app\",\n",[174,7709,7710],{"class":176,"line":2112},[174,7711,7712],{"class":188},"    host     = \"homelab\",\n",[174,7714,7715],{"class":176,"line":2129},[174,7716,7717],{"class":188},"  }]\n",[174,7719,7720],{"class":176,"line":2135},[174,7721,480],{"class":188},[174,7723,7724],{"class":176,"line":3364},[174,7725,2759],{"emptyLinePlaceholder":935},[174,7727,7728],{"class":176,"line":3369},[174,7729,7730],{"class":188},"loki.source.file \"applog\" {\n",[174,7732,7733],{"class":176,"line":3375},[174,7734,7735],{"class":188},"  targets    = local.file_match.applog.targets\n",[174,7737,7738],{"class":176,"line":3390},[174,7739,7740],{"class":188},"  forward_to = [loki.write.default.receiver]\n",[174,7742,7743],{"class":176,"line":3395},[174,7744,480],{"class":188},[174,7746,7747],{"class":176,"line":3400},[174,7748,2759],{"emptyLinePlaceholder":935},[174,7750,7751],{"class":176,"line":4044},[174,7752,7753],{"class":188},"loki.write \"default\" {\n",[174,7755,7756],{"class":176,"line":4052},[174,7757,7758],{"class":188},"  endpoint {\n",[174,7760,7761],{"class":176,"line":4060},[174,7762,7763],{"class":188},"    url = \"http:\u002F\u002Floki-demo:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\"\n",[174,7765,7766],{"class":176,"line":4068},[174,7767,5284],{"class":188},[174,7769,7770],{"class":176,"line":4073},[174,7771,480],{"class":188},[174,7773,7774],{"class":176,"line":4081},[174,7775,2057],{"class":2056},[126,7777,7778,7779,7782,7783,7786,7787,7790,7791,7794,7795,7797],{},"ขั้นตอนนี้ห้ามข้ามนะครับ ถ้ายังไม่มีไฟล์นี้แล้วไปสั่ง ",[171,7780,7781],{},"docker run"," เลย docker จะสร้าง",[390,7784,7785],{},"โฟลเดอร์","ชื่อ ",[171,7788,7789],{},"config.alloy"," ให้แทน แล้ว container จะพังตั้งแต่ยังไม่ทันขึ้น พร้อม error ที่งงมากว่า ",[171,7792,7793],{},"not a directory"," แถม ",[171,7796,7464],{}," ก็ว่างเปล่าไม่มีอะไรให้ดูด้วย",[126,7799,7800],{},"อ่าน config จากบนลงล่างได้เลยครับ",[707,7802,7803,7817,7835],{},[710,7804,7805,7808,7809,7812,7813,7816],{},[171,7806,7807],{},"local.file_match"," คือตัวบอกว่าจะอ่านไฟล์ไหนบ้าง ตรง ",[171,7810,7811],{},"job"," กับ ",[171,7814,7815],{},"host"," คือ label ที่จะติดไปกับ log ทุกบรรทัด เอาไว้ค้นทีหลัง",[710,7818,7819,7822,7823,7826,7827,7830,7831,7834],{},[171,7820,7821],{},"loki.source.file"," คือตัวอ่านไฟล์ สังเกตว่า ",[171,7824,7825],{},"targets"," ชี้ไปที่ผลลัพธ์ของบล็อกแรกตรง ๆ (",[171,7828,7829],{},"local.file_match.applog.targets",") แล้ว ",[171,7832,7833],{},"forward_to"," ก็ชี้ต่อไปยังบล็อกที่สาม",[710,7836,7837,7840],{},[171,7838,7839],{},"loki.write"," คือตัวส่งออก",[126,7842,7843],{},"การต่อกันแบบนี้แหละครับที่เป็นจุดขายของ Alloy คือ output ของ component นึงเสียบเข้า input ของอีกตัวได้เลย",[126,7845,7846,7847,7849,7850,7853,7854,7857,7858,7860],{},"อีกเรื่องที่ควรรู้ไว้คือ ",[171,7848,7821],{}," มีบล็อก ",[171,7851,7852],{},"file_match"," ในตัวอยู่แล้ว ใส่ glob ลงไปใน ",[171,7855,7856],{},"__path__"," ตรง ๆ ได้โดยไม่ต้องมี ",[171,7859,7807],{}," แยกออกมา แต่ผมเลือกเขียนแยกเพราะอยากให้เห็นภาพว่า component ต่อกันยังไง แล้วถ้าวันหลังมี component อื่นอยากใช้ targets ชุดเดียวกันก็ดึงไปใช้ต่อได้",[126,7862,7863],{},"ทีนี้รันได้แล้ว",[164,7865,7867],{"className":3233,"code":7866,"language":2675,"meta":169,"style":169},"docker run -d --name alloy-demo \\\n  --network alloy-net \\\n  -p 12345:12345 \\\n  -v ~\u002Falloy\u002Fconfig.alloy:\u002Fetc\u002Falloy\u002Fconfig.alloy \\\n  -v ~\u002Falloy\u002Flogs:\u002Fvar\u002Flog\u002Fdemo \\\n  grafana\u002Falloy:latest \\\n    run --server.http.listen-addr=0.0.0.0:12345 \\\n    --storage.path=\u002Fvar\u002Flib\u002Falloy\u002Fdata \\\n    \u002Fetc\u002Falloy\u002Fconfig.alloy\n",[171,7868,7869,7884,7892,7901,7911,7920,7927,7937,7944],{"__ignoreMap":169},[174,7870,7871,7873,7875,7877,7879,7882],{"class":176,"line":177},[174,7872,2226],{"class":180},[174,7874,2215],{"class":188},[174,7876,1986],{"class":184},[174,7878,3478],{"class":184},[174,7880,7881],{"class":188}," alloy-demo",[174,7883,2005],{"class":2004},[174,7885,7886,7888,7890],{"class":176,"line":236},[174,7887,7573],{"class":184},[174,7889,7576],{"class":188},[174,7891,2005],{"class":2004},[174,7893,7894,7896,7899],{"class":176,"line":242},[174,7895,7583],{"class":184},[174,7897,7898],{"class":188}," 12345:12345",[174,7900,2005],{"class":2004},[174,7902,7903,7906,7909],{"class":176,"line":248},[174,7904,7905],{"class":184},"  -v",[174,7907,7908],{"class":188}," ~\u002Falloy\u002Fconfig.alloy:\u002Fetc\u002Falloy\u002Fconfig.alloy",[174,7910,2005],{"class":2004},[174,7912,7913,7915,7918],{"class":176,"line":254},[174,7914,7905],{"class":184},[174,7916,7917],{"class":188}," ~\u002Falloy\u002Flogs:\u002Fvar\u002Flog\u002Fdemo",[174,7919,2005],{"class":2004},[174,7921,7922,7925],{"class":176,"line":2112},[174,7923,7924],{"class":188},"  grafana\u002Falloy:latest",[174,7926,2005],{"class":2004},[174,7928,7929,7932,7935],{"class":176,"line":2129},[174,7930,7931],{"class":188},"    run",[174,7933,7934],{"class":184}," --server.http.listen-addr=0.0.0.0:12345",[174,7936,2005],{"class":2004},[174,7938,7939,7942],{"class":176,"line":2135},[174,7940,7941],{"class":184},"    --storage.path=\u002Fvar\u002Flib\u002Falloy\u002Fdata",[174,7943,2005],{"class":2004},[174,7945,7946],{"class":176,"line":3364},[174,7947,7948],{"class":188},"    \u002Fetc\u002Falloy\u002Fconfig.alloy\n",[126,7950,7951,7952,7955,7956,7959],{},"ตรง ",[171,7953,7954],{},"--server.http.listen-addr=0.0.0.0:12345"," อย่าลืมใส่นะครับ ถ้าไม่ใส่มันจะไป bind ที่ ",[171,7957,7958],{},"127.0.0.1"," ข้างใน container แล้วเราจะเข้าหน้า UI จากข้างนอกไม่ได้เลย",[139,7961,7963],{"id":7962},"หน้า-ui-ของ-alloy","หน้า UI ของ Alloy",[126,7965,2936,7966,7969],{},[171,7967,7968],{},"http:\u002F\u002Flocalhost:12345"," แล้วไปที่เมนู Graph ได้เลยครับ (หน้าแรกที่เด้งขึ้นมาจะเป็น Components) มันจะวาด pipeline ให้ดูว่า component ไหนต่อกับอันไหน",[126,7971,7972],{},[3766,7973],{"alt":169,"src":7974},"\u002Fimages\u002F2026-08-03-grafana-alloy-loki\u002Falloy-ui.png",[126,7976,7977,7978,7980,7981,7983,7984,7986],{},"นี่แหละครับคือสิ่งที่อธิบายไปเมื่อกี้ ",[171,7979,7807],{}," ยิงไปหา ",[171,7982,7821],{}," แล้วต่อไป ",[171,7985,7839],{}," ตรงตาม config ที่เขียนไว้เป๊ะ ๆ เส้นสีเขียวคือ log ถ้ามี metrics หรือ traces ด้วยก็จะเป็นคนละสี อันนี้มีประโยชน์มากตอน config เริ่มใหญ่ เพราะดูรูปทีเดียวรู้เลยว่าอะไรต่อกับอะไร",[139,7988,7990],{"id":7989},"เช็คว่า-log-เข้าจริง","เช็คว่า log เข้าจริง",[126,7992,7993],{},"ลองเขียน log เพิ่มเข้าไปในไฟล์",[164,7995,7997],{"className":3233,"code":7996,"language":2675,"meta":169,"style":169},"for i in 1 2 3; do\n  echo \"{\\\"level\\\":\\\"info\\\",\\\"msg\\\":\\\"handled request $i\\\"}\" >> ~\u002Falloy\u002Flogs\u002Fapp.log\ndone\necho '{\"level\":\"error\",\"msg\":\"database connection refused\"}' >> ~\u002Falloy\u002Flogs\u002Fapp.log\n",[171,7998,7999,8021,8078,8083],{"__ignoreMap":169},[174,8000,8001,8003,8005,8008,8010,8013,8016,8018],{"class":176,"line":177},[174,8002,4942],{"class":1532},[174,8004,5128],{"class":2094},[174,8006,8007],{"class":1532}," in",[174,8009,5133],{"class":188},[174,8011,8012],{"class":188}," 2",[174,8014,8015],{"class":188}," 3",[174,8017,5136],{"class":455},[174,8019,8020],{"class":1532}," do\n",[174,8022,8023,8026,8028,8031,8034,8037,8039,8041,8043,8046,8048,8050,8052,8055,8057,8059,8061,8064,8067,8069,8071,8073,8076],{"class":176,"line":236},[174,8024,8025],{"class":2078},"  echo",[174,8027,2272],{"class":372},[174,8029,8030],{"class":188},"{",[174,8032,8033],{"class":2004},"\\\"",[174,8035,8036],{"class":188},"level",[174,8038,8033],{"class":2004},[174,8040,471],{"class":188},[174,8042,8033],{"class":2004},[174,8044,8045],{"class":188},"info",[174,8047,8033],{"class":2004},[174,8049,4889],{"class":188},[174,8051,8033],{"class":2004},[174,8053,8054],{"class":188},"msg",[174,8056,8033],{"class":2004},[174,8058,471],{"class":188},[174,8060,8033],{"class":2004},[174,8062,8063],{"class":188},"handled request ",[174,8065,8066],{"class":2094},"$i",[174,8068,8033],{"class":2004},[174,8070,2749],{"class":188},[174,8072,468],{"class":372},[174,8074,8075],{"class":2046}," >>",[174,8077,7658],{"class":188},[174,8079,8080],{"class":176,"line":242},[174,8081,8082],{"class":1532},"done\n",[174,8084,8085,8087,8089,8092,8094,8096],{"class":176,"line":248},[174,8086,7645],{"class":2078},[174,8088,373],{"class":372},[174,8090,8091],{"class":188},"{\"level\":\"error\",\"msg\":\"database connection refused\"}",[174,8093,7653],{"class":372},[174,8095,8075],{"class":2046},[174,8097,7658],{"class":188},[126,8099,8100],{},"รอสัก 2-3 วินาทีให้ Alloy อ่านไฟล์แล้วส่งเข้า Loki ก่อนนะครับ ถ้ายิง query ทันทีจะเห็นแค่บรรทัดแรกบรรทัดเดียวแล้วนึกว่าพัง",[126,8102,8103],{},"ถามก่อนว่า Loki รู้จัก label อะไรบ้าง",[164,8105,8107],{"className":3233,"code":8106,"language":2675,"meta":169,"style":169},"curl -s http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Flabels\n",[171,8108,8109],{"__ignoreMap":169},[174,8110,8111,8113,8115],{"class":176,"line":177},[174,8112,2380],{"class":180},[174,8114,7608],{"class":184},[174,8116,8117],{"class":188}," http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Flabels\n",[164,8119,8121],{"className":446,"code":8120,"language":448,"meta":169,"style":169},"{ \"status\": \"success\", \"data\": [\"filename\", \"host\", \"job\", \"service_name\"] }\n",[171,8122,8123],{"__ignoreMap":169},[174,8124,8125,8127,8129,8132,8134,8136,8138,8141,8143,8145,8147,8150,8152,8154,8156,8158,8161,8163,8165,8167,8169,8171,8173,8175,8177,8179,8181,8183,8186,8188,8190],{"class":176,"line":177},[174,8126,8030],{"class":455},[174,8128,2272],{"class":461},[174,8130,8131],{"class":465},"status",[174,8133,468],{"class":461},[174,8135,471],{"class":455},[174,8137,2272],{"class":372},[174,8139,8140],{"class":188},"success",[174,8142,468],{"class":372},[174,8144,4889],{"class":455},[174,8146,2272],{"class":461},[174,8148,8149],{"class":465},"data",[174,8151,468],{"class":461},[174,8153,471],{"class":455},[174,8155,1536],{"class":455},[174,8157,468],{"class":372},[174,8159,8160],{"class":188},"filename",[174,8162,468],{"class":372},[174,8164,4889],{"class":455},[174,8166,2272],{"class":372},[174,8168,7815],{"class":188},[174,8170,468],{"class":372},[174,8172,4889],{"class":455},[174,8174,2272],{"class":372},[174,8176,7811],{"class":188},[174,8178,468],{"class":372},[174,8180,4889],{"class":455},[174,8182,2272],{"class":372},[174,8184,8185],{"class":188},"service_name",[174,8187,468],{"class":372},[174,8189,5077],{"class":455},[174,8191,8192],{"class":455}," }\n",[126,8194,8195,7812,8197,8199,8200,8202,8203,8205,8206,8208,8209,8211],{},[171,8196,7811],{},[171,8198,7815],{}," คือที่เราใส่ไว้ใน config เอง ส่วนอีกสองตัวมาคนละที่กันครับ ",[171,8201,8160],{}," เป็นของ Alloy ที่เอา ",[171,8204,7856],{}," มาแปะให้ทุกบรรทัด ส่วน ",[171,8207,8185],{}," เป็นของ Loki ที่ map มาจาก label ",[171,8210,7811],{}," ให้อัตโนมัติตอน ingest",[126,8213,8214],{},"ทีนี้ลองดึง log ออกมาดูจริง ๆ",[164,8216,8218],{"className":3233,"code":8217,"language":2675,"meta":169,"style":169},"curl -sG http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fquery_range \\\n  --data-urlencode 'query={job=\"demo-app\"}' \\\n  --data-urlencode 'limit=10'\n",[171,8219,8220,8232,8246],{"__ignoreMap":169},[174,8221,8222,8224,8227,8230],{"class":176,"line":177},[174,8223,2380],{"class":180},[174,8225,8226],{"class":184}," -sG",[174,8228,8229],{"class":188}," http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fquery_range",[174,8231,2005],{"class":2004},[174,8233,8234,8237,8239,8242,8244],{"class":176,"line":236},[174,8235,8236],{"class":184},"  --data-urlencode",[174,8238,373],{"class":372},[174,8240,8241],{"class":188},"query={job=\"demo-app\"}",[174,8243,7653],{"class":372},[174,8245,2005],{"class":2004},[174,8247,8248,8250,8252,8255],{"class":176,"line":242},[174,8249,8236],{"class":184},[174,8251,373],{"class":372},[174,8253,8254],{"class":188},"limit=10",[174,8256,379],{"class":372},[126,8258,8259],{},"ที่ได้กลับมาคือ JSON ก้อนเดียวยาว ๆ หน้าตาประมาณนี้",[164,8261,8263],{"className":446,"code":8262,"language":448,"meta":169,"style":169},"{\"status\":\"success\",\"data\":{\"resultType\":\"streams\",\"result\":[{\"stream\":{\"detected_level\":\"error\",\"filename\":\"\u002Fvar\u002Flog\u002Fdemo\u002Fapp.log\",\"host\":\"homelab\",\"job\":\"demo-app\",\"service_name\":\"demo-app\"},\"values\":[[\"1785760821561036812\",\"{\\\"level\\\":\\\"error\\\",\\\"msg\\\":\\\"database connection refused\\\"}\"]]},...\n",[171,8264,8265],{"__ignoreMap":169},[174,8266,8267,8269,8271,8273,8275,8277,8279,8281,8283,8285,8287,8289,8291,8294,8296,8300,8302,8304,8306,8309,8311,8313,8315,8318,8320,8323,8325,8329,8331,8333,8335,8339,8341,8343,8345,8348,8350,8352,8354,8356,8358,8360,8362,8365,8367,8369,8371,8373,8375,8377,8379,8382,8384,8386,8388,8390,8392,8394,8396,8399,8401,8403,8405,8407,8409,8411,8413,8415,8417,8420,8422,8425,8427,8430,8432,8435,8437,8439,8441,8443,8445,8447,8449,8451,8453,8455,8457,8459,8461,8463,8465,8467,8469,8472,8474,8476,8478,8481],{"class":176,"line":177},[174,8268,8030],{"class":455},[174,8270,468],{"class":461},[174,8272,8131],{"class":465},[174,8274,468],{"class":461},[174,8276,471],{"class":455},[174,8278,468],{"class":372},[174,8280,8140],{"class":188},[174,8282,468],{"class":372},[174,8284,4889],{"class":455},[174,8286,468],{"class":461},[174,8288,8149],{"class":465},[174,8290,468],{"class":461},[174,8292,8293],{"class":455},":{",[174,8295,468],{"class":461},[174,8297,8299],{"class":8298},"sLise","resultType",[174,8301,468],{"class":461},[174,8303,471],{"class":455},[174,8305,468],{"class":372},[174,8307,8308],{"class":188},"streams",[174,8310,468],{"class":372},[174,8312,4889],{"class":455},[174,8314,468],{"class":461},[174,8316,8317],{"class":8298},"result",[174,8319,468],{"class":461},[174,8321,8322],{"class":455},":[{",[174,8324,468],{"class":461},[174,8326,8328],{"class":8327},"sxkdo","stream",[174,8330,468],{"class":461},[174,8332,8293],{"class":455},[174,8334,468],{"class":461},[174,8336,8338],{"class":8337},"s9IQt","detected_level",[174,8340,468],{"class":461},[174,8342,471],{"class":455},[174,8344,468],{"class":372},[174,8346,8347],{"class":188},"error",[174,8349,468],{"class":372},[174,8351,4889],{"class":455},[174,8353,468],{"class":461},[174,8355,8160],{"class":8337},[174,8357,468],{"class":461},[174,8359,471],{"class":455},[174,8361,468],{"class":372},[174,8363,8364],{"class":188},"\u002Fvar\u002Flog\u002Fdemo\u002Fapp.log",[174,8366,468],{"class":372},[174,8368,4889],{"class":455},[174,8370,468],{"class":461},[174,8372,7815],{"class":8337},[174,8374,468],{"class":461},[174,8376,471],{"class":455},[174,8378,468],{"class":372},[174,8380,8381],{"class":188},"homelab",[174,8383,468],{"class":372},[174,8385,4889],{"class":455},[174,8387,468],{"class":461},[174,8389,7811],{"class":8337},[174,8391,468],{"class":461},[174,8393,471],{"class":455},[174,8395,468],{"class":372},[174,8397,8398],{"class":188},"demo-app",[174,8400,468],{"class":372},[174,8402,4889],{"class":455},[174,8404,468],{"class":461},[174,8406,8185],{"class":8337},[174,8408,468],{"class":461},[174,8410,471],{"class":455},[174,8412,468],{"class":372},[174,8414,8398],{"class":188},[174,8416,468],{"class":372},[174,8418,8419],{"class":455},"},",[174,8421,468],{"class":461},[174,8423,8424],{"class":8327},"values",[174,8426,468],{"class":461},[174,8428,8429],{"class":455},":[[",[174,8431,468],{"class":372},[174,8433,8434],{"class":188},"1785760821561036812",[174,8436,468],{"class":372},[174,8438,4889],{"class":455},[174,8440,468],{"class":372},[174,8442,8030],{"class":188},[174,8444,8033],{"class":2004},[174,8446,8036],{"class":188},[174,8448,8033],{"class":2004},[174,8450,471],{"class":188},[174,8452,8033],{"class":2004},[174,8454,8347],{"class":188},[174,8456,8033],{"class":2004},[174,8458,4889],{"class":188},[174,8460,8033],{"class":2004},[174,8462,8054],{"class":188},[174,8464,8033],{"class":2004},[174,8466,471],{"class":188},[174,8468,8033],{"class":2004},[174,8470,8471],{"class":188},"database connection refused",[174,8473,8033],{"class":2004},[174,8475,2749],{"class":188},[174,8477,468],{"class":372},[174,8479,8480],{"class":455},"]]},",[174,8482,8483],{"class":4918},"...\n",[126,8485,8486,8487,8489],{},"อ่านไม่ไหวครับ ต่อ ",[171,8488,7481],{}," เอาเฉพาะบรรทัด log ดีกว่า",[164,8491,8493],{"className":3233,"code":8492,"language":2675,"meta":169,"style":169},"curl -sG http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fquery_range \\\n  --data-urlencode 'query={job=\"demo-app\"}' \\\n  --data-urlencode 'limit=10' | jq -r '.data.result[].values[][1]'\n",[171,8494,8495,8505,8517],{"__ignoreMap":169},[174,8496,8497,8499,8501,8503],{"class":176,"line":177},[174,8498,2380],{"class":180},[174,8500,8226],{"class":184},[174,8502,8229],{"class":188},[174,8504,2005],{"class":2004},[174,8506,8507,8509,8511,8513,8515],{"class":176,"line":236},[174,8508,8236],{"class":184},[174,8510,373],{"class":372},[174,8512,8241],{"class":188},[174,8514,7653],{"class":372},[174,8516,2005],{"class":2004},[174,8518,8519,8521,8523,8525,8527,8530,8533,8536,8538,8541],{"class":176,"line":242},[174,8520,8236],{"class":184},[174,8522,373],{"class":372},[174,8524,8254],{"class":188},[174,8526,7653],{"class":372},[174,8528,8529],{"class":2046}," |",[174,8531,8532],{"class":180}," jq",[174,8534,8535],{"class":184}," -r",[174,8537,373],{"class":372},[174,8539,8540],{"class":188},".data.result[].values[][1]",[174,8542,379],{"class":372},[164,8544,8547],{"className":8545,"code":8546,"language":529},[527],"{\"level\":\"error\",\"msg\":\"database connection refused\"}\n{\"level\":\"info\",\"msg\":\"handled request 3\"}\n{\"level\":\"info\",\"msg\":\"handled request 2\"}\n{\"level\":\"info\",\"msg\":\"handled request 1\"}\n{\"level\":\"info\",\"msg\":\"service started\"}\n",[171,8548,8546],{"__ignoreMap":169},[126,8550,8551],{},"ครบทั้ง 5 บรรทัดที่เขียนลงไฟล์ไป",[126,8553,8554,8555,8557],{},"กลับไปดูใน JSON ก้อนบนอีกทีจะเห็น ",[171,8556,8338],{}," โผล่มาด้วย อันนี้ผมไม่ได้ใส่ไว้ใน config เลยครับ เป็น Loki ที่อ่านเนื้อ log แล้วแยกให้เองว่าบรรทัดไหน error บรรทัดไหน info ทั้งที่ผมไม่ได้เขียน parser อะไรไว้สักตัว",[126,8559,8560],{},"ถ้าอยากกรองเฉพาะ error ก็ใส่ filter ต่อท้าย query ได้",[164,8562,8564],{"className":3233,"code":8563,"language":2675,"meta":169,"style":169},"curl -sG http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fquery_range \\\n  --data-urlencode 'query={job=\"demo-app\"} |= \"error\"' \\\n  --data-urlencode 'limit=10' | jq -r '.data.result[].values[][1]'\n",[171,8565,8566,8576,8589],{"__ignoreMap":169},[174,8567,8568,8570,8572,8574],{"class":176,"line":177},[174,8569,2380],{"class":180},[174,8571,8226],{"class":184},[174,8573,8229],{"class":188},[174,8575,2005],{"class":2004},[174,8577,8578,8580,8582,8585,8587],{"class":176,"line":236},[174,8579,8236],{"class":184},[174,8581,373],{"class":372},[174,8583,8584],{"class":188},"query={job=\"demo-app\"} |= \"error\"",[174,8586,7653],{"class":372},[174,8588,2005],{"class":2004},[174,8590,8591,8593,8595,8597,8599,8601,8603,8605,8607,8609],{"class":176,"line":242},[174,8592,8236],{"class":184},[174,8594,373],{"class":372},[174,8596,8254],{"class":188},[174,8598,7653],{"class":372},[174,8600,8529],{"class":2046},[174,8602,8532],{"class":180},[174,8604,8535],{"class":184},[174,8606,373],{"class":372},[174,8608,8540],{"class":188},[174,8610,379],{"class":372},[164,8612,8615],{"className":8613,"code":8614,"language":529},[527],"{\"level\":\"error\",\"msg\":\"database connection refused\"}\n",[171,8616,8614],{"__ignoreMap":169},[139,8618,8620],{"id":8619},"ตรวจ-config-ก่อนรัน","ตรวจ config ก่อนรัน",[126,8622,8623,8624,8627],{},"Alloy มีคำสั่ง ",[171,8625,8626],{},"validate"," ให้ใช้ครับ ไม่ต้องรันจริงแล้วมานั่งดู log ว่าพังตรงไหน",[164,8629,8631],{"className":3233,"code":8630,"language":2675,"meta":169,"style":169},"docker run --rm -v ~\u002Falloy\u002Fconfig.alloy:\u002Fc.alloy \\\n  grafana\u002Falloy:latest validate \u002Fc.alloy\n",[171,8632,8633,8649],{"__ignoreMap":169},[174,8634,8635,8637,8639,8641,8644,8647],{"class":176,"line":177},[174,8636,2226],{"class":180},[174,8638,2215],{"class":188},[174,8640,2218],{"class":184},[174,8642,8643],{"class":184}," -v",[174,8645,8646],{"class":188}," ~\u002Falloy\u002Fconfig.alloy:\u002Fc.alloy",[174,8648,2005],{"class":2004},[174,8650,8651,8653,8656],{"class":176,"line":236},[174,8652,7924],{"class":188},[174,8654,8655],{"class":188}," validate",[174,8657,8658],{"class":188}," \u002Fc.alloy\n",[126,8660,8661,8662,8665],{},"ถ้าผ่านจะไม่มีอะไรขึ้นมาเลย ทีนี้ลองทำให้มันพังดูบ้าง ผมสร้างไฟล์ ",[171,8663,8664],{},"bad.alloy"," ที่ใส่ attribute มั่ว ๆ เข้าไปหนึ่งตัว",[164,8667,8669],{"className":3233,"code":8668,"language":2675,"meta":169,"style":169},"cat > ~\u002Falloy\u002Fbad.alloy \u003C\u003C'EOF'\nloki.write \"default\" {\n  endpoint {\n    url = \"http:\u002F\u002Floki-demo:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\"\n  }\n  bogus_arg = 1\n}\nEOF\n\ndocker run --rm -v ~\u002Falloy\u002Fbad.alloy:\u002Fbad.alloy \\\n  grafana\u002Falloy:latest validate \u002Fbad.alloy\n",[171,8670,8671,8684,8688,8692,8696,8700,8705,8709,8713,8717,8732],{"__ignoreMap":169},[174,8672,8673,8675,8677,8680,8682],{"class":176,"line":177},[174,8674,1446],{"class":180},[174,8676,2047],{"class":2046},[174,8678,8679],{"class":188}," ~\u002Falloy\u002Fbad.alloy",[174,8681,2053],{"class":2046},[174,8683,7687],{"class":2056},[174,8685,8686],{"class":176,"line":236},[174,8687,7753],{"class":188},[174,8689,8690],{"class":176,"line":242},[174,8691,7758],{"class":188},[174,8693,8694],{"class":176,"line":248},[174,8695,7763],{"class":188},[174,8697,8698],{"class":176,"line":254},[174,8699,5284],{"class":188},[174,8701,8702],{"class":176,"line":2112},[174,8703,8704],{"class":188},"  bogus_arg = 1\n",[174,8706,8707],{"class":176,"line":2129},[174,8708,480],{"class":188},[174,8710,8711],{"class":176,"line":2135},[174,8712,2057],{"class":2056},[174,8714,8715],{"class":176,"line":3364},[174,8716,2759],{"emptyLinePlaceholder":935},[174,8718,8719,8721,8723,8725,8727,8730],{"class":176,"line":3369},[174,8720,2226],{"class":180},[174,8722,2215],{"class":188},[174,8724,2218],{"class":184},[174,8726,8643],{"class":184},[174,8728,8729],{"class":188}," ~\u002Falloy\u002Fbad.alloy:\u002Fbad.alloy",[174,8731,2005],{"class":2004},[174,8733,8734,8736,8738],{"class":176,"line":3375},[174,8735,7924],{"class":188},[174,8737,8655],{"class":188},[174,8739,8740],{"class":188}," \u002Fbad.alloy\n",[164,8742,8745],{"className":8743,"code":8744,"language":529},[527],"Error: \u002Fbad.alloy:5:3: unrecognized attribute name \"bogus_arg\"\n\n4 |   }\n5 |   bogus_arg = 1\n  |   ^^^^^^^^^^^^^\n6 | }\nError: validation failed\n2026\u002F08\u002F03 13:32:02 collector server run finished with error: validation failed\n",[171,8746,8744],{"__ignoreMap":169},[126,8748,8749],{},"ชี้ให้เลยว่าบรรทัด 5 ตัวอักษรที่ 3 พร้อมขีดเส้นใต้ให้ด้วย",[126,8751,8752,8753,8756,8757,8759,8760,8763,8764,8767,8768,8770,8771,8773],{},"ระวังอย่าไปสับสนกับคำสั่ง ",[171,8754,8755],{},"fmt"," นะครับ สองตัวนี้ตรวจคนละชั้นกัน ",[171,8758,8755],{}," ดูแค่ syntax คือวงเล็บปิดครบไหม โครงสร้างถูกไหม (ผมลองเอา config ที่ลืมปิดวงเล็บไปให้ มันฟ้อง ",[171,8761,8762],{},"expected }, got EOF"," แล้ว exit 1) แต่มันไม่เช็คว่าชื่อ attribute หรือ component นั้นมีอยู่จริงหรือเปล่า ตัว ",[171,8765,8766],{},"bogus_arg"," ข้างบนผ่าน ",[171,8769,8755],{}," ฉลุยด้วย exit 0 แถมยังพ่น config ที่จัดหน้าเรียบร้อยแล้วออกมาให้อีก ต้องใช้ ",[171,8772,8626],{}," ถึงจะจับได้",[139,8775,8777],{"id":8776},"ย้ายจาก-promtail","ย้ายจาก Promtail",[126,8779,8780,8781,8784],{},"ใครที่มี config Promtail อยู่แล้วไม่ต้องนั่งแปลมือครับ Alloy มีคำสั่ง ",[171,8782,8783],{},"convert"," ให้ ผมลองเอา config สั้น ๆ แบบนี้ไปแปลงดู",[164,8786,8788],{"className":3233,"code":8787,"language":2675,"meta":169,"style":169},"cat > ~\u002Falloy\u002Fpromtail.yaml \u003C\u003C'EOF'\nclients:\n  - url: http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\nscrape_configs:\n  - job_name: system\n    static_configs:\n      - targets: [localhost]\n        labels:\n          job: varlogs\n          __path__: \u002Fvar\u002Flog\u002F*.log\nEOF\n\ndocker run --rm -v ~\u002Falloy\u002Fpromtail.yaml:\u002Fp.yaml \\\n  grafana\u002Falloy:latest convert --source-format=promtail \u002Fp.yaml\n",[171,8789,8790,8803,8808,8813,8818,8823,8828,8833,8838,8843,8848,8852,8856,8871],{"__ignoreMap":169},[174,8791,8792,8794,8796,8799,8801],{"class":176,"line":177},[174,8793,1446],{"class":180},[174,8795,2047],{"class":2046},[174,8797,8798],{"class":188}," ~\u002Falloy\u002Fpromtail.yaml",[174,8800,2053],{"class":2046},[174,8802,7687],{"class":2056},[174,8804,8805],{"class":176,"line":236},[174,8806,8807],{"class":188},"clients:\n",[174,8809,8810],{"class":176,"line":242},[174,8811,8812],{"class":188},"  - url: http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\n",[174,8814,8815],{"class":176,"line":248},[174,8816,8817],{"class":188},"scrape_configs:\n",[174,8819,8820],{"class":176,"line":254},[174,8821,8822],{"class":188},"  - job_name: system\n",[174,8824,8825],{"class":176,"line":2112},[174,8826,8827],{"class":188},"    static_configs:\n",[174,8829,8830],{"class":176,"line":2129},[174,8831,8832],{"class":188},"      - targets: [localhost]\n",[174,8834,8835],{"class":176,"line":2135},[174,8836,8837],{"class":188},"        labels:\n",[174,8839,8840],{"class":176,"line":3364},[174,8841,8842],{"class":188},"          job: varlogs\n",[174,8844,8845],{"class":176,"line":3369},[174,8846,8847],{"class":188},"          __path__: \u002Fvar\u002Flog\u002F*.log\n",[174,8849,8850],{"class":176,"line":3375},[174,8851,2057],{"class":2056},[174,8853,8854],{"class":176,"line":3390},[174,8855,2759],{"emptyLinePlaceholder":935},[174,8857,8858,8860,8862,8864,8866,8869],{"class":176,"line":3395},[174,8859,2226],{"class":180},[174,8861,2215],{"class":188},[174,8863,2218],{"class":184},[174,8865,8643],{"class":184},[174,8867,8868],{"class":188}," ~\u002Falloy\u002Fpromtail.yaml:\u002Fp.yaml",[174,8870,2005],{"class":2004},[174,8872,8873,8875,8878,8881],{"class":176,"line":3400},[174,8874,7924],{"class":188},[174,8876,8877],{"class":188}," convert",[174,8879,8880],{"class":184}," --source-format=promtail",[174,8882,8883],{"class":188}," \u002Fp.yaml\n",[126,8885,8886],{},"ได้ผลออกมาแบบนี้",[164,8888,8892],{"className":8889,"code":8890,"language":8891,"meta":169,"style":169},"language-hcl shiki shiki-themes material-theme-lighter one-dark-pro github-dark","loki.source.file \"system\" {\n    targets = [{\n        __address__ = \"localhost\",\n        __path__    = \"\u002Fvar\u002Flog\u002F*.log\",\n        job         = \"varlogs\",\n    }]\n    forward_to = [loki.write.default.receiver]\n\n    file_match {\n        enabled = true\n    }\n    legacy_positions_file = \"\u002Fvar\u002Flog\u002Fpositions.yaml\"\n}\n\nloki.write \"default\" {\n    endpoint {\n        url = \"http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush\"\n    }\n    external_labels = {}\n}\n","hcl",[171,8893,8894,8919,8930,8944,8958,8975,8982,8992,8996,9003,9013,9018,9032,9036,9040,9057,9064,9078,9082,9092],{"__ignoreMap":169},[174,8895,8896,8899,8901,8904,8906,8909,8911,8914,8916],{"class":176,"line":177},[174,8897,8898],{"class":1542},"loki",[174,8900,2079],{"class":2046},[174,8902,8903],{"class":2094},"source",[174,8905,2079],{"class":2046},[174,8907,8908],{"class":2094},"file",[174,8910,2272],{"class":372},[174,8912,8913],{"class":188},"system",[174,8915,468],{"class":372},[174,8917,8918],{"class":455}," {\n",[174,8920,8921,8924,8926,8928],{"class":176,"line":236},[174,8922,8923],{"class":2094},"    targets",[174,8925,5040],{"class":1539},[174,8927,1536],{"class":1542},[174,8929,456],{"class":455},[174,8931,8932,8935,8937,8940,8942],{"class":176,"line":242},[174,8933,8934],{"class":1542},"        __address__ = ",[174,8936,468],{"class":372},[174,8938,8939],{"class":188},"localhost",[174,8941,468],{"class":372},[174,8943,4833],{"class":1542},[174,8945,8946,8949,8951,8954,8956],{"class":176,"line":248},[174,8947,8948],{"class":1542},"        __path__    = ",[174,8950,468],{"class":372},[174,8952,8953],{"class":188},"\u002Fvar\u002Flog\u002F*.log",[174,8955,468],{"class":372},[174,8957,4833],{"class":1542},[174,8959,8960,8963,8966,8968,8971,8973],{"class":176,"line":254},[174,8961,8962],{"class":2094},"        job",[174,8964,8965],{"class":1539},"         =",[174,8967,2272],{"class":372},[174,8969,8970],{"class":188},"varlogs",[174,8972,468],{"class":372},[174,8974,4833],{"class":1542},[174,8976,8977,8980],{"class":176,"line":2112},[174,8978,8979],{"class":455},"    }",[174,8981,5279],{"class":1542},[174,8983,8984,8987,8989],{"class":176,"line":2129},[174,8985,8986],{"class":2094},"    forward_to",[174,8988,5040],{"class":1539},[174,8990,8991],{"class":1542}," [loki.write.default.receiver]\n",[174,8993,8994],{"class":176,"line":2135},[174,8995,2759],{"emptyLinePlaceholder":935},[174,8997,8998,9001],{"class":176,"line":3364},[174,8999,9000],{"class":1542},"    file_match ",[174,9002,456],{"class":455},[174,9004,9005,9008,9010],{"class":176,"line":3369},[174,9006,9007],{"class":2094},"        enabled",[174,9009,5040],{"class":1539},[174,9011,9012],{"class":474}," true\n",[174,9014,9015],{"class":176,"line":3375},[174,9016,9017],{"class":455},"    }\n",[174,9019,9020,9023,9025,9027,9030],{"class":176,"line":3390},[174,9021,9022],{"class":2094},"    legacy_positions_file",[174,9024,5040],{"class":1539},[174,9026,2272],{"class":372},[174,9028,9029],{"class":188},"\u002Fvar\u002Flog\u002Fpositions.yaml",[174,9031,2278],{"class":372},[174,9033,9034],{"class":176,"line":3395},[174,9035,480],{"class":455},[174,9037,9038],{"class":176,"line":3400},[174,9039,2759],{"emptyLinePlaceholder":935},[174,9041,9042,9044,9046,9049,9051,9053,9055],{"class":176,"line":4044},[174,9043,8898],{"class":1542},[174,9045,2079],{"class":2046},[174,9047,9048],{"class":2094},"write",[174,9050,2272],{"class":372},[174,9052,572],{"class":188},[174,9054,468],{"class":372},[174,9056,8918],{"class":455},[174,9058,9059,9062],{"class":176,"line":4052},[174,9060,9061],{"class":1542},"    endpoint ",[174,9063,456],{"class":455},[174,9065,9066,9069,9071,9073,9076],{"class":176,"line":4060},[174,9067,9068],{"class":2094},"        url",[174,9070,5040],{"class":1539},[174,9072,2272],{"class":372},[174,9074,9075],{"class":188},"http:\u002F\u002Flocalhost:3100\u002Floki\u002Fapi\u002Fv1\u002Fpush",[174,9077,2278],{"class":372},[174,9079,9080],{"class":176,"line":4068},[174,9081,9017],{"class":455},[174,9083,9084,9087,9089],{"class":176,"line":4073},[174,9085,9086],{"class":2094},"    external_labels",[174,9088,5040],{"class":1539},[174,9090,9091],{"class":455}," {}\n",[174,9093,9094],{"class":176,"line":4081},[174,9095,480],{"class":455},[126,9097,9098,9099,9101,9102,9104,9105,9107],{},"สังเกตว่ามันเลือกใช้ ",[171,9100,7852],{}," block ในตัวของ ",[171,9103,7821],{}," แทนที่จะแยก ",[171,9106,7807],{}," ออกมาเหมือนที่ผมเขียนไว้ข้างบน ซึ่งก็ถูกทั้งคู่ครับ",[126,9109,9110],{},"ใช้ได้เลยแต่แนะนำให้อ่านทวนก่อนสักรอบ อย่าเอาไปใช้ทั้งดุ้นเลยทีเดียว",[139,9112,9113],{"id":9113},"ลบของทิ้ง",[126,9115,9116],{},"ลองเสร็จแล้วเก็บกวาดด้วยนะครับ",[164,9118,9120],{"className":3233,"code":9119,"language":2675,"meta":169,"style":169},"docker rm -f alloy-demo loki-demo\ndocker network rm alloy-net\nrm -rf ~\u002Falloy\n",[171,9121,9122,9136,9146],{"__ignoreMap":169},[174,9123,9124,9126,9129,9131,9133],{"class":176,"line":177},[174,9125,2226],{"class":180},[174,9127,9128],{"class":188}," rm",[174,9130,192],{"class":184},[174,9132,7881],{"class":188},[174,9134,9135],{"class":188}," loki-demo\n",[174,9137,9138,9140,9142,9144],{"class":176,"line":236},[174,9139,2226],{"class":180},[174,9141,7543],{"class":188},[174,9143,9128],{"class":188},[174,9145,7549],{"class":188},[174,9147,9148,9151,9154],{"class":176,"line":242},[174,9149,9150],{"class":180},"rm",[174,9152,9153],{"class":184}," -rf",[174,9155,9156],{"class":188}," ~\u002Falloy\n",[139,9158,1370],{"id":1370},[126,9160,9161],{},"ที่ลองมาผมว่า Alloy เข้าใจง่ายกว่า Promtail อยู่พอสมควรครับ ตรงที่ config เป็น component ต่อกันเป็นท่อ แล้วมีหน้า UI ให้ดูว่าท่อมันต่อถูกไหม เวลาพังจะหาต้นตอง่ายกว่าเยอะ",[126,9163,9164],{},"ที่เขียนในบทความนี้เป็นแค่ log อย่างเดียวนะครับ จริง ๆ Alloy ทำ metrics กับ traces ได้ด้วยในตัวเดียวกัน ถ้ามีโอกาสจะมาเขียนต่อ",[126,9166,9167,9168,9170],{},"ส่วนใครที่ยังใช้ Promtail อยู่ ถึงตอนนี้มันยังทำงานได้ปกติก็จริง แต่ EOL ไปแล้วตั้งแต่เดือนมีนาคมครับ แปลว่าถ้ามีช่องโหว่โผล่มาก็จะไม่มีใครแก้ให้แล้ว ควรวางแผนย้ายไว้แต่เนิ่น ๆ ดีกว่า และมีคำสั่ง ",[171,9169,8783],{}," ช่วยอยู่แล้วด้วย",[139,9172,6440],{"id":6439},[707,9174,9175,9182,9189,9196,9203],{},[710,9176,9177],{},[292,9178,9181],{"href":9179,"rel":9180},"https:\u002F\u002Fgrafana.com\u002Fdocs\u002Falloy\u002Flatest\u002F",[296],"Grafana Alloy documentation",[710,9183,9184],{},[292,9185,9188],{"href":9186,"rel":9187},"https:\u002F\u002Fgrafana.com\u002Fdocs\u002Falloy\u002Flatest\u002Fset-up\u002Finstall\u002Fdocker\u002F",[296],"Install Alloy on Docker",[710,9190,9191],{},[292,9192,9195],{"href":9193,"rel":9194},"https:\u002F\u002Fgrafana.com\u002Fdocs\u002Falloy\u002Flatest\u002Freference\u002Fcomponents\u002Floki\u002Floki.source.file\u002F",[296],"loki.source.file component",[710,9197,9198],{},[292,9199,9202],{"href":9200,"rel":9201},"https:\u002F\u002Fgrafana.com\u002Fdocs\u002Floki\u002Flatest\u002Fsend-data\u002Fpromtail\u002F",[296],"Promtail EOL notice",[710,9204,9205],{},[292,9206,9209],{"href":9207,"rel":9208},"https:\u002F\u002Fgrafana.com\u002Fdocs\u002Fagent\u002Flatest\u002F",[296],"Grafana Agent EOL announcement",[909,9211,9212],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sicAX, html code.shiki .sicAX{--shiki-light:#90A4AE;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .s2KDN, html code.shiki .s2KDN{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#9ECBFF}html pre.shiki code .s36IK, html code.shiki .s36IK{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sObbn, html code.shiki .sObbn{--shiki-light:#39ADB5;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sVeMc, html code.shiki .sVeMc{--shiki-light:#9C3EDA;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sLise, html code.shiki .sLise{--shiki-light:#E2931D;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sxkdo, html code.shiki .sxkdo{--shiki-light:#F76D47;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .s9IQt, html code.shiki .s9IQt{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sg798, html code.shiki .sg798{--shiki-light:#90A4AE;--shiki-light-font-style:inherit;--shiki-default:#FFFFFF;--shiki-default-font-style:inherit;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .sZDfs, html code.shiki .sZDfs{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .scCEF, html code.shiki .scCEF{--shiki-light:#39ADB5;--shiki-default:#D19A66;--shiki-dark:#79B8FF}",{"title":169,"searchDepth":236,"depth":236,"links":9214},[9215,9216,9217,9218,9219,9220,9221,9222,9223,9224,9225],{"id":3207,"depth":236,"text":3208},{"id":7492,"depth":236,"text":7493},{"id":3882,"depth":236,"text":3882},{"id":7661,"depth":236,"text":7662},{"id":7962,"depth":236,"text":7963},{"id":7989,"depth":236,"text":7990},{"id":8619,"depth":236,"text":8620},{"id":8776,"depth":236,"text":8777},{"id":9113,"depth":236,"text":9113},{"id":1370,"depth":236,"text":1370},{"id":6439,"depth":236,"text":6440},"แนะนำ Grafana Alloy ตัวเก็บ telemetry รุ่นใหม่ของ Grafana ตั้งแต่ติดตั้งด้วย docker เขียน config ส่ง log เข้า Loki ไปจนถึงคำสั่ง validate และ convert จาก Promtail",{},"Grafana Alloy With Loki",[9230],"2025-05-18-from-old-notebook-to-home-lab-server.md",{"title":7454,"description":9226},{"loc":106,"images":9233,"lastmod":104},[9234],{"loc":7974},"blogs\u002F2026-08-03-grafana-alloy-loki",[945],"3tOOWc7vHAWVF6oZTvJ2iGEf-zHS-kFig-DUL3kjfME",{"id":9239,"title":9240,"body":9241,"date":109,"description":10924,"draft":932,"extension":933,"meta":10925,"navigation":935,"next":936,"ogTitle":10926,"path":108,"pin":932,"prev":936,"recommends":10927,"seo":10929,"sitemap":10930,"stem":10934,"tags":10935,"updated":936,"__hash__":10936},"content\u002Fblogs\u002F2026-08-07-node-exporter-mtls-basic-auth.md","ตั้งค่า node_exporter ให้ปลอดภัยด้วย mTLS และ Basic auth",{"type":123,"value":9242,"toc":10908},[9243,9245,9248,9264,9270,9283,9287,9290,9328,9331,9373,9379,9382,9423,9429,9432,9435,9451,9455,9458,9465,9471,9474,9480,9485,9492,9498,9502,9505,9777,9783,9805,9811,9815,9827,9858,9861,9867,9878,9882,9892,9958,9976,9987,9990,9993,10047,10050,10053,10058,10061,10083,10086,10102,10108,10111,10125,10131,10134,10153,10159,10165,10173,10176,10210,10216,10219,10281,10287,10291,10294,10439,10446,10452,10459,10474,10481,10513,10519,10526,10567,10573,10580,10584,10590,10642,10648,10651,10657,10660,10667,10671,10674,10680,10713,10719,10735,10756,10759,10778,10792,10802,10804,10806,10866,10868,10874,10877,10880,10882,10905],[139,9244,3208],{"id":3207},[126,9246,9247],{},"สวัสดีครับ วันนี้มาแชร์วิธีทำให้ node_exporter ปลอดภัยขึ้นกัน ด้วยการเปิด Basic auth กับ mTLS ครับ เพราะโดยปกติแล้ว Port ดังกล่าวจะสามารถดึงข้อมูลได้ทันที",[126,9249,9250,9251,9254,9255,5159,9260,9263],{},"ระหว่างทางผมไปเจอเรื่องที่ทำให้งงอยู่พักนึงด้วย คือไฟล์ ",[171,9252,9253],{},"web-config.yml"," ที่ปกติเราเขียนให้ Prometheus (",[292,9256,9259],{"href":9257,"rel":9258},"https:\u002F\u002Fprometheus.io\u002Fdocs\u002Fguides\u002Fbasic-auth\u002F",[296],"Securing Prometheus API and UI endpoints using basic auth",[390,9261,9262],{},"เอามาใช้กับ node_exporter ได้เลย"," ทั้งที่ผมเข้าใจมาตลอดว่ามันเป็น config ของ Prometheus อย่างเดียว",[126,9265,9266,9267,9269],{},"บทความนี้ผมรันด้วย docker ทั้งหมดนะครับ เพราะลองแล้วลบทิ้งได้ง่ายดี output ทุกก้อนก๊อปมาจาก terminal ตรง ๆ (มีแก้แค่ชื่อเครื่องกับ arch ให้เป็นค่าทั่วไปนะ) เวอร์ชันที่ใช้คือ node_exporter 1.12.1 กับ Prometheus 3.13.2 (ใครรันแบบ bare metal อยู่แล้วก็อ่านข้ามส่วน ",[171,9268,7781],{}," ไปได้ ตัว config เหมือนกันหมด เดี๋ยวมีบอกท้ายบทความว่าแก้ systemd ตรงไหน)",[126,9271,9272,9273,9275,9276,7812,9279,9282],{},"ของที่ต้องมีคือ docker กับ ",[171,9274,7481],{}," ส่วน ",[171,9277,9278],{},"htpasswd",[171,9280,9281],{},"promtool"," เดี๋ยวเรียกผ่าน docker เอา ไม่ต้องลงเพิ่ม",[139,9284,9286],{"id":9285},"ปัญหาของพอร์ต-9100","ปัญหาของพอร์ต 9100",[126,9288,9289],{},"ลองยกตัวที่ไม่ได้ตั้งอะไรไว้เลยขึ้นมาดูก่อนครับ",[164,9291,9293],{"className":3233,"code":9292,"language":2675,"meta":169,"style":169},"docker network create mon-net\ndocker run -d --name ne-open --network mon-net quay.io\u002Fprometheus\u002Fnode-exporter:latest\n",[171,9294,9295,9306],{"__ignoreMap":169},[174,9296,9297,9299,9301,9303],{"class":176,"line":177},[174,9298,2226],{"class":180},[174,9300,7543],{"class":188},[174,9302,7546],{"class":188},[174,9304,9305],{"class":188}," mon-net\n",[174,9307,9308,9310,9312,9314,9316,9319,9322,9325],{"class":176,"line":236},[174,9309,2226],{"class":180},[174,9311,2215],{"class":188},[174,9313,1986],{"class":184},[174,9315,3478],{"class":184},[174,9317,9318],{"class":188}," ne-open",[174,9320,9321],{"class":184}," --network",[174,9323,9324],{"class":188}," mon-net",[174,9326,9327],{"class":188}," quay.io\u002Fprometheus\u002Fnode-exporter:latest\n",[126,9329,9330],{},"แล้วยิงเข้าไปเฉย ๆ โดยไม่ต้องมี credential",[164,9332,9334],{"className":3233,"code":9333,"language":2675,"meta":169,"style":169},"docker run --rm --network mon-net curlimages\u002Fcurl:latest \\\n  -s http:\u002F\u002Fne-open:9100\u002Fmetrics | grep '^node_uname_info'\n",[171,9335,9336,9353],{"__ignoreMap":169},[174,9337,9338,9340,9342,9344,9346,9348,9351],{"class":176,"line":177},[174,9339,2226],{"class":180},[174,9341,2215],{"class":188},[174,9343,2218],{"class":184},[174,9345,9321],{"class":184},[174,9347,9324],{"class":188},[174,9349,9350],{"class":188}," curlimages\u002Fcurl:latest",[174,9352,2005],{"class":2004},[174,9354,9355,9358,9361,9363,9366,9368,9371],{"class":176,"line":236},[174,9356,9357],{"class":184},"  -s",[174,9359,9360],{"class":188}," http:\u002F\u002Fne-open:9100\u002Fmetrics",[174,9362,8529],{"class":2046},[174,9364,9365],{"class":180}," grep",[174,9367,373],{"class":372},[174,9369,9370],{"class":188},"^node_uname_info",[174,9372,379],{"class":372},[164,9374,9377],{"className":9375,"code":9376,"language":529},[527],"node_uname_info{domainname=\"(none)\",machine=\"x86_64\",nodename=\"homelab-01\",sysname=\"Linux\",version=\"#1 SMP PREEMPT Fri Jul 31 00:11:41 UTC 2026\"} 1\n",[171,9378,9376],{"__ignoreMap":169},[126,9380,9381],{},"ได้ชื่อเครื่อง สถาปัตยกรรม และเวอร์ชัน kernel มาครบ ลองนับทั้งหมดดู",[164,9383,9385],{"className":3233,"code":9384,"language":2675,"meta":169,"style":169},"docker run --rm --network mon-net curlimages\u002Fcurl:latest \\\n  -s http:\u002F\u002Fne-open:9100\u002Fmetrics | grep -c '^node_'\n",[171,9386,9387,9403],{"__ignoreMap":169},[174,9388,9389,9391,9393,9395,9397,9399,9401],{"class":176,"line":177},[174,9390,2226],{"class":180},[174,9392,2215],{"class":188},[174,9394,2218],{"class":184},[174,9396,9321],{"class":184},[174,9398,9324],{"class":188},[174,9400,9350],{"class":188},[174,9402,2005],{"class":2004},[174,9404,9405,9407,9409,9411,9413,9416,9418,9421],{"class":176,"line":236},[174,9406,9357],{"class":184},[174,9408,9360],{"class":188},[174,9410,8529],{"class":2046},[174,9412,9365],{"class":180},[174,9414,9415],{"class":184}," -c",[174,9417,373],{"class":372},[174,9419,9420],{"class":188},"^node_",[174,9422,379],{"class":372},[164,9424,9427],{"className":9425,"code":9426,"language":529},[527],"906\n",[171,9428,9426],{"__ignoreMap":169},[126,9430,9431],{},"906 บรรทัดครับ มีทั้ง mount point ที่มีอยู่ พื้นที่ดิสก์ที่เหลือ interface ที่ต่ออยู่ แล้วก็เวอร์ชัน kernel ที่บอกกลาย ๆ ว่าเครื่องนี้แพตช์ล่าสุดเมื่อไหร่ ข้อมูลพวกนี้อย่างเดียวไม่ได้ทำให้ใครเข้าเครื่องได้ แต่มันก็นับว่าเป็นข้อมูลที่สำคัญในการนำไปหาข้อมูลต่อได้",[126,9433,9434],{},"ลบตัวทดลองทิ้งก่อนไปต่อ",[164,9436,9438],{"className":3233,"code":9437,"language":2675,"meta":169,"style":169},"docker rm -f ne-open\n",[171,9439,9440],{"__ignoreMap":169},[174,9441,9442,9444,9446,9448],{"class":176,"line":177},[174,9443,2226],{"class":180},[174,9445,9128],{"class":188},[174,9447,192],{"class":184},[174,9449,9450],{"class":188}," ne-open\n",[139,9452,9454],{"id":9453},"config-ที่ใช้ร่วมกัน","config ที่ใช้ร่วมกัน",[126,9456,9457],{},"ทีนี้มาถึงเรื่องที่ผมเข้าใจผิดมาตลอดครับ",[126,9459,9460,9461,9464],{},"พอเปิด ",[171,9462,9463],{},"--help"," ของ node_exporter ดู มันชี้ไปที่ repo ของ exporter-toolkit ตรง ๆ เลย",[164,9466,9469],{"className":9467,"code":9468,"language":529},[527],"--web.config.file=\"\"       Path to configuration file that can\n                           enable TLS or authentication. See:\n                           https:\u002F\u002Fgithub.com\u002Fprometheus\u002Fexporter-toolkit\u002Fblob\u002Fmaster\u002Fdocs\u002Fweb-configuration.md\n",[171,9470,9468],{"__ignoreMap":169},[126,9472,9473],{},"ในเอกสารตัวนั้นก็เขียนไว้ตรง ๆ ว่า \"Exporters and services instrumented with the Exporter Toolkit share the same web configuration file format.\"",[126,9475,9476,9477],{},"แปลว่า Prometheus, node_exporter, Alertmanager และ exporter ตัวอื่น ๆ ในตระกูลนี้ใช้ library ตัวเดียวกันจัดการเรื่อง TLS กับ auth ไฟล์ config เลยหน้าตาเหมือนกันหมด flag ที่ใช้เปิดก็ชื่อเดียวกันคือ ",[171,9478,9479],{},"--web.config.file",[126,9481,9482],{},[3766,9483],{"alt":169,"src":9484},"\u002Fimages\u002F2026-08-07-node-exporter-mtls-basic-auth\u002Fshared-config.png",[126,9486,9487,9488,9491],{},"ตอนรัน node_exporter จะเห็นใน log ด้วยว่ามันเรียก ",[171,9489,9490],{},"tls_config.go"," ซึ่งเป็นไฟล์ของ exporter-toolkit ไม่ใช่โค้ดของ node_exporter เอง",[164,9493,9496],{"className":9494,"code":9495,"language":529},[527],"level=INFO source=tls_config.go:415 msg=\"TLS is enabled.\" http2=true address=[::]:9100\n",[171,9497,9495],{"__ignoreMap":169},[139,9499,9501],{"id":9500},"สร้าง-cert","สร้าง cert",[126,9503,9504],{},"mTLS แปลว่าทั้งสองฝั่งต้องยืนยันตัวตนกัน ไม่ใช่แค่ฝั่ง server เพราะฉะนั้นต้องมี CA ของตัวเองไว้เซ็นให้ทั้งคู่",[164,9506,9508],{"className":3233,"code":9507,"language":2675,"meta":169,"style":169},"mkdir -p ~\u002Fnode-exporter\u002Fcerts && cd ~\u002Fnode-exporter\u002Fcerts\n\n# CA ของเราเอง\nopenssl req -x509 -newkey rsa:2048 -nodes -days 365 \\\n  -keyout ca.key -out ca.crt -subj \"\u002FCN=homelab-ca\"\n\n# cert ฝั่ง node_exporter\nopenssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr \\\n  -subj \"\u002FCN=node-exporter\"\nprintf \"subjectAltName=DNS:node-exporter,DNS:localhost,IP:127.0.0.1\" > san.ext\nopenssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \\\n  -out server.crt -days 365 -extfile san.ext\n\n# cert ฝั่ง Prometheus\nopenssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr \\\n  -subj \"\u002FCN=prometheus\"\nopenssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \\\n  -out client.crt -days 365\n",[171,9509,9510,9527,9531,9536,9563,9587,9591,9596,9621,9633,9650,9680,9697,9701,9706,9730,9741,9765],{"__ignoreMap":169},[174,9511,9512,9514,9516,9519,9521,9524],{"class":176,"line":177},[174,9513,3896],{"class":180},[174,9515,7637],{"class":184},[174,9517,9518],{"class":188}," ~\u002Fnode-exporter\u002Fcerts",[174,9520,3248],{"class":455},[174,9522,9523],{"class":2078}," cd",[174,9525,9526],{"class":188}," ~\u002Fnode-exporter\u002Fcerts\n",[174,9528,9529],{"class":176,"line":236},[174,9530,2759],{"emptyLinePlaceholder":935},[174,9532,9533],{"class":176,"line":242},[174,9534,9535],{"class":3353},"# CA ของเราเอง\n",[174,9537,9538,9540,9543,9546,9549,9552,9555,9558,9561],{"class":176,"line":248},[174,9539,4236],{"class":180},[174,9541,9542],{"class":188}," req",[174,9544,9545],{"class":184}," -x509",[174,9547,9548],{"class":184}," -newkey",[174,9550,9551],{"class":188}," rsa:2048",[174,9553,9554],{"class":184}," -nodes",[174,9556,9557],{"class":184}," -days",[174,9559,9560],{"class":1982}," 365",[174,9562,2005],{"class":2004},[174,9564,9565,9568,9571,9574,9577,9580,9582,9585],{"class":176,"line":254},[174,9566,9567],{"class":184},"  -keyout",[174,9569,9570],{"class":188}," ca.key",[174,9572,9573],{"class":184}," -out",[174,9575,9576],{"class":188}," ca.crt",[174,9578,9579],{"class":184}," -subj",[174,9581,2272],{"class":372},[174,9583,9584],{"class":188},"\u002FCN=homelab-ca",[174,9586,2278],{"class":372},[174,9588,9589],{"class":176,"line":2112},[174,9590,2759],{"emptyLinePlaceholder":935},[174,9592,9593],{"class":176,"line":2129},[174,9594,9595],{"class":3353},"# cert ฝั่ง node_exporter\n",[174,9597,9598,9600,9602,9604,9606,9608,9611,9614,9616,9619],{"class":176,"line":2135},[174,9599,4236],{"class":180},[174,9601,9542],{"class":188},[174,9603,9548],{"class":184},[174,9605,9551],{"class":188},[174,9607,9554],{"class":184},[174,9609,9610],{"class":184}," -keyout",[174,9612,9613],{"class":188}," server.key",[174,9615,9573],{"class":184},[174,9617,9618],{"class":188}," server.csr",[174,9620,2005],{"class":2004},[174,9622,9623,9626,9628,9631],{"class":176,"line":3364},[174,9624,9625],{"class":184},"  -subj",[174,9627,2272],{"class":372},[174,9629,9630],{"class":188},"\u002FCN=node-exporter",[174,9632,2278],{"class":372},[174,9634,9635,9638,9640,9643,9645,9647],{"class":176,"line":3369},[174,9636,9637],{"class":2078},"printf",[174,9639,2272],{"class":372},[174,9641,9642],{"class":188},"subjectAltName=DNS:node-exporter,DNS:localhost,IP:127.0.0.1",[174,9644,468],{"class":372},[174,9646,2047],{"class":2046},[174,9648,9649],{"class":188}," san.ext\n",[174,9651,9652,9654,9657,9660,9663,9665,9668,9670,9673,9675,9678],{"class":176,"line":3375},[174,9653,4236],{"class":180},[174,9655,9656],{"class":188}," x509",[174,9658,9659],{"class":184}," -req",[174,9661,9662],{"class":184}," -in",[174,9664,9618],{"class":188},[174,9666,9667],{"class":184}," -CA",[174,9669,9576],{"class":188},[174,9671,9672],{"class":184}," -CAkey",[174,9674,9570],{"class":188},[174,9676,9677],{"class":184}," -CAcreateserial",[174,9679,2005],{"class":2004},[174,9681,9682,9685,9688,9690,9692,9695],{"class":176,"line":3390},[174,9683,9684],{"class":184},"  -out",[174,9686,9687],{"class":188}," server.crt",[174,9689,9557],{"class":184},[174,9691,9560],{"class":1982},[174,9693,9694],{"class":184}," -extfile",[174,9696,9649],{"class":188},[174,9698,9699],{"class":176,"line":3395},[174,9700,2759],{"emptyLinePlaceholder":935},[174,9702,9703],{"class":176,"line":3400},[174,9704,9705],{"class":3353},"# cert ฝั่ง Prometheus\n",[174,9707,9708,9710,9712,9714,9716,9718,9720,9723,9725,9728],{"class":176,"line":4044},[174,9709,4236],{"class":180},[174,9711,9542],{"class":188},[174,9713,9548],{"class":184},[174,9715,9551],{"class":188},[174,9717,9554],{"class":184},[174,9719,9610],{"class":184},[174,9721,9722],{"class":188}," client.key",[174,9724,9573],{"class":184},[174,9726,9727],{"class":188}," client.csr",[174,9729,2005],{"class":2004},[174,9731,9732,9734,9736,9739],{"class":176,"line":4052},[174,9733,9625],{"class":184},[174,9735,2272],{"class":372},[174,9737,9738],{"class":188},"\u002FCN=prometheus",[174,9740,2278],{"class":372},[174,9742,9743,9745,9747,9749,9751,9753,9755,9757,9759,9761,9763],{"class":176,"line":4060},[174,9744,4236],{"class":180},[174,9746,9656],{"class":188},[174,9748,9659],{"class":184},[174,9750,9662],{"class":184},[174,9752,9727],{"class":188},[174,9754,9667],{"class":184},[174,9756,9576],{"class":188},[174,9758,9672],{"class":184},[174,9760,9570],{"class":188},[174,9762,9677],{"class":184},[174,9764,2005],{"class":2004},[174,9766,9767,9769,9772,9774],{"class":176,"line":4068},[174,9768,9684],{"class":184},[174,9770,9771],{"class":188}," client.crt",[174,9773,9557],{"class":184},[174,9775,9776],{"class":1982}," 365\n",[126,9778,7951,9779,9782],{},[171,9780,9781],{},"subjectAltName"," สำคัญมากครับ ต้องใส่ชื่อหรือ IP ที่ Prometheus จะใช้เรียกจริง ๆ ถ้าใส่ไม่ตรงจะ verify ไม่ผ่านตอน scrape เช็คได้ด้วย",[164,9784,9786],{"className":3233,"code":9785,"language":2675,"meta":169,"style":169},"openssl verify -CAfile ca.crt server.crt client.crt\n",[171,9787,9788],{"__ignoreMap":169},[174,9789,9790,9792,9795,9798,9800,9802],{"class":176,"line":177},[174,9791,4236],{"class":180},[174,9793,9794],{"class":188}," verify",[174,9796,9797],{"class":184}," -CAfile",[174,9799,9576],{"class":188},[174,9801,9687],{"class":188},[174,9803,9804],{"class":188}," client.crt\n",[164,9806,9809],{"className":9807,"code":9808,"language":529},[527],"server.crt: OK\nclient.crt: OK\n",[171,9810,9808],{"__ignoreMap":169},[139,9812,9814],{"id":9813},"เปิด-basic-auth","เปิด basic auth",[126,9816,9817,9818,9820,9821,9824,9825],{},"รหัสผ่านใน ",[171,9819,9253],{}," ต้องเป็น bcrypt hash ใส่เป็นข้อความเปล่าไม่ได้ (ถ้าใส่ไป node_exporter จะขึ้นมาแป๊บนึงแล้วดับ พร้อม log ว่า ",[171,9822,9823],{},"hashedSecret too short to be a bcrypted password",") สร้าง hash ด้วย ",[171,9826,9278],{},[164,9828,9830],{"className":3233,"code":9829,"language":2675,"meta":169,"style":169},"docker run --rm -it httpd:2.4-alpine htpasswd -nBC 12 prometheus\n",[171,9831,9832],{"__ignoreMap":169},[174,9833,9834,9836,9838,9840,9843,9846,9849,9852,9855],{"class":176,"line":177},[174,9835,2226],{"class":180},[174,9837,2215],{"class":188},[174,9839,2218],{"class":184},[174,9841,9842],{"class":184}," -it",[174,9844,9845],{"class":188}," httpd:2.4-alpine",[174,9847,9848],{"class":188}," htpasswd",[174,9850,9851],{"class":184}," -nBC",[174,9853,9854],{"class":1982}," 12",[174,9856,9857],{"class":188}," prometheus\n",[126,9859,9860],{},"มันจะถามรหัสให้พิมพ์สองรอบ แล้วพ่นออกมาแบบนี้",[164,9862,9865],{"className":9863,"code":9864,"language":529},[527],"prometheus:$2y$12$\u003Chash 53 ตัวอักษร>\n",[171,9866,9864],{"__ignoreMap":169},[126,9868,9869,9870,9873,9874,9877],{},"ที่ไม่ใช้ ",[171,9871,9872],{},"-b"," แล้วพิมพ์รหัสต่อท้ายคำสั่งไปเลย เพราะรหัสจะไปค้างใน shell history แล้วก็โผล่ใน ",[171,9875,9876],{},"ps"," ด้วยครับ",[139,9879,9881],{"id":9880},"เปิด-mtls","เปิด mTLS",[126,9883,9884,9885,9888,9889],{},"เอา hash ที่ได้มาใส่ แล้วเติม ",[171,9886,9887],{},"tls_server_config"," เข้าไปในไฟล์เดียวกัน สร้างที่ ",[171,9890,9891],{},"~\u002Fnode-exporter\u002Fweb-config.yml",[164,9893,9895],{"className":3233,"code":9894,"language":2675,"meta":169,"style":169},"cat > ~\u002Fnode-exporter\u002Fweb-config.yml \u003C\u003C'EOF'\ntls_server_config:\n  cert_file: \u002Fetc\u002Fnode_exporter\u002Fcerts\u002Fserver.crt\n  key_file: \u002Fetc\u002Fnode_exporter\u002Fcerts\u002Fserver.key\n  client_auth_type: RequireAndVerifyClientCert\n  client_ca_file: \u002Fetc\u002Fnode_exporter\u002Fcerts\u002Fca.crt\n  min_version: TLS12\n\nbasic_auth_users:\n  prometheus: $2y$12$\u003Chash ที่ได้จากขั้นตอนที่แล้ว>\nEOF\n",[171,9896,9897,9910,9915,9920,9925,9930,9935,9940,9944,9949,9954],{"__ignoreMap":169},[174,9898,9899,9901,9903,9906,9908],{"class":176,"line":177},[174,9900,1446],{"class":180},[174,9902,2047],{"class":2046},[174,9904,9905],{"class":188}," ~\u002Fnode-exporter\u002Fweb-config.yml",[174,9907,2053],{"class":2046},[174,9909,7687],{"class":2056},[174,9911,9912],{"class":176,"line":236},[174,9913,9914],{"class":188},"tls_server_config:\n",[174,9916,9917],{"class":176,"line":242},[174,9918,9919],{"class":188},"  cert_file: \u002Fetc\u002Fnode_exporter\u002Fcerts\u002Fserver.crt\n",[174,9921,9922],{"class":176,"line":248},[174,9923,9924],{"class":188},"  key_file: \u002Fetc\u002Fnode_exporter\u002Fcerts\u002Fserver.key\n",[174,9926,9927],{"class":176,"line":254},[174,9928,9929],{"class":188},"  client_auth_type: RequireAndVerifyClientCert\n",[174,9931,9932],{"class":176,"line":2112},[174,9933,9934],{"class":188},"  client_ca_file: \u002Fetc\u002Fnode_exporter\u002Fcerts\u002Fca.crt\n",[174,9936,9937],{"class":176,"line":2129},[174,9938,9939],{"class":188},"  min_version: TLS12\n",[174,9941,9942],{"class":176,"line":2135},[174,9943,2759],{"emptyLinePlaceholder":935},[174,9945,9946],{"class":176,"line":3364},[174,9947,9948],{"class":188},"basic_auth_users:\n",[174,9950,9951],{"class":176,"line":3369},[174,9952,9953],{"class":188},"  prometheus: $2y$12$\u003Chash ที่ได้จากขั้นตอนที่แล้ว>\n",[174,9955,9956],{"class":176,"line":3375},[174,9957,2057],{"class":2056},[126,9959,9960,9961,9964,9965,9967,9968,9971,9972,9975],{},"path ใน config เป็น path ",[390,9962,9963],{},"ข้างใน container"," นะครับ เดี๋ยวตอน ",[171,9966,7781],{}," เรา mount ",[171,9969,9970],{},"~\u002Fnode-exporter\u002Fcerts"," ไปไว้ที่ ",[171,9973,9974],{},"\u002Fetc\u002Fnode_exporter\u002Fcerts"," ให้ตรงกัน ถ้ารันแบบ bare metal ก็เปลี่ยนเป็น path จริงบนเครื่องได้เลย",[126,9977,9978,9979,9982,9983,9986],{},"หัวใจอยู่ที่ ",[171,9980,9981],{},"client_auth_type: RequireAndVerifyClientCert"," ครับ อันนี้แหละที่ทำให้เป็น mTLS จริง ๆ คือ server จะบังคับให้ client ส่ง cert มาด้วย แล้วตรวจว่าเซ็นด้วย CA ใน ",[171,9984,9985],{},"client_ca_file"," หรือเปล่า",[126,9988,9989],{},"เอกสารของ exporter-toolkit เตือนไว้ตรง ๆ ว่า \"If you want to enable client authentication, you need to use RequireAndVerifyClientCert. Other values are insecure.\" อย่าใส่ค่าอื่นแม้ชื่อจะดูคล้ายกันนะครับ",[126,9991,9992],{},"รันได้แล้ว",[164,9994,9996],{"className":3233,"code":9995,"language":2675,"meta":169,"style":169},"docker run -d --name node-exporter --network mon-net \\\n  -v ~\u002Fnode-exporter\u002Fweb-config.yml:\u002Fetc\u002Fnode_exporter\u002Fweb-config.yml:ro \\\n  -v ~\u002Fnode-exporter\u002Fcerts:\u002Fetc\u002Fnode_exporter\u002Fcerts:ro \\\n  quay.io\u002Fprometheus\u002Fnode-exporter:latest \\\n  --web.config.file=\u002Fetc\u002Fnode_exporter\u002Fweb-config.yml\n",[171,9997,9998,10017,10026,10035,10042],{"__ignoreMap":169},[174,9999,10000,10002,10004,10006,10008,10011,10013,10015],{"class":176,"line":177},[174,10001,2226],{"class":180},[174,10003,2215],{"class":188},[174,10005,1986],{"class":184},[174,10007,3478],{"class":184},[174,10009,10010],{"class":188}," node-exporter",[174,10012,9321],{"class":184},[174,10014,9324],{"class":188},[174,10016,2005],{"class":2004},[174,10018,10019,10021,10024],{"class":176,"line":236},[174,10020,7905],{"class":184},[174,10022,10023],{"class":188}," ~\u002Fnode-exporter\u002Fweb-config.yml:\u002Fetc\u002Fnode_exporter\u002Fweb-config.yml:ro",[174,10025,2005],{"class":2004},[174,10027,10028,10030,10033],{"class":176,"line":242},[174,10029,7905],{"class":184},[174,10031,10032],{"class":188}," ~\u002Fnode-exporter\u002Fcerts:\u002Fetc\u002Fnode_exporter\u002Fcerts:ro",[174,10034,2005],{"class":2004},[174,10036,10037,10040],{"class":176,"line":248},[174,10038,10039],{"class":188},"  quay.io\u002Fprometheus\u002Fnode-exporter:latest",[174,10041,2005],{"class":2004},[174,10043,10044],{"class":176,"line":254},[174,10045,10046],{"class":184},"  --web.config.file=\u002Fetc\u002Fnode_exporter\u002Fweb-config.yml\n",[139,10048,10049],{"id":10049},"ทดสอบทีละชั้น",[126,10051,10052],{},"ตรงนี้สนุกครับ เพราะขาดชั้นไหนไป error ที่ได้ก็คนละแบบกัน ใช้ไล่หาสาเหตุได้เลย",[126,10054,10055],{},[3766,10056],{"alt":169,"src":10057},"\u002Fimages\u002F2026-08-07-node-exporter-mtls-basic-auth\u002Fauth-layers.png",[126,10059,10060],{},"ผมตั้ง alias สั้น ๆ ไว้ก่อน จะได้ไม่ต้องพิมพ์ยาว",[164,10062,10064],{"className":3233,"code":10063,"language":2675,"meta":169,"style":169},"alias c='docker run --rm --network mon-net -v ~\u002Fnode-exporter\u002Fcerts:\u002Fc:ro curlimages\u002Fcurl:latest'\n",[171,10065,10066],{"__ignoreMap":169},[174,10067,10068,10071,10074,10076,10078,10081],{"class":176,"line":177},[174,10069,10070],{"class":4948},"alias",[174,10072,10073],{"class":2094}," c",[174,10075,4326],{"class":1539},[174,10077,7653],{"class":372},[174,10079,10080],{"class":188},"docker run --rm --network mon-net -v ~\u002Fnode-exporter\u002Fcerts:\u002Fc:ro curlimages\u002Fcurl:latest",[174,10082,379],{"class":372},[126,10084,10085],{},"เริ่มจากยิง http เปล่า ๆ แบบเดิม",[164,10087,10089],{"className":3233,"code":10088,"language":2675,"meta":169,"style":169},"c -sS http:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[171,10090,10091],{"__ignoreMap":169},[174,10092,10093,10096,10099],{"class":176,"line":177},[174,10094,10095],{"class":180},"c",[174,10097,10098],{"class":184}," -sS",[174,10100,10101],{"class":188}," http:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[164,10103,10106],{"className":10104,"code":10105,"language":529},[527],"Client sent an HTTP request to an HTTPS server.\n",[171,10107,10105],{"__ignoreMap":169},[126,10109,10110],{},"เปลี่ยนเป็น https แต่ยังไม่บอก CA",[164,10112,10114],{"className":3233,"code":10113,"language":2675,"meta":169,"style":169},"c -sS https:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[171,10115,10116],{"__ignoreMap":169},[174,10117,10118,10120,10122],{"class":176,"line":177},[174,10119,10095],{"class":180},[174,10121,10098],{"class":184},[174,10123,10124],{"class":188}," https:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[164,10126,10129],{"className":10127,"code":10128,"language":529},[527],"curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)\nMore details here: https:\u002F\u002Fcurl.se\u002Fdocs\u002Fsslcerts.html\n",[171,10130,10128],{"__ignoreMap":169},[126,10132,10133],{},"ใส่ CA แล้วแต่ยังไม่มี client cert",[164,10135,10137],{"className":3233,"code":10136,"language":2675,"meta":169,"style":169},"c -sS --cacert \u002Fc\u002Fca.crt https:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[171,10138,10139],{"__ignoreMap":169},[174,10140,10141,10143,10145,10148,10151],{"class":176,"line":177},[174,10142,10095],{"class":180},[174,10144,10098],{"class":184},[174,10146,10147],{"class":184}," --cacert",[174,10149,10150],{"class":188}," \u002Fc\u002Fca.crt",[174,10152,10124],{"class":188},[164,10154,10157],{"className":10155,"code":10156,"language":529},[527],"curl: (56) OpenSSL SSL_read: OpenSSL\u002F3.5.7: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0\n",[171,10158,10156],{"__ignoreMap":169},[126,10160,1698,10161,10164],{},[171,10162,10163],{},"alert certificate required"," นี่แหละครับคือหลักฐานว่า mTLS ทำงานอยู่ ฝั่ง server ไม่ยอมคุยต่อเพราะเราไม่ได้ส่ง cert ไปให้",[1031,10166,10167],{},[126,10168,10169,10170,10172],{},"ข้อความพวกนี้มาจาก curl ที่ build กับ OpenSSL นะครับ ถ้ายิงจาก macOS ที่ curl ใช้ LibreSSL จะได้เลข exit code กับข้อความคนละแบบ และจะไม่มีคำว่า ",[171,10171,10163],{}," ให้เห็น ผมเลยยิงผ่าน container เอาเพื่อให้ทุกคนได้ผลเหมือนกัน",[126,10174,10175],{},"ใส่ client cert แล้วแต่ยังไม่ใส่ user กับ password",[164,10177,10179],{"className":3233,"code":10178,"language":2675,"meta":169,"style":169},"c -sS --cacert \u002Fc\u002Fca.crt --cert \u002Fc\u002Fclient.crt --key \u002Fc\u002Fclient.key \\\n  https:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[171,10180,10181,10205],{"__ignoreMap":169},[174,10182,10183,10185,10187,10189,10191,10194,10197,10200,10203],{"class":176,"line":177},[174,10184,10095],{"class":180},[174,10186,10098],{"class":184},[174,10188,10147],{"class":184},[174,10190,10150],{"class":188},[174,10192,10193],{"class":184}," --cert",[174,10195,10196],{"class":188}," \u002Fc\u002Fclient.crt",[174,10198,10199],{"class":184}," --key",[174,10201,10202],{"class":188}," \u002Fc\u002Fclient.key",[174,10204,2005],{"class":2004},[174,10206,10207],{"class":176,"line":236},[174,10208,10209],{"class":188},"  https:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[164,10211,10214],{"className":10212,"code":10213,"language":529},[527],"Unauthorized\n",[171,10215,10213],{"__ignoreMap":169},[126,10217,10218],{},"คราวนี้ผ่านชั้น TLS มาได้แล้ว มาตกที่ basic auth แทน (HTTP 401) ใส่ให้ครบทั้งหมด",[164,10220,10222],{"className":3233,"code":10221,"language":2675,"meta":169,"style":169},"c -sS -u prometheus:'รหัสที่ตั้งไว้' \\\n  --cacert \u002Fc\u002Fca.crt --cert \u002Fc\u002Fclient.crt --key \u002Fc\u002Fclient.key \\\n  https:\u002F\u002Fnode-exporter:9100\u002Fmetrics | grep -E '^node_(boot_time_seconds|uname_info)'\n",[171,10223,10224,10245,10262],{"__ignoreMap":169},[174,10225,10226,10228,10230,10233,10236,10238,10241,10243],{"class":176,"line":177},[174,10227,10095],{"class":180},[174,10229,10098],{"class":184},[174,10231,10232],{"class":184}," -u",[174,10234,10235],{"class":188}," prometheus:",[174,10237,7653],{"class":372},[174,10239,10240],{"class":188},"รหัสที่ตั้งไว้",[174,10242,7653],{"class":372},[174,10244,2005],{"class":2004},[174,10246,10247,10250,10252,10254,10256,10258,10260],{"class":176,"line":236},[174,10248,10249],{"class":184},"  --cacert",[174,10251,10150],{"class":188},[174,10253,10193],{"class":184},[174,10255,10196],{"class":188},[174,10257,10199],{"class":184},[174,10259,10202],{"class":188},[174,10261,2005],{"class":2004},[174,10263,10264,10267,10269,10271,10274,10276,10279],{"class":176,"line":242},[174,10265,10266],{"class":188},"  https:\u002F\u002Fnode-exporter:9100\u002Fmetrics",[174,10268,8529],{"class":2046},[174,10270,9365],{"class":180},[174,10272,10273],{"class":184}," -E",[174,10275,373],{"class":372},[174,10277,10278],{"class":188},"^node_(boot_time_seconds|uname_info)",[174,10280,379],{"class":372},[164,10282,10285],{"className":10283,"code":10284,"language":529},[527],"node_boot_time_seconds 1.786004256e+09\nnode_uname_info{domainname=\"(none)\",machine=\"x86_64\",nodename=\"homelab-01\",...} 1\n",[171,10286,10284],{"__ignoreMap":169},[139,10288,10290],{"id":10289},"ฝั่ง-prometheus","ฝั่ง Prometheus",[126,10292,10293],{},"ทีนี้ต้องบอก Prometheus ว่าให้ส่งอะไรไปบ้างตอน scrape",[164,10295,10297],{"className":3233,"code":10296,"language":2675,"meta":169,"style":169},"cat > ~\u002Fnode-exporter\u002Fprometheus.yml \u003C\u003C'EOF'\nglobal:\n  scrape_interval: 15s\n\nscrape_configs:\n  - job_name: 'node'\n    scheme: https\n    static_configs:\n      - targets: ['node-exporter:9100']\n    basic_auth:\n      username: prometheus\n      password: 'รหัสที่ตั้งไว้'\n    tls_config:\n      ca_file: \u002Fetc\u002Fprometheus\u002Fcerts\u002Fca.crt\n      cert_file: \u002Fetc\u002Fprometheus\u002Fcerts\u002Fclient.crt\n      key_file: \u002Fetc\u002Fprometheus\u002Fcerts\u002Fclient.key\nEOF\n\ndocker run -d --name prometheus --network mon-net -p 9090:9090 \\\n  -v ~\u002Fnode-exporter\u002Fprometheus.yml:\u002Fetc\u002Fprometheus\u002Fprometheus.yml:ro \\\n  -v ~\u002Fnode-exporter\u002Fcerts:\u002Fetc\u002Fprometheus\u002Fcerts:ro \\\n  prom\u002Fprometheus:latest\n",[171,10298,10299,10312,10317,10322,10326,10330,10335,10340,10344,10349,10354,10359,10364,10369,10374,10379,10384,10388,10392,10416,10425,10434],{"__ignoreMap":169},[174,10300,10301,10303,10305,10308,10310],{"class":176,"line":177},[174,10302,1446],{"class":180},[174,10304,2047],{"class":2046},[174,10306,10307],{"class":188}," ~\u002Fnode-exporter\u002Fprometheus.yml",[174,10309,2053],{"class":2046},[174,10311,7687],{"class":2056},[174,10313,10314],{"class":176,"line":236},[174,10315,10316],{"class":188},"global:\n",[174,10318,10319],{"class":176,"line":242},[174,10320,10321],{"class":188},"  scrape_interval: 15s\n",[174,10323,10324],{"class":176,"line":248},[174,10325,2759],{"emptyLinePlaceholder":935},[174,10327,10328],{"class":176,"line":254},[174,10329,8817],{"class":188},[174,10331,10332],{"class":176,"line":2112},[174,10333,10334],{"class":188},"  - job_name: 'node'\n",[174,10336,10337],{"class":176,"line":2129},[174,10338,10339],{"class":188},"    scheme: https\n",[174,10341,10342],{"class":176,"line":2135},[174,10343,8827],{"class":188},[174,10345,10346],{"class":176,"line":3364},[174,10347,10348],{"class":188},"      - targets: ['node-exporter:9100']\n",[174,10350,10351],{"class":176,"line":3369},[174,10352,10353],{"class":188},"    basic_auth:\n",[174,10355,10356],{"class":176,"line":3375},[174,10357,10358],{"class":188},"      username: prometheus\n",[174,10360,10361],{"class":176,"line":3390},[174,10362,10363],{"class":188},"      password: 'รหัสที่ตั้งไว้'\n",[174,10365,10366],{"class":176,"line":3395},[174,10367,10368],{"class":188},"    tls_config:\n",[174,10370,10371],{"class":176,"line":3400},[174,10372,10373],{"class":188},"      ca_file: \u002Fetc\u002Fprometheus\u002Fcerts\u002Fca.crt\n",[174,10375,10376],{"class":176,"line":4044},[174,10377,10378],{"class":188},"      cert_file: \u002Fetc\u002Fprometheus\u002Fcerts\u002Fclient.crt\n",[174,10380,10381],{"class":176,"line":4052},[174,10382,10383],{"class":188},"      key_file: \u002Fetc\u002Fprometheus\u002Fcerts\u002Fclient.key\n",[174,10385,10386],{"class":176,"line":4060},[174,10387,2057],{"class":2056},[174,10389,10390],{"class":176,"line":4068},[174,10391,2759],{"emptyLinePlaceholder":935},[174,10393,10394,10396,10398,10400,10402,10405,10407,10409,10411,10414],{"class":176,"line":4073},[174,10395,2226],{"class":180},[174,10397,2215],{"class":188},[174,10399,1986],{"class":184},[174,10401,3478],{"class":184},[174,10403,10404],{"class":188}," prometheus",[174,10406,9321],{"class":184},[174,10408,9324],{"class":188},[174,10410,7637],{"class":184},[174,10412,10413],{"class":188}," 9090:9090",[174,10415,2005],{"class":2004},[174,10417,10418,10420,10423],{"class":176,"line":4081},[174,10419,7905],{"class":184},[174,10421,10422],{"class":188}," ~\u002Fnode-exporter\u002Fprometheus.yml:\u002Fetc\u002Fprometheus\u002Fprometheus.yml:ro",[174,10424,2005],{"class":2004},[174,10426,10427,10429,10432],{"class":176,"line":4091},[174,10428,7905],{"class":184},[174,10430,10431],{"class":188}," ~\u002Fnode-exporter\u002Fcerts:\u002Fetc\u002Fprometheus\u002Fcerts:ro",[174,10433,2005],{"class":2004},[174,10435,10436],{"class":176,"line":4100},[174,10437,10438],{"class":188},"  prom\u002Fprometheus:latest\n",[126,10440,10441,10442,10445],{},"จุดที่คนพลาดกันบ่อยคือลืม ",[171,10443,10444],{},"scheme: https"," ครับ ค่าเริ่มต้นของ Prometheus คือ http ผมลองลบบรรทัดนั้นออกดูแล้ว หน้า target จะขึ้นแบบนี้",[164,10447,10450],{"className":10448,"code":10449,"language":529},[527],"url       = http:\u002F\u002Fnode-exporter:9100\u002Fmetrics\nhealth    = down\nlastError = server returned HTTP status 400 Bad Request\n",[171,10451,10449],{"__ignoreMap":169},[126,10453,10454,10455,10458],{},"สังเกตว่ามันไม่ได้บอกว่า ",[171,10456,10457],{},"Client sent an HTTP request to an HTTPS server"," เหมือนตอนที่เรายิง curl เองนะครับ ข้อความนั้นเป็นแค่ body ที่ Prometheus ทิ้งไป เหลือให้เห็นแค่ 400 เฉย ๆ เพราะฉะนั้นถ้าเจอ 400 กับ target ที่เป็น node_exporter ให้สงสัยเรื่อง scheme ไว้ก่อนเลย",[126,10460,10461,10462,10465,10466,10469,10470,10473],{},"ส่วนที่ไม่ได้ใส่ไว้ในตัวอย่างคือ ",[171,10463,10464],{},"server_name"," ครับ มันเป็นตัว override ชื่อที่ใช้ตรวจ cert จำเป็นตอนที่ address ของ target ไม่ตรงกับ SAN เช่นเวลา scrape ด้วย IP ในที่นี้ ",[171,10467,10468],{},"node-exporter:9100"," ตรงกับ ",[171,10471,10472],{},"DNS:node-exporter"," อยู่แล้วเลยไม่ต้องใส่",[126,10475,10476,10477,10480],{},"รอสัก 20 วินาทีให้ scrape รอบแรกทำงานก่อนนะครับ แล้วค่อยเช็ค ถ้าถามเร็วเกินไปจะเห็น health เป็น ",[171,10478,10479],{},"unknown"," แล้วนึกว่าพัง",[164,10482,10484],{"className":3233,"code":10483,"language":2675,"meta":169,"style":169},"curl -s http:\u002F\u002Flocalhost:9090\u002Fapi\u002Fv1\u002Ftargets \\\n  | jq -r '.data.activeTargets[] | \"\\(.labels.job)  \\(.health)  \\(.scrapeUrl)\"'\n",[171,10485,10486,10497],{"__ignoreMap":169},[174,10487,10488,10490,10492,10495],{"class":176,"line":177},[174,10489,2380],{"class":180},[174,10491,7608],{"class":184},[174,10493,10494],{"class":188}," http:\u002F\u002Flocalhost:9090\u002Fapi\u002Fv1\u002Ftargets",[174,10496,2005],{"class":2004},[174,10498,10499,10502,10504,10506,10508,10511],{"class":176,"line":236},[174,10500,10501],{"class":2046},"  |",[174,10503,8532],{"class":180},[174,10505,8535],{"class":184},[174,10507,373],{"class":372},[174,10509,10510],{"class":188},".data.activeTargets[] | \"\\(.labels.job)  \\(.health)  \\(.scrapeUrl)\"",[174,10512,379],{"class":372},[164,10514,10517],{"className":10515,"code":10516,"language":529},[527],"node  up  https:\u002F\u002Fnode-exporter:9100\u002Fmetrics\n",[171,10518,10516],{"__ignoreMap":169},[126,10520,10521,10522,10525],{},"หรือจะ query ค่า ",[171,10523,10524],{},"up"," ตรง ๆ ก็ได้",[164,10527,10529],{"className":3233,"code":10528,"language":2675,"meta":169,"style":169},"curl -sG http:\u002F\u002Flocalhost:9090\u002Fapi\u002Fv1\u002Fquery --data-urlencode 'query=up{job=\"node\"}' \\\n  | jq -r '.data.result[] | \"up = \\(.value[1])  instance=\\(.metric.instance)\"'\n",[171,10530,10531,10552],{"__ignoreMap":169},[174,10532,10533,10535,10537,10540,10543,10545,10548,10550],{"class":176,"line":177},[174,10534,2380],{"class":180},[174,10536,8226],{"class":184},[174,10538,10539],{"class":188}," http:\u002F\u002Flocalhost:9090\u002Fapi\u002Fv1\u002Fquery",[174,10541,10542],{"class":184}," --data-urlencode",[174,10544,373],{"class":372},[174,10546,10547],{"class":188},"query=up{job=\"node\"}",[174,10549,7653],{"class":372},[174,10551,2005],{"class":2004},[174,10553,10554,10556,10558,10560,10562,10565],{"class":176,"line":236},[174,10555,10501],{"class":2046},[174,10557,8532],{"class":180},[174,10559,8535],{"class":184},[174,10561,373],{"class":372},[174,10563,10564],{"class":188},".data.result[] | \"up = \\(.value[1])  instance=\\(.metric.instance)\"",[174,10566,379],{"class":372},[164,10568,10571],{"className":10569,"code":10570,"language":529},[527],"up = 1  instance=node-exporter:9100\n",[171,10572,10570],{"__ignoreMap":169},[126,10574,10575,10576,10579],{},"ได้ ",[171,10577,10578],{},"1"," แปลว่า scrape ผ่าน mTLS สำเร็จแล้วครับ",[139,10581,10583],{"id":10582},"ตรวจ-config","ตรวจ config",[126,10585,10586,10587,10589],{},"อันนี้เป็นของแถมที่ผมชอบมาก ",[171,10588,9281],{}," ของ Prometheus ตรวจไฟล์ของ node_exporter ได้ด้วย เพราะมันเป็น format เดียวกันนั่นแหละ",[164,10591,10593],{"className":3233,"code":10592,"language":2675,"meta":169,"style":169},"docker run --rm --entrypoint promtool \\\n  -v ~\u002Fnode-exporter\u002Fweb-config.yml:\u002Fw.yml:ro \\\n  -v ~\u002Fnode-exporter\u002Fcerts:\u002Fetc\u002Fnode_exporter\u002Fcerts:ro \\\n  prom\u002Fprometheus:latest check web-config \u002Fw.yml\n",[171,10594,10595,10611,10620,10628],{"__ignoreMap":169},[174,10596,10597,10599,10601,10603,10606,10609],{"class":176,"line":177},[174,10598,2226],{"class":180},[174,10600,2215],{"class":188},[174,10602,2218],{"class":184},[174,10604,10605],{"class":184}," --entrypoint",[174,10607,10608],{"class":188}," promtool",[174,10610,2005],{"class":2004},[174,10612,10613,10615,10618],{"class":176,"line":236},[174,10614,7905],{"class":184},[174,10616,10617],{"class":188}," ~\u002Fnode-exporter\u002Fweb-config.yml:\u002Fw.yml:ro",[174,10619,2005],{"class":2004},[174,10621,10622,10624,10626],{"class":176,"line":242},[174,10623,7905],{"class":184},[174,10625,10032],{"class":188},[174,10627,2005],{"class":2004},[174,10629,10630,10633,10636,10639],{"class":176,"line":248},[174,10631,10632],{"class":188},"  prom\u002Fprometheus:latest",[174,10634,10635],{"class":188}," check",[174,10637,10638],{"class":188}," web-config",[174,10640,10641],{"class":188}," \u002Fw.yml\n",[164,10643,10646],{"className":10644,"code":10645,"language":529},[527],"\u002Fw.yml SUCCESS\n",[171,10647,10645],{"__ignoreMap":169},[126,10649,10650],{},"ลองพิมพ์ค่าผิดดูว่ามันจับได้ไหม",[164,10652,10655],{"className":10653,"code":10654,"language":529},[527],"\u002Fw.yml FAILED: invalid ClientAuth: RequireAnyClientCert2\n",[171,10656,10654],{"__ignoreMap":169},[126,10658,10659],{},"จับได้ครับ ควรรันทุกครั้งก่อน restart service เพราะถ้า config พังแล้ว service ไม่ขึ้น กว่าจะรู้ตัวก็ตอน metrics หายไปแล้ว",[126,10661,10662,10663,10666],{},"อย่างเดียวที่ต้องระวังคือมันเปิดไฟล์ cert ตาม path ใน config ไปด้วย เพราะฉะนั้นต้องรันบนเครื่องที่มีไฟล์พวกนั้นอยู่จริง (หรือ mount เข้าไปให้ตรง path เหมือนคำสั่งข้างบน) ไม่งั้นจะได้ ",[171,10664,10665],{},"failed to read cert_file"," ทั้งที่ config ถูกทุกอย่าง",[139,10668,10670],{"id":10669},"ถ้ารันแบบ-bare-metal","ถ้ารันแบบ bare metal",[126,10672,10673],{},"ที่ทำมาทั้งหมดใช้กับ systemd ได้เหมือนกันครับ ต่างแค่สองอย่าง",[126,10675,10676,10677,10679],{},"หนึ่ง เปลี่ยน path ใน ",[171,10678,9253],{}," เป็น path จริงบนเครื่อง แล้วก๊อป cert ไปไว้ตรงนั้น",[164,10681,10683],{"className":3233,"code":10682,"language":2675,"meta":169,"style":169},"sudo mkdir -p \u002Fetc\u002Fnode_exporter\nsudo cp -r ~\u002Fnode-exporter\u002Fcerts ~\u002Fnode-exporter\u002Fweb-config.yml \u002Fetc\u002Fnode_exporter\u002F\n",[171,10684,10685,10697],{"__ignoreMap":169},[174,10686,10687,10689,10692,10694],{"class":176,"line":177},[174,10688,403],{"class":180},[174,10690,10691],{"class":188}," mkdir",[174,10693,7637],{"class":184},[174,10695,10696],{"class":188}," \u002Fetc\u002Fnode_exporter\n",[174,10698,10699,10701,10704,10706,10708,10710],{"class":176,"line":236},[174,10700,403],{"class":180},[174,10702,10703],{"class":188}," cp",[174,10705,8535],{"class":184},[174,10707,9518],{"class":188},[174,10709,9905],{"class":188},[174,10711,10712],{"class":188}," \u002Fetc\u002Fnode_exporter\u002F\n",[126,10714,10715,10716],{},"สอง เติม flag เข้าไปใน unit ที่ ",[171,10717,10718],{},"\u002Fetc\u002Fsystemd\u002Fsystem\u002Fnode_exporter.service",[164,10720,10724],{"className":10721,"code":10722,"language":10723,"meta":169,"style":169},"language-ini shiki shiki-themes material-theme-lighter one-dark-pro github-dark","ExecStart=\u002Fusr\u002Flocal\u002Fbin\u002Fnode_exporter \\\n  --web.config.file=\u002Fetc\u002Fnode_exporter\u002Fweb-config.yml\n","ini",[171,10725,10726,10731],{"__ignoreMap":169},[174,10727,10728],{"class":176,"line":177},[174,10729,10730],{},"ExecStart=\u002Fusr\u002Flocal\u002Fbin\u002Fnode_exporter \\\n",[174,10732,10733],{"class":176,"line":236},[174,10734,10046],{},[126,10736,10737,10738,10741,10742,10744,10745,10747,10748,10751,10752,10755],{},"แล้ว ",[171,10739,10740],{},"sudo systemctl daemon-reload && sudo systemctl restart node_exporter"," ตามปกติ ส่วน ",[171,10743,9281],{}," จะติดมากับ tarball ของ Prometheus อยู่แล้ว และ ",[171,10746,9278],{}," อยู่ในแพ็กเกจ ",[171,10749,10750],{},"apache2-utils"," (Debian\u002FUbuntu) หรือ ",[171,10753,10754],{},"httpd-tools"," (RHEL)",[139,10757,10758],{"id":10758},"ข้อควรระวัง",[126,10760,10761,10764,10765,10767,10768,439,10771,10774,10775,10777],{},[390,10762,10763],{},"รหัสผ่านอยู่หลายที่ ต้องเปลี่ยนพร้อมกัน"," ตอนหมุนรหัสต้องแก้ทั้ง ",[171,10766,9253],{}," ฝั่ง node_exporter และ ",[171,10769,10770],{},"basic_auth",[171,10772,10773],{},"prometheus.yml"," ถ้าแก้ไม่ครบ target จะกลายเป็น down แล้วอาการที่เห็นมีอย่างเดียวคือ ",[171,10776,10524],{}," เป็น 0",[126,10779,10780,10783,10784,10787,10788,10791],{},[390,10781,10782],{},"cert มีวันหมดอายุ"," ที่ผมตั้งไว้คือ 365 วัน พอครบแล้ว target ตัวนั้นจะ down ทันที (ตัวอื่นที่ไม่ได้ใช้ cert ยังทำงานปกติ) ที่สำคัญคือ ",[390,10785,10786],{},"ต้องจำวันหมดอายุเอง"," เพราะสแตกที่ตั้งในบทความนี้ไม่มีตัวไหนคอย monitor cert ให้ ผมลอง query ",[171,10789,10790],{},"probe_ssl_earliest_cert_expiry"," ที่หลายคนแนะนำกันดูแล้ว ได้ผลลัพธ์ว่างเปล่า เพราะ metric ตัวนั้นเป็นของ blackbox_exporter ซึ่งไม่ได้อยู่ในบทความนี้ ถ้าจะใช้จริงต้องลง blackbox_exporter เพิ่มแล้วตั้ง module ให้ใส่ client cert ไปด้วย ไม่งั้นมันก็ทะลุ mTLS เข้าไปวัดไม่ได้เหมือนกัน ทางที่ง่ายกว่าคือจดวันหมดอายุใส่ปฏิทินไว้เลยครับ",[126,10793,10794,10797,10798,10801],{},[390,10795,10796],{},"ถ้า Prometheus อยู่เครื่องเดียวกับ node_exporter"," ผูก ",[171,10799,10800],{},"--web.listen-address=127.0.0.1:9100"," ไปเลยง่ายกว่าเยอะครับ ไม่ต้องยุ่งกับ cert เลยสักนิด mTLS มีประโยชน์ตอนที่ต้องวิ่งข้ามเครื่องข้ามวงจริง ๆ",[139,10803,9113],{"id":9113},[126,10805,9116],{},[164,10807,10809],{"className":3233,"code":10808,"language":2675,"meta":169,"style":169},"docker rm -f node-exporter prometheus\ndocker network rm mon-net\ndocker rmi quay.io\u002Fprometheus\u002Fnode-exporter:latest prom\u002Fprometheus:latest curlimages\u002Fcurl:latest\nrm -rf ~\u002Fnode-exporter\nunalias c\n",[171,10810,10811,10823,10833,10849,10858],{"__ignoreMap":169},[174,10812,10813,10815,10817,10819,10821],{"class":176,"line":177},[174,10814,2226],{"class":180},[174,10816,9128],{"class":188},[174,10818,192],{"class":184},[174,10820,10010],{"class":188},[174,10822,9857],{"class":188},[174,10824,10825,10827,10829,10831],{"class":176,"line":236},[174,10826,2226],{"class":180},[174,10828,7543],{"class":188},[174,10830,9128],{"class":188},[174,10832,9305],{"class":188},[174,10834,10835,10837,10840,10843,10846],{"class":176,"line":242},[174,10836,2226],{"class":180},[174,10838,10839],{"class":188}," rmi",[174,10841,10842],{"class":188}," quay.io\u002Fprometheus\u002Fnode-exporter:latest",[174,10844,10845],{"class":188}," prom\u002Fprometheus:latest",[174,10847,10848],{"class":188}," curlimages\u002Fcurl:latest\n",[174,10850,10851,10853,10855],{"class":176,"line":248},[174,10852,9150],{"class":180},[174,10854,9153],{"class":184},[174,10856,10857],{"class":188}," ~\u002Fnode-exporter\n",[174,10859,10860,10863],{"class":176,"line":254},[174,10861,10862],{"class":2078},"unalias",[174,10864,10865],{"class":188}," c\n",[139,10867,1370],{"id":1370},[126,10869,10870,10871,10873],{},"เรื่องที่ผมได้จากรอบนี้ไม่ใช่แค่วิธีเปิด mTLS ครับ แต่เป็นการรู้ว่า ",[171,10872,9253],{}," มันเป็นไฟล์ที่ใช้ร่วมกันได้กับทุกตัวในตระกูล Prometheus ซึ่งแปลว่าถ้าเคยตั้งให้ตัวไหนไปแล้วตัวนึง ที่เหลือก็ก๊อปแล้วแก้ path เอาได้เลย ไม่ต้องไปเรียนรู้ใหม่",[126,10875,10876],{},"ส่วนใครที่ยังปล่อย node_exporter โล่งอยู่ ถ้าอยู่ในวงบ้านที่มีแต่เราคนเดียวก็อาจจะยังไม่ต้องรีบ แต่ถ้ามีเครื่องอื่นหรือคนอื่นอยู่ในวงด้วยก็ควรทำอะไรสักอย่างแล้วครับ",[126,10878,10879],{},"มีเรื่องนึงที่ต้องบอกไว้ด้วย ถ้าใส่แค่ basic auth โดยไม่เปิด TLS รหัสผ่านจะวิ่งไปแบบ base64 ซึ่งถอดกลับได้ทันที ใครดักอ่านในวงเดียวกันก็เห็นตั้งแต่ scrape รอบแรก มันพอกันคนที่บังเอิญเปิดเจอได้ก็จริง แต่ไม่ได้กันคนที่ตั้งใจดัก เพราะฉะนั้นถ้าจะใส่แค่ basic auth ก่อน อย่าเอารหัสที่ใช้ที่อื่นมาใช้ซ้ำนะครับ ตัวที่ปกป้องรหัสจริง ๆ คือ TLS",[139,10881,6440],{"id":6439},[707,10883,10884,10891,10898],{},[710,10885,10886],{},[292,10887,10890],{"href":10888,"rel":10889},"https:\u002F\u002Fgithub.com\u002Fprometheus\u002Fnode_exporter",[296],"node_exporter",[710,10892,10893],{},[292,10894,10897],{"href":10895,"rel":10896},"https:\u002F\u002Fgithub.com\u002Fprometheus\u002Fexporter-toolkit\u002Fblob\u002Fmaster\u002Fdocs\u002Fweb-configuration.md",[296],"exporter-toolkit — web configuration",[710,10899,10900],{},[292,10901,10904],{"href":10902,"rel":10903},"https:\u002F\u002Fprometheus.io\u002Fdocs\u002Fprometheus\u002Flatest\u002Fconfiguration\u002Fconfiguration\u002F#tls_config",[296],"Prometheus — tls_config",[909,10906,10907],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sicAX, html code.shiki .sicAX{--shiki-light:#90A4AE;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sJZfL, html code.shiki .sJZfL{--shiki-light:#6182B8;--shiki-default:#56B6C2;--shiki-dark:#79B8FF}html pre.shiki code .sDKbk, html code.shiki .sDKbk{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .s2KDN, html code.shiki .s2KDN{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#9ECBFF}html pre.shiki code .sOHk9, html code.shiki .sOHk9{--shiki-light:#9C3EDA;--shiki-default:#C678DD;--shiki-dark:#F97583}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}",{"title":169,"searchDepth":236,"depth":236,"links":10909},[10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,10920,10921,10922,10923],{"id":3207,"depth":236,"text":3208},{"id":9285,"depth":236,"text":9286},{"id":9453,"depth":236,"text":9454},{"id":9500,"depth":236,"text":9501},{"id":9813,"depth":236,"text":9814},{"id":9880,"depth":236,"text":9881},{"id":10049,"depth":236,"text":10049},{"id":10289,"depth":236,"text":10290},{"id":10582,"depth":236,"text":10583},{"id":10669,"depth":236,"text":10670},{"id":10758,"depth":236,"text":10758},{"id":9113,"depth":236,"text":9113},{"id":1370,"depth":236,"text":1370},{"id":6439,"depth":236,"text":6440},"วิธีเปิด Basic auth และ mTLS ให้ node_exporter ด้วย web-config.yml ไฟล์เดียวกับที่ Prometheus ใช้",{},"Secure node_exporter With mTLS",[9230,10928],"2026-08-03-grafana-alloy-loki.md",{"title":9240,"description":10924},{"loc":108,"images":10931,"lastmod":109},[10932,10933],{"loc":9484},{"loc":10057},"blogs\u002F2026-08-07-node-exporter-mtls-basic-auth",[945],"qwSBiDDiYh7YY5EGNCRdEeOz03btPDfY463cDyPdRJE",{"id":10938,"title":10939,"body":10940,"date":112,"description":11953,"draft":932,"extension":933,"meta":11954,"navigation":935,"next":936,"ogTitle":11955,"path":111,"pin":932,"prev":936,"recommends":11956,"seo":11957,"sitemap":11958,"stem":11961,"tags":11962,"updated":936,"__hash__":11963},"content\u002Fblogs\u002F2026-09-16-headroom.md","ลองใช้ Headroom บีบ context ก่อนส่งเข้า Claude Code",{"type":123,"value":10941,"toc":11935},[10942,10944,10947,10956,10959,10962,10966,10969,10976,10979,10982,10989,10992,10995,11006,11009,11036,11042,11045,11056,11062,11065,11080,11091,11094,11108,11115,11127,11133,11139,11161,11176,11179,11182,11194,11200,11205,11215,11222,11243,11386,11400,11403,11406,11412,11438,11521,11530,11533,11536,11539,11542,11548,11554,11560,11566,11572,11575,11578,11588,11591,11596,11602,11605,11615,11618,11622,11625,11628,11634,11637,11643,11649,11652,11655,11658,11664,11667,11670,11676,11685,11690,11693,11696,11709,11712,11716,11722,11731,11737,11744,11751,11768,11772,11775,11778,11781,11796,11798,11813,11819,11825,11829,11838,11841,11858,11861,11864,11867,11870,11872,11875,11878,11881,11884,11887,11890,11893,11901,11903,11932],[139,10943,3208],{"id":3207},[126,10945,10946],{},"ใครใช้ Claude Code หรือ Codex เป็นหลัก น่าจะเคยเจอว่า token ไหลเร็วกว่าที่คิด Agent อ่านไฟล์ ยิง grep ดึง log แล้วทั้งหมดก็เข้าไปอยู่ใน context รอบถัดไปก็ส่งต่อไปอีก",[126,10948,10949,10950,10955],{},"ช่วงนี้ผมเลยลอง ",[292,10951,10954],{"href":10952,"rel":10953},"https:\u002F\u002Fgithub.com\u002Fheadroomlabs-ai\u002Fheadroom",[296],"Headroom"," ซึ่งเป็น proxy ที่คั่นระหว่าง agent กับ provider แล้วช่วยลดขนาด context ก่อนส่งออก ตอนเขียนบทความนี้ repo มีดาวเจ็ดหมื่นกว่า ทั้งที่เพิ่งสร้างเมื่อเดือนมกราคมปีนี้",[126,10957,10958],{},"ตัวเลขในบทความนี้มาจากการใช้งานจริงหนึ่งวันบนเครื่องผมเอง ใช้ Headroom v0.37.0 คู่กับ Claude Code ส่วน output ที่แปะไว้ก็ก๊อปมาจาก terminal โดยตรง มีตัดบางบรรทัดที่ไม่เกี่ยวออกให้อ่านง่ายขึ้น แต่ไม่ได้แก้ตัวเลข",[126,10960,10961],{},"ผลที่ได้ต่างจากที่ผมคิดไว้ตอนแรกพอสมควร",[139,10963,10965],{"id":10964},"headroom-คืออะไร","Headroom คืออะไร",[126,10967,10968],{},"ถ้าอธิบายแบบสั้น ๆ Headroom คือชั้นที่ช่วยลดขนาด context โดยรันอยู่บนเครื่องเราเอง ข้อมูลที่ผ่านมันมีทั้ง tool output, log, ไฟล์, RAG chunk และประวัติแชท",[126,10970,10971,10972,10975],{},"ข้างในมีตัวจัดการหลายแบบตามชนิดข้อมูล เช่น SmartCrusher สำหรับ JSON ก้อนใหญ่, CodeCompressor สำหรับโค้ดที่อ่าน AST ได้ 11 ภาษา ได้แก่ Python, JS\u002FTS, Go, Rust, Java, C\u002FC++, C#, PHP และ Perl ส่วนข้อความทั่วไปใช้โมเดลชื่อ ",[171,10973,10974],{},"kompress-v2-base"," โดยมี ContentRouter คอยเลือกว่าจะส่งข้อมูลไปให้ตัวไหนจัดการ",[126,10977,10978],{},"CodeCompressor มีเงื่อนไขค่อนข้างเข้ม เอกสารระบุไว้ตรง ๆ ว่าแทบไม่ทำงานในสถานการณ์จริง เพราะมันจะไม่แตะโค้ดที่เพิ่งคุยกันหรือกำลังวิเคราะห์อยู่ เพื่อลดโอกาสที่ข้อมูลสำคัญจะถูกบีบจนเพี้ยน",[126,10980,10981],{},"จากที่ผมใช้ทั้งวัน มันทำงานแค่ 3 ครั้ง",[126,10983,10984,10985,10988],{},"อีกอย่างที่ผมชอบคือข้อมูลเดิมย้อนกลับได้ ของต้นฉบับถูก cache ไว้ในเครื่อง และโมเดลสามารถเรียก ",[171,10986,10987],{},"headroom_retrieve"," เพื่อขอข้อมูลเต็มกลับมาได้ ถ้าข้อมูลที่ถูกบีบไม่พอใช้งาน",[126,10990,10991],{},"Headroom ใช้ได้ 4 แบบ คือเรียกเป็น library, รันเป็น proxy, ใช้ wrap agent หรือเสียบเป็น MCP server ผมเลือกแบบ wrap เพราะตั้งค่าง่ายสุด",[139,10993,10994],{"id":10994},"วิธีติดตั้ง",[126,10996,10997,10998,11001,11002,11005],{},"CLI มีเฉพาะบน PyPI ส่วน ",[171,10999,11000],{},"headroom-ai"," บน npm เป็น TypeScript SDK ไม่มีคำสั่ง ",[171,11003,11004],{},"headroom"," ให้ใช้",[126,11007,11008],{},"ต้องใช้ Python 3.10 ขึ้นไป",[164,11010,11012],{"className":3233,"code":11011,"language":2675,"meta":169,"style":169},"uv tool install --python 3.13 \"headroom-ai[all]\"\n",[171,11013,11014],{"__ignoreMap":169},[174,11015,11016,11018,11021,11023,11026,11029,11031,11034],{"class":176,"line":177},[174,11017,7345],{"class":180},[174,11019,11020],{"class":188}," tool",[174,11022,1605],{"class":188},[174,11024,11025],{"class":184}," --python",[174,11027,11028],{"class":1982}," 3.13",[174,11030,2272],{"class":372},[174,11032,11033],{"class":188},"headroom-ai[all]",[174,11035,2278],{"class":372},[126,11037,11038,11039],{},"ผมแนะนำให้ล็อก Python เป็น 3.13 ไปเลย เพราะตัวคำนวณค่าใช้จ่ายของ Headroom ใช้ LiteLLM ซึ่งยังลงบน Python 3.14 ไม่ได้ ถ้าใช้ 3.14 จำนวน token ยังนับได้ตามปกติ แต่ตัวเลขเงินใน dashboard จะค้างที่ ",[171,11040,11041],{},"$0.00",[126,11043,11044],{},"เช็กเวอร์ชันก่อน",[164,11046,11048],{"className":3233,"code":11047,"language":2675,"meta":169,"style":169},"headroom --version\n",[171,11049,11050],{"__ignoreMap":169},[174,11051,11052,11054],{"class":176,"line":177},[174,11053,11004],{"class":180},[174,11055,2442],{"class":184},[164,11057,11060],{"className":11058,"code":11059,"language":529,"meta":169},[527],"headroom, version 0.37.0\n",[171,11061,11059],{"__ignoreMap":169},[126,11063,11064],{},"จากนั้นสั่ง wrap Claude Code ได้เลย",[164,11066,11068],{"className":3233,"code":11067,"language":2675,"meta":169,"style":169},"headroom wrap claude\n",[171,11069,11070],{"__ignoreMap":169},[174,11071,11072,11074,11077],{"class":176,"line":177},[174,11073,11004],{"class":180},[174,11075,11076],{"class":188}," wrap",[174,11078,11079],{"class":188}," claude\n",[126,11081,11082,11083,11086,11087,11090],{},"คำสั่งนี้จะเปิด proxy ที่ port 8787 แล้วรัน Claude Code โดยตั้ง ",[171,11084,11085],{},"ANTHROPIC_BASE_URL"," ให้ชี้เข้าหา proxy พร้อมตั้ง ",[171,11088,11089],{},"ENABLE_TOOL_SEARCH"," ให้ด้วย",[126,11092,11093],{},"ถ้าต้องการถอนก็ใช้",[164,11095,11097],{"className":3233,"code":11096,"language":2675,"meta":169,"style":169},"headroom unwrap claude\n",[171,11098,11099],{"__ignoreMap":169},[174,11100,11101,11103,11106],{"class":176,"line":177},[174,11102,11004],{"class":180},[174,11104,11105],{"class":188}," unwrap",[174,11107,11079],{"class":188},[126,11109,11110,11111,11114],{},"ก่อนเริ่มใช้จริงควรรัน ",[171,11112,11113],{},"doctor"," สักรอบ",[164,11116,11118],{"className":3233,"code":11117,"language":2675,"meta":169,"style":169},"headroom doctor\n",[171,11119,11120],{"__ignoreMap":169},[174,11121,11122,11124],{"class":176,"line":177},[174,11123,11004],{"class":180},[174,11125,11126],{"class":188}," doctor\n",[164,11128,11131],{"className":11129,"code":11130,"language":529,"meta":169},[527],"Headroom Doctor v0.37.0 · port 8787\n\n┃ check       ┃ status ┃ summary                                     ┃\n│ proxy       │ ✓ pass │ running at http:\u002F\u002F127.0.0.1:8787 (up 3m)    │\n│ version     │ ✓ pass │ proxy matches installed v0.37.0             │\n│ claude      │ ✓ pass │ routed via ...                              │\n│ wrap_marker │ ✓ pass │ live wrap session (pid 84723)               │\n│ shell env   │ ✓ pass │ routed via ANTHROPIC_BASE_URL               │\n│ budget      │ ⚠ warn │ no budget configured — spend is unlimited   │\n",[171,11132,11130],{"__ignoreMap":169},[126,11134,2526,11135,11138],{},[171,11136,11137],{},"budget"," ขึ้นเตือนแบบนี้ เราสามารถตั้งเพดานรายวันผ่าน environment variable ได้",[164,11140,11142],{"className":3233,"code":11141,"language":2675,"meta":169,"style":169},"HEADROOM_BUDGET=10 headroom wrap claude\n",[171,11143,11144],{"__ignoreMap":169},[174,11145,11146,11149,11151,11154,11157,11159],{"class":176,"line":177},[174,11147,11148],{"class":2094},"HEADROOM_BUDGET",[174,11150,4326],{"class":1539},[174,11152,11153],{"class":188},"10",[174,11155,11156],{"class":180}," headroom",[174,11158,11076],{"class":188},[174,11160,11079],{"class":188},[126,11162,11163,11164,11167,11168,11171,11172,11175],{},"ส่วน ",[171,11165,11166],{},"--budget"," ใช้กับคำสั่ง ",[171,11169,11170],{},"headroom proxy"," ถ้ารัน proxy เอง อย่าเปิดซ้อนกับตัวที่ ",[171,11173,11174],{},"wrap"," เปิดไว้ เพราะจะชนกันที่ port 8787",[139,11177,11178],{"id":11178},"ตัวเลขหลังใช้หนึ่งวัน",[126,11180,11181],{},"ดูแบบเร็ว ๆ ได้จาก",[164,11183,11185],{"className":3233,"code":11184,"language":2675,"meta":169,"style":169},"headroom dashboard\n",[171,11186,11187],{"__ignoreMap":169},[174,11188,11189,11191],{"class":176,"line":177},[174,11190,11004],{"class":180},[174,11192,11193],{"class":188}," dashboard\n",[126,11195,11196,11197],{},"ซึ่งจะเปิด dashboard ที่ ",[171,11198,11199],{},"127.0.0.1:8787\u002Fdashboard",[126,11201,11202],{},[3766,11203],{"alt":169,"src":11204},"\u002Fimages\u002F2026-09-16-headroom\u002Fdashboard.png",[126,11206,11207,11208,11211,11212],{},"ภาพนี้ผมถ่ายทีหลัง ตัวเลขเลยขยับจากค่าที่จะยกมาด้านล่างเล็กน้อย แต่สังเกตช่อง ",[171,11209,11210],{},"SAVINGS · TOOL SEARCH"," ไว้ เพราะส่วนนี้แยกจาก ",[171,11213,11214],{},"TOKENS SAVED",[126,11216,11217,11218,11221],{},"ถ้าอยากดูตัวเลขดิบ ดึงจาก ",[171,11219,11220],{},"\u002Fstats"," ได้ตรง ๆ",[164,11223,11225],{"className":3233,"code":11224,"language":2675,"meta":169,"style":169},"curl -s 127.0.0.1:8787\u002Fstats | jq .summary.compression\n",[171,11226,11227],{"__ignoreMap":169},[174,11228,11229,11231,11233,11236,11238,11240],{"class":176,"line":177},[174,11230,2380],{"class":180},[174,11232,7608],{"class":184},[174,11234,11235],{"class":188}," 127.0.0.1:8787\u002Fstats",[174,11237,8529],{"class":2046},[174,11239,8532],{"class":180},[174,11241,11242],{"class":188}," .summary.compression\n",[164,11244,11246],{"className":446,"code":11245,"language":448,"meta":169,"style":169},"{\n  \"requests_compressed\": 129,\n  \"avg_compression_pct\": 1.7,\n  \"best_compression_pct\": 11.8,\n  \"best_detail\": \"15,316 → 13,505 tokens\",\n  \"total_tokens_removed\": 130497,\n  \"total_tokens_before\": 10992312,\n  \"tool_schema_tokens_saved\": 484226,\n  \"total_tokens_saved_all_layers\": 614723\n}\n",[171,11247,11248,11252,11268,11284,11300,11320,11336,11352,11368,11382],{"__ignoreMap":169},[174,11249,11250],{"class":176,"line":177},[174,11251,456],{"class":455},[174,11253,11254,11256,11259,11261,11263,11266],{"class":176,"line":236},[174,11255,462],{"class":461},[174,11257,11258],{"class":465},"requests_compressed",[174,11260,468],{"class":461},[174,11262,471],{"class":455},[174,11264,11265],{"class":1982}," 129",[174,11267,4833],{"class":455},[174,11269,11270,11272,11275,11277,11279,11282],{"class":176,"line":242},[174,11271,462],{"class":461},[174,11273,11274],{"class":465},"avg_compression_pct",[174,11276,468],{"class":461},[174,11278,471],{"class":455},[174,11280,11281],{"class":1982}," 1.7",[174,11283,4833],{"class":455},[174,11285,11286,11288,11291,11293,11295,11298],{"class":176,"line":248},[174,11287,462],{"class":461},[174,11289,11290],{"class":465},"best_compression_pct",[174,11292,468],{"class":461},[174,11294,471],{"class":455},[174,11296,11297],{"class":1982}," 11.8",[174,11299,4833],{"class":455},[174,11301,11302,11304,11307,11309,11311,11313,11316,11318],{"class":176,"line":254},[174,11303,462],{"class":461},[174,11305,11306],{"class":465},"best_detail",[174,11308,468],{"class":461},[174,11310,471],{"class":455},[174,11312,2272],{"class":372},[174,11314,11315],{"class":188},"15,316 → 13,505 tokens",[174,11317,468],{"class":372},[174,11319,4833],{"class":455},[174,11321,11322,11324,11327,11329,11331,11334],{"class":176,"line":2112},[174,11323,462],{"class":461},[174,11325,11326],{"class":465},"total_tokens_removed",[174,11328,468],{"class":461},[174,11330,471],{"class":455},[174,11332,11333],{"class":1982}," 130497",[174,11335,4833],{"class":455},[174,11337,11338,11340,11343,11345,11347,11350],{"class":176,"line":2129},[174,11339,462],{"class":461},[174,11341,11342],{"class":465},"total_tokens_before",[174,11344,468],{"class":461},[174,11346,471],{"class":455},[174,11348,11349],{"class":1982}," 10992312",[174,11351,4833],{"class":455},[174,11353,11354,11356,11359,11361,11363,11366],{"class":176,"line":2135},[174,11355,462],{"class":461},[174,11357,11358],{"class":465},"tool_schema_tokens_saved",[174,11360,468],{"class":461},[174,11362,471],{"class":455},[174,11364,11365],{"class":1982}," 484226",[174,11367,4833],{"class":455},[174,11369,11370,11372,11375,11377,11379],{"class":176,"line":3364},[174,11371,462],{"class":461},[174,11373,11374],{"class":465},"total_tokens_saved_all_layers",[174,11376,468],{"class":461},[174,11378,471],{"class":455},[174,11380,11381],{"class":1982}," 614723\n",[174,11383,11384],{"class":176,"line":3369},[174,11385,480],{"class":455},[126,11387,11388,11389,11392,11393,11395,11396,11399],{},"ตัวเลขที่น่าสนใจคือ compression ลดไป ",[171,11390,11391],{},"130,497"," token แต่ ",[171,11394,11358],{}," ลดไปถึง ",[171,11397,11398],{},"484,226"," token",[126,11401,11402],{},"สองอย่างนี้เป็นคนละกลไกกัน ตัวหลังมาจากการไม่ส่ง schema ของ tool ทั้งหมดไปหาโมเดลทุก request แล้วโหลดเฉพาะตัวที่ต้องใช้",[126,11404,11405],{},"ในงานของผม เกือบ 80% ของ token ที่ประหยัดได้มาจาก tool search มากกว่า compression",[126,11407,11408,11409,11411],{},"น่าเสียดายที่ ",[171,11410,11220],{}," ยังไม่ตีมูลค่าส่วนนี้เป็นเงิน",[164,11413,11415],{"className":3233,"code":11414,"language":2675,"meta":169,"style":169},"curl -s 127.0.0.1:8787\u002Fstats | jq -c '.savings.by_source'\n",[171,11416,11417],{"__ignoreMap":169},[174,11418,11419,11421,11423,11425,11427,11429,11431,11433,11436],{"class":176,"line":177},[174,11420,2380],{"class":180},[174,11422,7608],{"class":184},[174,11424,11235],{"class":188},[174,11426,8529],{"class":2046},[174,11428,8532],{"class":180},[174,11430,9415],{"class":184},[174,11432,373],{"class":372},[174,11434,11435],{"class":188},".savings.by_source",[174,11437,379],{"class":372},[164,11439,11441],{"className":446,"code":11440,"language":448,"meta":169,"style":169},"[{ \"source\": \"tool_search\", \"realized\": true, \"events\": 79, \"tokens\": 484226, \"usd\": 0.0 }]\n",[171,11442,11443],{"__ignoreMap":169},[174,11444,11445,11448,11450,11452,11454,11456,11458,11461,11463,11465,11467,11470,11472,11474,11477,11479,11481,11484,11486,11488,11491,11493,11495,11498,11500,11502,11504,11506,11508,11511,11513,11515,11518],{"class":176,"line":177},[174,11446,11447],{"class":455},"[{",[174,11449,2272],{"class":461},[174,11451,8903],{"class":465},[174,11453,468],{"class":461},[174,11455,471],{"class":455},[174,11457,2272],{"class":372},[174,11459,11460],{"class":188},"tool_search",[174,11462,468],{"class":372},[174,11464,4889],{"class":455},[174,11466,2272],{"class":461},[174,11468,11469],{"class":465},"realized",[174,11471,468],{"class":461},[174,11473,471],{"class":455},[174,11475,11476],{"class":474}," true",[174,11478,4889],{"class":455},[174,11480,2272],{"class":461},[174,11482,11483],{"class":465},"events",[174,11485,468],{"class":461},[174,11487,471],{"class":455},[174,11489,11490],{"class":1982}," 79",[174,11492,4889],{"class":455},[174,11494,2272],{"class":461},[174,11496,11497],{"class":465},"tokens",[174,11499,468],{"class":461},[174,11501,471],{"class":455},[174,11503,11365],{"class":1982},[174,11505,4889],{"class":455},[174,11507,2272],{"class":461},[174,11509,11510],{"class":465},"usd",[174,11512,468],{"class":461},[174,11514,471],{"class":455},[174,11516,11517],{"class":1982}," 0.0",[174,11519,11520],{"class":455}," }]\n",[126,11522,11523,11524,11526,11527],{},"ประหยัดไปกว่า 480,000 token แต่ ",[171,11525,11510],{}," ยังเป็น ",[171,11528,11529],{},"0.0",[126,11531,11532],{},"ถ้าดูเฉพาะตัวเลขเงินบน dashboard จึงอาจทำให้เข้าใจว่าประหยัดได้น้อยกว่าความเป็นจริง เพราะมันนับเงินจากฝั่ง compression แต่ไม่ได้รวม token ที่ลดลงจาก tool schema",[126,11534,11535],{},"แล้วทำไม compression ของผมถึงต่ำ?",[126,11537,11538],{},"README อธิบายไว้ค่อนข้างตรง ถ้า input เป็นข้อความล้วนหรือข้อมูลค่อนข้างแน่นอยู่แล้ว มันจะบีบได้ไม่มาก ส่วน benchmark 21–57% ที่เขาโชว์เป็นงานอย่าง code search, incident investigation, สำรวจ codebase หรือ triage issue ซึ่งมี tool output ก้อนใหญ่ให้ลดได้เยอะกว่า",[126,11540,11541],{},"วันที่ผมทดสอบ ผมนั่งเขียน Markdown ภาษาไทยเป็นหลัก เลยแทบไม่มีข้อมูลแบบนั้น",[126,11543,11544,11545,11547],{},"อีกอย่างคือ ",[171,11546,11274],{}," ที่ขึ้น 1.7% เป็นค่าเฉลี่ยต่อ request ถ้าเอา token ที่ลดได้ทั้งหมดหารด้วย token ก่อนบีบทั้งหมด จะได้ประมาณ 1.2%",[126,11549,11163,11550,11553],{},[171,11551,11552],{},"cache_savings_usd"," ใน dashboard ขึ้นตัวเลขค่อนข้างสูง แต่ตรงนี้ไม่ใช่เงินที่ Headroom ประหยัดให้ทั้งหมด",[126,11555,11556,11557,11559],{},"ใน ",[171,11558,11220],{}," มีคำอธิบายว่า",[164,11561,11564],{"className":11562,"code":11563,"language":529,"meta":169},[527],"Cost discount from provider prefix caching. Headroom's CacheAligner improves\nhit rates; baseline caching is provider-native.\n",[171,11565,11563],{"__ignoreMap":169},[126,11567,11568,11571],{},[171,11569,11570],{},"baseline caching is provider-native"," หมายความว่า prompt cache เป็นความสามารถของ Anthropic API ที่ Claude Code ใช้อยู่แล้ว",[126,11573,11574],{},"สิ่งที่ Headroom ทำคือพยายามไม่ทำให้ cache เดิมเสีย และช่วยจัดส่วนที่เพิ่มเข้ามาใหม่ให้เข้ากับ cache มากขึ้น",[139,11576,11577],{"id":11577},"หลังใช้จริงแล้วชอบอะไรบ้าง",[126,11579,11580,11581,11584,11585],{},"ติดตั้งง่าย ใช้ ",[171,11582,11583],{},"headroom wrap claude"," ครั้งเดียวแล้วทำงานต่อได้เลย ถ้าจะถอนก็มี ",[171,11586,11587],{},"unwrap",[126,11589,11590],{},"ส่วนที่เห็นผลชัดที่สุดในงานของผมคือ tool schema ลดไปกว่า 400,000 token ในวันเดียว แม้ dashboard จะยังไม่แสดงเป็นมูลค่าเงินก็ตาม",[126,11592,11593,11594],{},"ข้อมูลที่ถูกบีบยังเรียกกลับมาได้ผ่าน ",[171,11595,10987],{},[126,11597,11598,11599,11601],{},"เรื่อง latency ก็ไม่ได้รู้สึกชัด จาก ",[171,11600,11220],{}," ของผม overhead เฉลี่ยอยู่ราว 100 ms ต่อ request ขณะที่เวลารอโมเดลตอบอยู่ในหลักสิบวินาที",[126,11603,11604],{},"README ระบุ overhead ไว้ที่ 0.21 ms แต่ตัวเลขนั้นเป็น path ของ JSON ส่วนข้อความธรรมดาจะวิ่งเข้าโมเดล ML ซึ่งช้ากว่า จากที่ผมเจอ request ที่หนักที่สุดใช้เวลาประมาณ 4 วินาที",[126,11606,11607,11608,843,11610,847,11613],{},"เครื่องมือสำหรับดูสถานะก็มีค่อนข้างครบ ทั้ง ",[171,11609,11113],{},[171,11611,11612],{},"dashboard",[171,11614,11220],{},[139,11616,11617],{"id":11617},"จุดที่ผมติดตอนใช้งาน",[153,11619,11621],{"id":11620},"tool-output-อาจถูกบีบจนข้อมูลหาย","Tool output อาจถูกบีบจนข้อมูลหาย",[126,11623,11624],{},"อันนี้เป็นเรื่องที่ผมกังวลที่สุด",[126,11626,11627],{},"ตอนเขียนบทความนี้ ผมให้ agent ใช้ grep หาคำใน README บน terminal ผมเห็น output ครบตามปกติ แต่ข้อมูลที่ส่งไปถึงโมเดลเหลือแค่นี้",[164,11629,11632],{"className":11630,"code":11631,"language":529,"meta":169},[527],"328:you\n330:preserved. vscode-claude`\n",[171,11633,11631],{"__ignoreMap":169},[126,11635,11636],{},"Agent เกือบสรุปว่าไม่เจอข้อมูลที่ต้องการ",[126,11638,11639,11640,11642],{},"พอเรียก ",[171,11641,10987],{}," เอาของเต็มกลับมา กลายเป็น",[164,11644,11647],{"className":11645,"code":11646,"language":529,"meta":169},[527],"328:you use the Claude Code panel; the dashboard or proxy log printed at startup\n330:preserved. `Ctrl+C` stops the proxy; `headroom unwrap vscode-claude` restores the\n",[171,11648,11646],{"__ignoreMap":169},[126,11650,11651],{},"ข้อความถูกตัดกลางประโยค",[126,11653,11654],{},"ปัญหาคือคนที่นั่งดู terminal ไม่เห็นความผิดปกติ เพราะ output ฝั่งเรายังครบ คนที่เห็นข้อมูลไม่ครบคือโมเดล",[126,11656,11657],{},"สัญญาณหนึ่งที่ช่วยบอกได้คือข้อความท้าย output",[164,11659,11662],{"className":11660,"code":11661,"language":529,"meta":169},[527],"[276 words compressed to 174 (from 6 source lines). Retrieve more: hash=24aa7b12]\n",[171,11663,11661],{"__ignoreMap":169},[126,11665,11666],{},"ของต้นฉบับไม่ได้หาย สามารถเรียกคืนได้ แต่ agent ต้องรู้ก่อนว่าข้อมูลที่ได้รับไม่ครบ",[126,11668,11669],{},"ถ้าเป็นงานที่ทุกบรรทัดมีผลต่อการตัดสินใจ เช่นวิเคราะห์ log หรือ audit เรื่อง security ผมคิดว่าควรระวังตรงนี้เป็นพิเศษ",[153,11671,11673,11675],{"id":11672},"wrap-จะติดตั้ง-serena-ให้ด้วย",[171,11674,11174],{}," จะติดตั้ง Serena ให้ด้วย",[126,11677,11678,11679,11681,11682],{},"README ระบุว่าเมื่อใช้ ",[171,11680,11174],{}," Headroom จะติดตั้ง Serena ซึ่งเป็นเครื่องมือช่วย navigate code แบบเข้าใจ symbol แล้วลงทะเบียนไว้ที่ user scope ใน ",[171,11683,11684],{},"~\u002F.claude.json",[126,11686,11687,11688],{},"นั่นหมายความว่าโปรเจกต์อื่นก็จะเห็น Serena ตัวนี้จนกว่าจะ ",[171,11689,11587],{},[126,11691,11692],{},"ถ้ามี Serena อยู่ก่อนแล้ว config เดิมยังอยู่ จากที่ผมตรวจของตัวเองไม่ได้ถูกเขียนทับ",[126,11694,11695],{},"ถ้าไม่ต้องการใช้ Serena สามารถสั่ง",[164,11697,11699],{"className":3233,"code":11698,"language":2675,"meta":169,"style":169},"--code-memory none\n",[171,11700,11701],{"__ignoreMap":169},[174,11702,11703,11706],{"class":176,"line":177},[174,11704,11705],{"class":180},"--code-memory",[174,11707,11708],{"class":188}," none\n",[126,11710,11711],{},"ตอน wrap ได้",[153,11713,11715],{"id":11714},"มีการแก้-config-และสร้างไฟล์ในโปรเจกต์","มีการแก้ config และสร้างไฟล์ในโปรเจกต์",[126,11717,11718,11719,11721],{},"ถึงเราจะไม่ต้องแก้ config เอง แต่ ",[171,11720,11174],{}," มีการแก้หลายอย่างให้เบื้องหลัง",[126,11723,11724,11725,11727,11728,11730],{},"ของผมมันเพิ่ม MCP server ชื่อ ",[171,11726,11004],{}," เข้าไปใน ",[171,11729,11684],{}," ที่ user scope และสร้างไฟล์ในโปรเจกต์ เช่น",[164,11732,11735],{"className":11733,"code":11734,"language":529,"meta":169},[527],".claude\u002F.headroom_wrap_marker.json\n.headroom_wrap_owners.json\n.headroom\u002F\n",[171,11736,11734],{"__ignoreMap":169},[126,11738,11739,11740,11743],{},"ไฟล์พวกนี้โผล่ใน ",[171,11741,11742],{},"git status"," เป็น untracked",[126,11745,11746,11747,11750],{},"ควรเพิ่มลง ",[171,11748,11749],{},".gitignore"," ไว้ก่อน",[164,11752,11756],{"className":11753,"code":11754,"language":11755,"meta":169,"style":169},"language-gitignore shiki shiki-themes material-theme-lighter one-dark-pro github-dark",".headroom\u002F\n.claude\u002F.headroom_wrap_*\n","gitignore",[171,11757,11758,11763],{"__ignoreMap":169},[174,11759,11760],{"class":176,"line":177},[174,11761,11762],{},".headroom\u002F\n",[174,11764,11765],{"class":176,"line":236},[174,11766,11767],{},".claude\u002F.headroom_wrap_*\n",[153,11769,11771],{"id":11770},"telemetry-เปิดเป็นค่าเริ่มต้น","Telemetry เปิดเป็นค่าเริ่มต้น",[126,11773,11774],{},"ค่า default ของ telemetry คือเปิด",[126,11776,11777],{},"เอกสารระบุว่าส่งข้อมูลอย่างอัตราการบีบ ชื่อ provider\u002Fmodel, OS และสถาปัตยกรรม โดยไม่ส่ง prompt, code หรือ path",[126,11779,11780],{},"ถ้าไม่ต้องการส่ง ปิดได้ด้วย",[164,11782,11784],{"className":3233,"code":11783,"language":2675,"meta":169,"style":169},"HEADROOM_BEACON=off\n",[171,11785,11786],{"__ignoreMap":169},[174,11787,11788,11791,11793],{"class":176,"line":177},[174,11789,11790],{"class":2094},"HEADROOM_BEACON",[174,11792,4326],{"class":1539},[174,11794,11795],{"class":188},"off\n",[126,11797,6810],{},[164,11799,11801],{"className":3233,"code":11800,"language":2675,"meta":169,"style":169},"DO_NOT_TRACK=1\n",[171,11802,11803],{"__ignoreMap":169},[174,11804,11805,11808,11810],{"class":176,"line":177},[174,11806,11807],{"class":2094},"DO_NOT_TRACK",[174,11809,4326],{"class":1539},[174,11811,11812],{"class":188},"1\n",[126,11814,11815,11816],{},"หรือใช้ ",[171,11817,11818],{},"--offline",[126,11820,11821,11822,11824],{},"เครื่องผมตั้ง ",[171,11823,11807],{}," ไว้อยู่แล้ว เลยไม่ได้ส่งออกตั้งแต่แรก",[153,11826,11828],{"id":11827},"ฟีเจอร์บางอย่างของ-claude-code-ใช้ไม่ได้","ฟีเจอร์บางอย่างของ Claude Code ใช้ไม่ได้",[126,11830,11831,11832,11834,11835],{},"เมื่อ ",[171,11833,11085],{}," ชี้ไปที่ proxy Claude Code จะปิด ",[171,11836,11837],{},"\u002Fremote-control",[126,11839,11840],{},"ส่วน context 1M token ต้องสั่งเองด้วย",[164,11842,11844],{"className":3233,"code":11843,"language":2675,"meta":169,"style":169},"headroom wrap claude --1m\n",[171,11845,11846],{"__ignoreMap":169},[174,11847,11848,11850,11852,11855],{"class":176,"line":177},[174,11849,11004],{"class":180},[174,11851,11076],{"class":188},[174,11853,11854],{"class":188}," claude",[174,11856,11857],{"class":184}," --1m\n",[126,11859,11860],{},"Claude Desktop ยังไม่รองรับ เพราะตัวแอปจะเขียนทับ base URL",[153,11862,11863],{"id":11863},"ออกเวอร์ชันถี่มาก",[126,11865,11866],{},"ตอนที่ผมเช็ก มี 198 เวอร์ชันบน PyPI ในเวลาประมาณ 7 เดือนครึ่ง",[126,11868,11869],{},"ข้อดีคือแก้บั๊กเร็ว แต่ก็หมายความว่า behavior และรายละเอียดต่าง ๆ เปลี่ยนค่อนข้างไว",[139,11871,1370],{"id":1370},[126,11873,11874],{},"ก่อนลอง ผมคิดว่าเหตุผลหลักของการใช้ Headroom คือ compression",[126,11876,11877],{},"หลังใช้หนึ่งวัน กลับกลายเป็นว่าฝั่ง compression ลด token ในงานของผมได้ไม่มาก แต่ tool search ช่วยลดไปกว่า 400K token",[126,11879,11880],{},"เรื่องที่ทำให้ผมลังเลมากกว่าตัวเลขการประหยัดคือ tool output ที่อาจถูกบีบจนข้อมูลไม่ครบ",[126,11882,11883],{},"ข้อมูลต้นฉบับยังเรียกกลับมาได้ แต่ agent ต้องรู้ก่อนว่ามีข้อมูลบางส่วนหายไป ซึ่งเป็นจุดที่ต้องระวัง เพราะคนที่นั่งดู terminal ยังเห็น output เต็มตามปกติ",[126,11885,11886],{},"ถ้างานเป็น API response ใหญ่ ๆ, JSON, code search หรือ log ยาว ๆ Headroom น่าจะมีของให้บีบเยอะกว่างานที่ผมทดสอบ",[126,11888,11889],{},"ส่วนงานเขียนหรือแก้ไฟล์ทีละไฟล์แบบที่ผมทำวันนั้น compression ช่วยค่อนข้างน้อย",[126,11891,11892],{},"ตอนนี้ผมยังเปิดใช้อยู่ เพราะอยากเก็บตัวเลขเพิ่มอีกหน่อย แต่ถ้าเป็นงานที่ข้อมูลทุกบรรทัดสำคัญ ผมคงไม่เชื่อ output ที่ถูกบีบโดยไม่ตรวจซ้ำ",[126,11894,11895,11896,11898,11899,11750],{},"ถ้าจะลองใช้ แนะนำให้ดูด้วยว่า ",[171,11897,11174],{}," แก้อะไรบนเครื่องบ้าง และเพิ่มไฟล์ที่ Headroom สร้างลง ",[171,11900,11749],{},[139,11902,6440],{"id":6439},[707,11904,11905,11911,11918,11925],{},[710,11906,11907],{},[292,11908,11910],{"href":10952,"rel":11909},[296],"Headroom บน GitHub",[710,11912,11913],{},[292,11914,11917],{"href":11915,"rel":11916},"https:\u002F\u002Fdocs.headroomlabs.ai\u002F",[296],"เอกสารของ Headroom",[710,11919,11920],{},[292,11921,11924],{"href":11922,"rel":11923},"https:\u002F\u002Fpypi.org\u002Fproject\u002Fheadroom-ai\u002F",[296],"headroom-ai บน PyPI",[710,11926,11927],{},[292,11928,11931],{"href":11929,"rel":11930},"https:\u002F\u002Fgithub.com\u002Foraios\u002Fserena",[296],"Serena ตัวที่ Headroom ลงให้",[909,11933,11934],{},"html pre.shiki code .sosa_, html code.shiki .sosa_{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#B392F0}html pre.shiki code .sAlJX, html code.shiki .sAlJX{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html pre.shiki code .sEoV_, html code.shiki .sEoV_{--shiki-light:#91B859;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snOyU, html code.shiki .snOyU{--shiki-light:#F76D47;--shiki-default:#D19A66;--shiki-dark:#79B8FF}html pre.shiki code .snfNA, html code.shiki .snfNA{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sLHrO, html code.shiki .sLHrO{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#E1E4E8}html pre.shiki code .sMTEB, html code.shiki .sMTEB{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F97583}html pre.shiki code .sbGrh, html code.shiki .sbGrh{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F97583}html pre.shiki code .stlKB, html code.shiki .stlKB{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#E1E4E8}html pre.shiki code .sObbn, html code.shiki .sObbn{--shiki-light:#39ADB5;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .sVeMc, html code.shiki .sVeMc{--shiki-light:#9C3EDA;--shiki-default:#E06C75;--shiki-dark:#79B8FF}html pre.shiki code .scCEF, html code.shiki .scCEF{--shiki-light:#39ADB5;--shiki-default:#D19A66;--shiki-dark:#79B8FF}",{"title":169,"searchDepth":236,"depth":236,"links":11936},[11937,11938,11939,11940,11941,11942,11951,11952],{"id":3207,"depth":236,"text":3208},{"id":10964,"depth":236,"text":10965},{"id":10994,"depth":236,"text":10994},{"id":11178,"depth":236,"text":11178},{"id":11577,"depth":236,"text":11577},{"id":11617,"depth":236,"text":11617,"children":11943},[11944,11945,11947,11948,11949,11950],{"id":11620,"depth":242,"text":11621},{"id":11672,"depth":242,"text":11946},"wrap จะติดตั้ง Serena ให้ด้วย",{"id":11714,"depth":242,"text":11715},{"id":11770,"depth":242,"text":11771},{"id":11827,"depth":242,"text":11828},{"id":11863,"depth":242,"text":11863},{"id":1370,"depth":236,"text":1370},{"id":6439,"depth":236,"text":6440},"รีวิว Headroom ตัวบีบ context ก่อนส่งถึง LLM ตั้งแต่วิธีติดตั้ง ตัวเลขจริงที่วัดได้จากเครื่องตัวเอง ไปจนถึงข้อดีข้อเสียและเรื่องที่ควรรู้ก่อนเอาไปใช้จริง",{},"Headroom Context Compression Review",[6016],{"title":10939,"description":11953},{"loc":111,"images":11959,"lastmod":112},[11960],{"loc":11204},"blogs\u002F2026-09-16-headroom",[944],"sjapOo5ZLEu5A9y0QG6hSkEm_0j3nlpON6kGzYyUSNM",{"id":949,"title":950,"body":11965,"date":115,"description":1397,"draft":932,"extension":933,"meta":12275,"navigation":935,"next":936,"ogTitle":950,"path":114,"pin":932,"prev":936,"recommends":12276,"seo":12277,"sitemap":12278,"stem":1404,"tags":12279,"updated":1406,"__hash__":1407},{"type":123,"value":11966,"toc":12264},[11967,11969,11971,11978,11980,11982,11984,12000,12002,12012,12014,12016,12018,12022,12024,12028,12030,12032,12036,12038,12042,12044,12046,12048,12053,12055,12075,12084,12086,12088,12090,12094,12098,12100,12102,12106,12110,12114,12116,12118,12122,12124,12126,12128,12130,12146,12148,12166,12168,12170,12172,12176,12178,12182,12184,12186,12188,12190,12192,12196,12198,12200,12202,12204,12206,12222,12224,12226,12228,12230,12232,12234,12238,12242,12246,12250,12252,12254,12256,12258,12260,12262],[126,11968,955],{},[126,11970,958],{},[126,11972,961,11973,969],{},[292,11974,11976],{"href":964,"rel":11975},[296],[171,11977,968],{},[139,11979,973],{"id":972},[126,11981,976],{},[126,11983,979],{},[707,11985,11986,11988,11990,11992,11994,11996,11998],{},[710,11987,984],{},[710,11989,987],{},[710,11991,990],{},[710,11993,993],{},[710,11995,996],{},[710,11997,999],{},[710,11999,1002],{},[126,12001,1005],{},[812,12003,12004,12006,12008,12010],{},[710,12005,1010],{},[710,12007,1013],{},[710,12009,1016],{},[710,12011,1019],{},[126,12013,1022],{},[139,12015,1026],{"id":1025},[126,12017,1029],{},[1031,12019,12020],{},[126,12021,1035],{},[126,12023,1038],{},[1031,12025,12026],{},[126,12027,1043],{},[126,12029,1046],{},[126,12031,1049],{},[1031,12033,12034],{},[126,12035,1054],{},[126,12037,1038],{},[1031,12039,12040],{},[126,12041,1061],{},[126,12043,1064],{},[139,12045,1068],{"id":1067},[126,12047,1071],{},[164,12049,12051],{"className":12050,"code":1075,"language":529,"meta":169},[527],[171,12052,1075],{"__ignoreMap":169},[126,12054,1080],{},[164,12056,12057],{"className":166,"code":1083,"language":168,"meta":169,"style":169},[171,12058,12059],{"__ignoreMap":169},[174,12060,12061,12063,12065,12067,12069,12071,12073],{"class":176,"line":177},[174,12062,1090],{"class":180},[174,12064,1093],{"class":188},[174,12066,1096],{"class":188},[174,12068,1099],{"class":188},[174,12070,1102],{"class":184},[174,12072,1105],{"class":184},[174,12074,1108],{"class":188},[126,12076,1111,12077,1115,12079,1119,12081],{},[171,12078,1114],{},[171,12080,1118],{},[292,12082,1124],{"href":1122,"rel":12083},[296],[139,12085,1128],{"id":1127},[126,12087,1131],{},[126,12089,1134],{},[1031,12091,12092],{},[126,12093,1139],{},[126,12095,1142,12096,1146],{},[171,12097,1145],{},[126,12099,1149],{},[126,12101,1152],{},[1031,12103,12104],{},[126,12105,1157],{},[1031,12107,12108],{},[126,12109,1162],{},[1031,12111,12112],{},[126,12113,1167],{},[126,12115,1170],{},[126,12117,1173],{},[1031,12119,12120],{},[126,12121,1178],{},[126,12123,1181],{},[139,12125,1185],{"id":1184},[126,12127,1188],{},[126,12129,1191],{},[126,12131,12132,843,12134,843,12136,843,12138,843,12140,843,12142,843,12144],{},[171,12133,1196],{},[171,12135,1199],{},[171,12137,1202],{},[171,12139,1205],{},[171,12141,1208],{},[171,12143,1211],{},[171,12145,1214],{},[126,12147,1217],{},[707,12149,12150,12152,12154,12156,12158,12160,12162,12164],{},[710,12151,1222],{},[710,12153,1225],{},[710,12155,1228],{},[710,12157,1231],{},[710,12159,1234],{},[710,12161,1237],{},[710,12163,1240],{},[710,12165,1243],{},[126,12167,1246],{},[126,12169,1249],{},[126,12171,1252],{},[1031,12173,12174],{},[126,12175,1257],{},[126,12177,1260],{},[1031,12179,12180],{},[126,12181,1265],{},[126,12183,1268],{},[139,12185,1272],{"id":1271},[126,12187,1275],{},[126,12189,1278],{},[126,12191,1281],{},[126,12193,1284,12194,1288],{},[171,12195,1287],{},[126,12197,1291],{},[139,12199,1294],{"id":1294},[126,12201,1297],{},[126,12203,1300],{},[126,12205,1303],{},[707,12207,12208,12210,12212,12214,12216,12218,12220],{},[710,12209,1308],{},[710,12211,1311],{},[710,12213,1314],{},[710,12215,1317],{},[710,12217,1320],{},[710,12219,1323],{},[710,12221,1326],{},[126,12223,1329],{},[139,12225,1332],{"id":1332},[126,12227,1335],{},[126,12229,1338],{},[126,12231,1341],{},[126,12233,1344],{},[1031,12235,12236],{},[126,12237,1349],{},[1031,12239,12240],{},[126,12241,1354],{},[1031,12243,12244],{},[126,12245,1359],{},[1031,12247,12248],{},[126,12249,1364],{},[126,12251,1367],{},[139,12253,1370],{"id":1370},[126,12255,1373],{},[126,12257,1376],{},[126,12259,1379],{},[126,12261,1382],{},[909,12263,1385],{},{"title":169,"searchDepth":236,"depth":236,"links":12265},[12266,12267,12268,12269,12270,12271,12272,12273,12274],{"id":972,"depth":236,"text":973},{"id":1025,"depth":236,"text":1026},{"id":1067,"depth":236,"text":1068},{"id":1127,"depth":236,"text":1128},{"id":1184,"depth":236,"text":1185},{"id":1271,"depth":236,"text":1272},{"id":1294,"depth":236,"text":1294},{"id":1332,"depth":236,"text":1332},{"id":1370,"depth":236,"text":1370},{},[1400,1401],{"title":950,"description":1397},{"loc":114,"lastmod":115},[944],1793191612947]