SSD Nodes Learn
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-07-24

วิธีใช้ Claude Code บน VPS ด้วย tmux

วิธีรัน Claude Code บน Linux VPS ผ่าน tmux เพื่อป้องกันปัญหา agent หยุดทำงานเมื่อการเชื่อมต่อ SSH ขาดหายหรือได้รับสัญญาณ SIGHUP จากการปิดแล็ปท็อป

ปัญหาเกิดจากฝาพับแล็ปท็อป ไม่ใช่จาก CLI

Claude Code ทำงานได้ปกติบนแล็ปท็อปจนกระทั่งคุณปิดฝาพับ: การเชื่อมต่อ SSH จะถูกตัด, shell จะได้รับสัญญาณ SIGHUP และ agent จะหยุดทำงานหลังจากเริ่มรัน test ไปได้ 3 นาที ให้รัน CLI บนเครื่องที่ไม่เข้าสู่โหมด sleep และรันภายใน terminal multiplexer ที่กระบวนการทำงาน (processes) ไม่ได้เป็น child process ของ SSH session วิธีการแก้ไขคือการใช้ tmux เพื่อรักษาการทำงานของโปรแกรม ไม่ใช่การติดตั้งโปรแกรม

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

การทำงานที่แท้จริงของ tmux

เมื่อคุณ SSH เข้ามา sshd จะทำการ fork shell และส่ง pseudo-terminal ให้แก่ shell นั้น ทุกอย่างที่คุณเริ่มทำงานจาก shell ดังกล่าวจะมีสถานะเป็น child process ของ shell นั้น หากการเชื่อมต่อขาดหายไป kernel จะทำการทำลาย pty ส่งผลให้ shell ได้รับสัญญาณ SIGHUP และส่งสัญญาณนี้ต่อไปยัง child processes ของมันตามลำดับ ทำให้ process ที่ทำงานแบบ foreground และใช้เวลานานจะถูกปิดตัวลง

tmux เปลี่ยนรูปแบบการเป็นเจ้าของ process ใหม่ คำสั่ง tmux ที่คุณพิมพ์คือ thin client ที่สื่อสารผ่าน unix socket ไปยัง tmux server ซึ่งทำงานแบบ detached แยกจาก terminal ของคุณ Shell ภายใน session จะเป็น child process ของ server ดังกล่าว ไม่ใช่ของ sshd หากการเชื่อมต่อ SSH ขาดหายไป ตัว client จะหายไป แต่ server, session และ agent จะยังคงทำงานต่อไป เมื่อเชื่อมต่อใหม่ผ่าน tmux attach คุณจะกลับเข้าสู่ shell เดิมพร้อมกับประวัติการเลื่อนหน้าจอ (scrollback) เดิม nohup สามารถทำงานต่อได้แม้การเชื่อมต่อจะขาดหายไป แต่จะไม่สามารถกลับเข้าไปได้หากเป็น TUI ที่ทำงานอยู่เบื้องหลัง Claude Code เป็นเครื่องมือแบบ interactive ดังนั้น tmux (หรือ screen) จึงเป็นเครื่องมือที่เหมาะสมกว่า

การเลือกขนาดของเครื่อง

CLI คือกระบวนการของ Node ซึ่งไม่ใช่ส่วนที่ใช้ทรัพยากรหลักของเครื่อง สิ่งที่ใช้ทรัพยากรคือสิ่งที่ agent รันแทนคุณ เช่น การ build, ชุดทดสอบ (test suite) ทั้งหมด, tsc, language server หรือ database ใน Docker จงเลือกขนาดเครื่องตามความต้องการของ toolchain ไม่ใช่ตามความต้องการของ CLI ควรเพิ่ม swap ไว้แม้จะไม่ได้ใช้งาน เพราะจะช่วยเปลี่ยนจากการถูกระบบสั่ง kill เนื่องจาก OOM (Out of Memory) มาเป็นการ build ที่ช้าลงแทน:

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

ควรตรวจสอบพื้นที่ดิสก์ด้วย เนื่องจาก repos, node_modules และ Docker images จะเพิ่มขึ้นอย่างรวดเร็ว และหาก toolchain ของคุณใช้งานเกินกว่าระดับ container ไปจนถึง virtual machines เต็มรูปแบบ เช่น KVM guest หรือ local Kubernetes node โปรดตรวจสอบว่าแผนบริการของคุณรองรับ CPU virtualisation extensions หรือไม่ก่อนตัดสินใจ เนื่องจาก การรัน nested virtualization บน VPS เป็นสิ่งที่ผู้ให้บริการต้องเปิดใช้งานให้ ไม่ใช่สิ่งที่คุณสามารถเปิดใช้งานเองจากภายใน guest ได้

การใช้ผู้ใช้ที่ไม่ใช่ root เป็นอันดับแรก

สร้างผู้ใช้เฉพาะที่มี home directory ของตนเอง และจัดเก็บ public key ไว้ในตำแหน่งที่ถูกต้อง:

sudo adduser --disabled-password --gecos "" agent
sudo install -d -m 700 -o agent -g agent /home/agent/.ssh
sudo cp ~/.ssh/authorized_keys /home/agent/.ssh/authorized_keys
sudo chown agent:agent /home/agent/.ssh/authorized_keys
sudo chmod 600 /home/agent/.ssh/authorized_keys

โดยตั้งใจให้ agent ไม่อยู่ในกลุ่ม sudo หากจำเป็นต้องใช้ package ของระบบ ให้ทำการติดตั้งผ่านกระบวนการปกติ การตัดสินใจนี้จะช่วยลดโอกาสที่คำสั่ง shell ที่ผิดพลาดจะสร้างความเสียหายต่อ host ได้เป็นส่วนใหญ่

SSH hygiene สำหรับเครื่องที่เปิดทิ้งไว้ตลอดเวลา

การเปิด Password auth บนเครื่องที่เชื่อมต่อกับ public internet ตลอดทั้งวัน ซึ่งมีการเก็บ agent และ source code ไว้ ถือเป็นความเสี่ยงที่ไม่ควรแบกรับ ควรปิดการใช้งานนี้ สำหรับ Ubuntu 24.04 และ Debian 13 เนื่องจาก /etc/ssh/sshd_config รวม /etc/ssh/sshd_config.d/*.conf ไว้ด้วย จึงควรสร้างไฟล์ใหม่แทนการแก้ไขไฟล์ config หลัก:

# /etc/ssh/sshd_config.d/10-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

ตรวจสอบความถูกต้องและ reload — ให้เปิด session ปัจจุบันค้างไว้ในขณะที่ทดสอบ session ใหม่ จาก terminal ที่สอง:

sudo sshd -t && sudo systemctl restart ssh

ข้อควรระวังสำหรับ Ubuntu 24.04: sshd ทำงานแบบ socket-activated การตั้งค่า auth จะมีผลใน systemctl restart ssh แต่หากมีการเปลี่ยนแปลง Port จะต้องใช้ systemctl daemon-reload และต้อง restart ssh.socket ด้วย

ถัดไปคือ firewall ควรอนุญาต SSH ก่อน ที่จะเปิดใช้งาน มิฉะนั้นคุณจะถูก lock out:

sudo ufw allow OpenSSH
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable

ติดตั้ง fail2ban โดยพิจารณาถึงประโยชน์ที่จะได้รับ: เมื่อปิด password auth แล้ว การโจมตีแบบ brute force จะไม่สามารถทำสำเร็จได้ — ซึ่งจะช่วยลดจำนวนความพยายามที่ล้มเหลวใน journal ของคุณ

# /etc/fail2ban/jail.local
[sshd]
enabled = true
backend = systemd
maxretry = 5
bantime = 1h

สุดท้าย ให้ติดตั้ง patch อัตโนมัติด้วย sudo apt install unattended-upgrades และ sudo dpkg-reconfigure -plow unattended-upgrades ข้อควรระวังเกี่ยวกับการใช้งานร่วมกับ tmux: หากเปิด Unattended-Upgrade::Automatic-Reboot ไว้ เมื่อมีการอัปเดต kernel เครื่องจะ reboot และทำให้ทุก session ถูกปิดลง หากปิดฟังก์ชันนี้ไว้ คุณสามารถเลือก reboot เครื่องได้ตามเวลาที่ต้องการเมื่อไม่มีกระบวนการใดกำลังทำงานอยู่

ติดตั้ง Node.js และ Claude Code บน Ubuntu

Claude Code เป็น Node CLI ดังนั้นคุณจึงต้องมี Node เวอร์ชันปัจจุบัน แพ็กเกจจาก distro มักจะล้าหลัง; สำหรับ Ubuntu และ Debian วิธีที่นิยมคือการใช้ NodeSource ซึ่งมาพร้อมกับ repo ที่มีการลงลายเซ็นแล้ว (ไม่มี apt-key — เครื่องมือนั้นถูกยกเลิกไปแล้ว):

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --version

ขั้นตอนที่คนมักทำผิดคือ: ติดตั้ง CLI ด้วยผู้ใช้ที่เป็น agent ห้ามใช้ sudo npm -g โดยเด็ดขาด การใช้ global prefix ที่เป็นของ root จะทำให้เกิดข้อผิดพลาดด้าน permission ในภายหลัง และทำให้มีไฟล์ที่เป็นของ root ค้างอยู่ใน npm cache ให้ตั้งค่า npm prefix ไปที่ home ของผู้ใช้ก่อน:

mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
npm install -g @anthropic-ai/claude-code
claude --version

การ export ต้องใส่ไว้ใน ~/.bashrc ไม่ใช่ ~/.profile และต้องวางไว้ เหนือ เงื่อนไข "If not running interactively, don't do anything" ที่อยู่ด้านบนสุดของไฟล์ เนื่องจาก tmux อาจเริ่มการทำงานแบบ non-login shells ซึ่งจะอ่าน ~/.bashrc และข้าม ~/.profile ไป — ~/.profile จะทำงานเฉพาะใน login shells เท่านั้น การใช้ Node แบบรายผู้ใช้ผ่าน version manager เช่น nvm ให้ผลลัพธ์แบบเดียวกัน เป้าหมายคือทำให้ npm install -g ไม่จำเป็นต้องใช้ sudo คุณยังสามารถใช้ npm ได้ตามปกติ หรือใช้ install script ของ Anthropic ซึ่งเป็นวิธีมาตรฐานที่ระบุไว้ในเอกสารปัจจุบัน โปรดตรวจสอบเอกสารการติดตั้งของ Anthropic ก่อนคัดลอกคำสั่ง เนื่องจากวิธีการติดตั้งอาจมีการเปลี่ยนแปลง

รัน claude ภายใน repo เพื่อเริ่มใช้งาน การรันครั้งแรกจะเป็นการแนะนำขั้นตอนการยืนยันตัวตน (authentication) หากเป็นเครื่องแบบ headless จะไม่มี browser ระบบจะให้ URL สำหรับเปิดบนเครื่องของคุณ และให้ code สำหรับนำกลับมาใส่ใน terminal (อีกวิธีคือการใช้ API key ใน environment) ไม่ว่าจะวิธีใด ข้อมูลรับรอง (credential) จะถูกเก็บไว้บนเซิร์ฟเวอร์ ซึ่งนำไปสู่ขั้นตอนที่คนมักข้ามไป

การพิจารณาเรื่องขอบเขตความเสียหาย (blast radius)

Agent ที่มีสิทธิ์เข้าถึง shell คือ shell อย่างหนึ่ง มันสามารถอ่านข้อมูลทุกอย่างที่ user ที่รันมันสามารถอ่านได้ และสามารถ push ข้อมูลไปยังทุกที่ที่ user นั้นสามารถ push ได้ นี่ไม่ใช่ข้อเสียของเครื่องมือ แต่เป็นคุณสมบัติพื้นฐานของมัน และเป็นเหตุผลว่าทำไมบัญชีที่ใช้รัน agent จึงมีความสำคัญมากกว่าการตั้งค่าใดๆ

  • ใช้ user เฉพาะที่มีสิทธิ์จำกัด (unprivileged user). ห้ามอยู่ในกลุ่ม sudo และห้ามใช้ home directory ร่วมกับบัญชีส่วนตัวของคุณ
  • ห้ามเก็บข้อมูลสำคัญของระบบ production ไว้ในเครื่อง. ห้ามใช้ ~/.aws/credentials เพื่อเก็บ prod keys, ห้ามคัดลอก .env จากระบบ production และห้ามใช้รหัสผ่านฐานข้อมูลที่มีสิทธิ์เขียน (write access) ในส่วนที่สำคัญ ให้ใช้ credential สำหรับ staging หรือแบบ read-only แทน
  • ใช้ token ที่จำกัดขอบเขต (Scoped tokens). เช่น GitHub token ที่จำกัดสิทธิ์เฉพาะหนึ่ง repository หรือใช้ deploy key เมื่อต้องการเพียงสิทธิ์ในการอ่านเท่านั้น

Claude Code มี flag ที่ใช้ข้ามการถามคำถามขออนุญาต (permission prompts) ทั้งหมด หากใช้งานบน laptop หรือโปรเจกต์ชั่วคราว คุณสามารถตัดสินใจได้ตามความเหมาะสม แต่หากใช้งานบน server ที่มีการเก็บ token การใช้ flag นี้จะตัดปราการด่านสุดท้ายระหว่างคำสั่งที่ผิดพลาดกับความเสียหายระดับ git push --force รายละเอียดเกี่ยวกับสิ่งที่ flag นี้เปลี่ยนแปลง และวิธีการควบคุม agent ที่รันด้วย flag นี้ ตั้งแต่การใช้ sandbox ในตัวไปจนถึงการใช้ VPS แบบใช้แล้วทิ้ง สามารถอ่านเพิ่มเติมได้ที่ running Claude Code safely on a server

Deploy key เทียบกับ SSH agent forwarding

การใช้ ssh -A เพื่อให้ git สามารถใช้ key บน laptop ของคุณนั้นเป็นสิ่งที่ทำได้ง่าย แต่ต้องเข้าใจถึงสิทธิ์ที่จะได้รับ: agent forwarding จะเปิด socket ของ local SSH agent ให้กับ process ที่รันด้วย user นั้นบนเครื่อง server สิ่งใดก็ตามที่รันด้วย agent รวมถึงตัว agent เอง สามารถขอให้ key ของคุณเซ็นชื่อเพื่อยืนยันตัวตนกับ host ใดก็ได้ที่สามารถเข้าถึงได้ ตราบใดที่คุณยังเชื่อมต่ออยู่ ซึ่งเป็นสิทธิ์ที่มากกว่าแค่ "การให้ git pull repository นี้เพียงแห่งเดียว"

ควรสร้าง key บน server แทน โดยลงทะเบียนเป็น deploy key ประจำแต่ละ repository (ให้สิทธิ์ write access เฉพาะเมื่อ agent จำเป็นต้อง push เท่านั้น) และตั้งค่า git identity เพื่อให้สามารถระบุตัวตนของ commit ที่มาจากเครื่องนั้นได้:

ssh-keygen -t ed25519 -C "agent deploy key" -f ~/.ssh/id_ed25519_repo
cat ~/.ssh/id_ed25519_repo.pub   # paste into the repo's Deploy Keys
git config --global user.name "Agent (build box)"
git config --global user.email "agent@example.com"

The tmux workflow

ติดตั้งโปรแกรม (sudo apt install tmux) จากนั้นสร้าง ~/.tmux.conf ขั้นพื้นฐาน:

set -g mouse on
set -g history-limit 50000
set -g default-terminal "tmux-256color"

คำสั่ง 4 คำสั่งสำหรับการใช้งานทั่วไป:

tmux new -A -s claude     # attach to session "claude", creating it if absent
# ...run `claude` inside it, work normally...
# Ctrl-b then d           -> detach; everything keeps running
tmux ls                   # list sessions
tmux attach -t claude     # reattach, from this machine or any other
tmux kill-session -t claude

ควรจดจำ tmux new -A -s claude ไว้ เนื่องจากคำสั่งนี้จะเชื่อมต่อเข้าสู่ session เดิมหากมีอยู่ หรือสร้าง session ใหม่หากยังไม่มี ดังนั้นคำสั่งเดียวสามารถใช้ได้ทั้งการเริ่มงานใหม่และการกลับมาทำงานต่อหลังจากหลุดการเชื่อมต่อ ควรตั้ง alias สำหรับคำสั่งนี้ เมื่ออยู่ใน session แล้ว Ctrl-b c ใช้สำหรับเปิด window, Ctrl-b n และ Ctrl-b p ใช้สำหรับสลับ window และ Ctrl-b [ ใช้สำหรับเข้าสู่ copy mode เพื่อเลื่อนดูข้อความย้อนหลัง (ใช้ q เพื่อออกจากโหมดนี้)

ข้อควรระวังสำหรับ session ที่เปิดทิ้งไว้โดยไม่ปิด: agent จะส่งประวัติการสนทนาทั้งหมดใหม่ทุกครั้งที่มีการตอบโต้ โปรดอ่าน การใช้ token ของ Claude Code session ที่เปิดค้างไว้เป็นเวลานาน ก่อนที่จะเปิด session ทิ้งไว้เป็นเวลาหนึ่งสัปดาห์

Failure modes

"My session is gone." tmux ls แสดงผล no server running on /tmp/tmux-1000/default สาเหตุเกือบทั้งหมดเกิดจาก process ไม่ได้ทำงานอยู่ภายใน tmux โดยคุณอาจ SSH เข้าไปแล้วรัน claude โดยตรง ซึ่งเมื่อการเชื่อมต่อขาดหายไปจะทำให้ process ถูกปิดลง ไม่สามารถกู้คืนได้ วิธีป้องกันคือต้องรัน tmux new -A -s <project> เป็นคำสั่งแรกหลังจากการ login ทุกครั้ง

Pane มีขนาดเล็กลงจนเหลือเป็นช่องขนาดเล็ก tmux จะปรับขนาด session ให้เท่ากับ client ที่เล็กที่สุดที่เชื่อมต่ออยู่ ดังนั้นหากมี client ค้างจากการเชื่อมต่อจากเครื่องอื่น จะทำให้การแสดงผลถูกบีบให้เล็กลง ให้ใช้คำสั่ง tmux attach -d -t claude เพื่อตัดการเชื่อมต่อจาก client อื่นขณะที่คุณทำการ attach

Build แสดงข้อความ Killed เป็นข้อความสั้นๆ โดยไม่มี stack trace ให้ตรวจสอบด้วย sudo dmesg -T | grep -i -E 'out of memory|killed process' ซึ่งหมายความว่า kernel OOM killer ได้เลือกปิด process ที่ใช้ทรัพยากรมากที่สุด สำหรับ Node คุณอาจพบข้อความ FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory แทน วิธีแก้ไขตามลำดับคือ: เพิ่ม swap (ตามที่ระบุไว้ด้านบน), จำกัดการทำงานแบบ parallel ของ test และ compiler, เพิ่ม heap size ของ Node ด้วย NODE_OPTIONS=--max-old-space-size=... หรือเพิ่มขนาดของ VPS

OOM killer อาจเลือกปิด tmux server แทนที่จะเป็นตัว build ซึ่งจะทำให้ session ของคุณหายไปด้วย หากมีการรัน systemd-oomd อยู่ อาจส่งผลให้ user slice ทั้งหมดถูกปิดลงในลักษณะเดียวกัน

npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...' เกิดจากการติดตั้งแบบ global ลงใน prefix ที่เป็นของ root ให้ใช้ prefix ~/.npm-global ตามที่ระบุไว้ด้านบน หากคุณเคยรัน sudo npm มาก่อน อาจพบข้อความ Your cache folder contains root-owned files ให้แก้ไขด้วย sudo chown -R $(id -u):$(id -g) ~/.npm

claude: command not found — แต่เกิดขึ้นเพียงบางครั้ง การ export PATH ของคุณอยู่ใน ~/.bashrc ซึ่งอยู่ใต้เงื่อนไข "If not running interactively, don't do anything" ทำให้ non-interactive shells ข้ามการตั้งค่านี้ ให้ย้ายการ export ไปไว้เหนือเงื่อนไขดังกล่าว และเก็บไว้ใน ~/.bashrc แทนที่จะเป็น ~/.profile เนื่องจาก tmux อาจเริ่มการทำงานแบบ non-login shells ซึ่งจะอ่านค่าจาก ~/.bashrc แต่จะไม่เข้าถึง ~/.profile

สีเพี้ยนหลังจาก attach เกิดจากความไม่สอดคล้องกันของ TERM — สามารถแก้ไขได้โดยทำตามบรรทัด default-terminal ด้านบน

Session หายไปหลังจาก reboot ไม่ใช่ข้อผิดพลาดของโปรแกรม เนื่องจาก tmux server คือ process หนึ่ง ซึ่งจะถูกปิดลงเมื่อมีการ reboot ให้ตรวจสอบที่ uptime

ปัญหาที่จะเกิดขึ้นเมื่อระบบขยายตัวขึ้น

จำนวนโปรเจกต์ที่มากขึ้น หากใช้หนึ่ง tmux session ต่อหนึ่ง repo และตั้งชื่อตามชื่อ repo นั้น tmux ls จะทำหน้าที่เป็น dashboard ของคุณ หากไม่รักษาวินัยในการตั้งชื่อ คุณจะพบกับ session 0, 1 และ 2 ในทำนองเดียวกัน การจัดการ port จะเริ่มสับสน เช่น เมื่อมี 6 repo ที่ต้องการใช้ :3000 พร้อมกัน เมื่อถึงจุดนี้ควรเลิกกำหนด port ด้วยตนเอง และใช้ a Traefik reverse proxy route multiple apps under Docker Compose เพื่อจัดการการส่งข้อมูลผ่าน hostname แทน

จำนวนผู้ใช้งานที่มากขึ้น tmux socket จะถูกแยกตามผู้ใช้งาน ดังนั้นนักพัฒนาสองคนที่ใช้เครื่องเดียวกันจะมี tmux server ของตนเอง และไม่สามารถมองเห็น session ของกันและกันได้ การใช้ session เดียวกันผ่าน shared socket หมายความว่าทุกคนจะพิมพ์คำสั่งลงใน shell เดียวกันภายใต้ Unix user คนเดียวกัน ซึ่งจะส่งผลต่อการตรวจสอบ (audit) และสิทธิ์การใช้งาน (permission) วิธีการที่ถูกต้องและเรียบง่ายที่สุดคือการแยกผู้ใช้งานออกจากกัน

งานที่ทำงานโดยไม่มีผู้ดูแล tmux ออกแบบมาเพื่อใช้งานกับ interactive sessions ที่ต้องมีการเชื่อมต่อเข้าไป งานที่ต้องทำงานตามกำหนดเวลาโดยไม่มีผู้ดูแลควรใช้ systemd unit และ timer เนื่องจากจะได้รับระบบบันทึก log, นโยบายการ restart และการทำงานต่ออัตโนมัติหลัง boot โดยไม่ต้องตั้งค่าเพิ่มเติม การเลือกใช้ tmux เพื่อรันงานลักษณะ cron แสดงว่างานนั้นควรถูกเปลี่ยนเป็น service

หมายเหตุเพิ่มเติม: ควรตั้งค่าให้ dev servers ผูกกับ 127.0.0.1 ไม่ใช่ 0.0.0.0 และเข้าถึงผ่าน SSH tunnel (ssh -L 3000:127.0.0.1:3000 agent@your-server) แทนการเปิด port ใน ufw เมื่อคุณต้องทำการ forward port จำนวนมาก หรือเมื่อต้องใช้งานพร้อมกันทั้งโทรศัพท์และแล็ปท็อป ให้ใช้ self-hosted WireGuard VPN on the VPS แทน โดยตั้งค่าให้ dev servers ผูกกับ private interface และใช้ ufw ปิดกั้นการเชื่อมต่อทั้งหมดจาก public interface การใช้ firewall จะมีประสิทธิภาพก็ต่อเมื่อคุณหยุดเปิดช่องโหว่ (punching holes) ในนั้น

Claude Code ไม่ใช่ทางเลือกเดียว: running a coding AI agent on a VPS มีตัวเลือกอย่าง Aider และ Goose เช่นกัน

FAQ

Claude Code จะยังทำงานต่อไปหรือไม่หากการเชื่อมต่อ SSH หลุด?

จะทำงานต่อไปก็ต่อเมื่อคุณเริ่มใช้งานผ่าน tmux เท่านั้น กระบวนการที่เริ่มจาก SSH shell โดยตรงจะเป็น child process ของ shell นั้น และจะหยุดทำงานทันทีเมื่อ pty ถูกตัดการเชื่อมต่อ หากใช้งานภายใน tmux shell จะเป็นของ detached tmux server ทำให้ agent สามารถทำงานต่อจนเสร็จสิ้น และ tmux attach จะพาคุณกลับเข้าสู่หน้าจอเดิม ให้ใช้คำสั่ง tmux new -A -s <project> เป็นคำสั่งแรกหลังการ login ทุกครั้งเพื่อป้องกันปัญหานี้

ควรติดตั้ง CLI ด้วย sudo npm install -g หรือไม่?

ไม่ควร การใช้ global prefix ที่เป็นของ root จะทำให้เกิดข้อผิดพลาด EACCES เมื่อมีการติดตั้งในภายหลัง และทำให้มีไฟล์ที่เป็นของ root ใน npm cache ให้ตั้งค่า npm prefix เป็น ~/.npm-global (หรือใช้ version manager เช่น nvm) จากนั้นติดตั้งในฐานะผู้ใช้ agent ที่ไม่มีสิทธิ์ root และทำการ export ~/.npm-global/bin ไปยัง PATH จาก ~/.bashrc โดยวางไว้เหนือ interactive guard หากคุณเคยรัน sudo npm ไปแล้ว ให้ซ่อมแซม cache ด้วย sudo chown -R $(id -u):$(id -g) ~/.npm

การทำ ssh -A agent forwarding ปลอดภัยหรือไม่บนเครื่องที่มี agent รันอยู่?

การทำเช่นนี้ให้สิทธิ์เกินความจำเป็น การ forwarding จะเปิดเผย socket ของ local SSH agent ให้กับทุก process ที่รันด้วย user นั้น ดังนั้นทุกอย่างบนเครื่องสามารถใช้ key ของคุณเพื่อ sign สำหรับ host ใดก็ได้ที่เครื่องนั้นเข้าถึงได้ ตราบใดที่คุณยังเชื่อมต่ออยู่ แนะนำให้สร้าง ed25519 key บน server และลงทะเบียนเป็น deploy key ประจำ repository โดยให้สิทธิ์ write access เฉพาะในกรณีที่ agent จำเป็นต้อง push เท่านั้น

ทำไมการ build ของฉันถึงแสดงแค่ Killed?

ข้อความคำเดียวที่ไม่มี stack trace คือ kernel OOM killer ตรวจสอบให้แน่ใจด้วย sudo dmesg -T | grep -i -E 'out of memory|killed process' หากใช้ Node คุณอาจเห็น JavaScript heap out of memory แทน ให้แก้ไขตามลำดับดังนี้: เพิ่ม swapfile, จำกัดจำนวนการทำงานแบบ parallel ของ test และ compiler, เพิ่ม NODE_OPTIONS=--max-old-space-size=... และขยายขนาด VPS โปรดระวังว่า OOM killer อาจเลือกปิด tmux server แทนที่จะเป็นตัว build ซึ่งจะทำให้ session ทั้งหมดของคุณหลุดไปด้วย

ควรใช้ tmux หรือ systemd service?

tmux เหมาะสำหรับ interactive sessions ที่คุณต้องเชื่อมต่อเข้าไป ดูสถานะ และพิมพ์คำสั่ง ซึ่งเป็นลักษณะการทำงานของ agent session ส่วนงานที่ทำงานตามตารางเวลาโดยไม่มีผู้ดูแลควรใช้ systemd unit และ timer เนื่องจากมีระบบ logging, นโยบายการ restart และการทำงานอัตโนมัติเมื่อ boot มาให้ในตัว หากคุณต้องการใช้ tmux เพื่อรันงานในลักษณะ cron แสดงว่างานนั้นควรถูกตั้งค่าเป็น service