ที่ต้องเตรียมก่อนเริ่ม
- โปรเจค Node.js หรือ Next.js ที่อยู่บน GitHub แล้ว
- VPS หรือ server ที่ SSH เข้าได้ (ใน example นี้ใช้ Ubuntu)
- โดเมน + SSH key สำหรับ login server (หรือใช้ password ก็ได้แต่ไม่แนะนำ)
ถ้ายังไม่มี VPS อ่าน Deploy Node.js ขึ้น VPS ก่อน
โครงสร้างที่เราจะทำ
Workflow จะเป็นแบบนี้:
push ขึ้น main
↓
GitHub Actions runner เริ่ม
↓
checkout code
↓
รัน test
↓ (ถ้าผ่าน)
SSH เข้า server
↓
git pull + build + restart pm2
ทั้งหมดอัตโนมัติ ใช้เวลา 1-3 นาทีต่อ deploy
ขั้นที่ 1: สร้างไฟล์ workflow
ในโปรเจคของคุณสร้าง path นี้:
.github/
└── workflows/
└── deploy.yml
ชื่อไฟล์ตั้งอะไรก็ได้ ขอให้นามสกุลเป็น .yml หรือ .yaml
ขั้นที่ 2: เขียน workflow
name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
# Job 1: รัน test
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run lint
run: npm run lint
- name: Run tests
run: npm test
# Job 2: deploy (รันต่อหลัง test ผ่าน + เฉพาะตอน push main)
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Deploy to server
uses: appleboy/[email protected]
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
set -e
cd /var/www/myapp
git pull origin main
npm ci --omit=dev
npm run build
pm2 reload ecosystem.config.js --update-env
จุดที่ควรเข้าใจ:
npm ciดีกว่าnpm installเพราะใช้ lockfile แม่นกว่า เร็วกว่า เหมาะกับ CIcache: 'npm'ช่วยให้ run ครั้งที่สองเร็วขึ้นมาก (cachenode_modules)needs: testหมายความว่า jobdeployรอtestผ่านก่อนif:ทำให้ deploy รันแค่ตอน push เข้า main ไม่ใช่ตอน open PR
ขั้นที่ 3: ตั้ง Secrets
ไปที่ repo → Settings → Secrets and variables → Actions → New repository secret
ใส่ 3 ตัวนี้:
| Secret | ค่า |
|---|---|
| SERVER_HOST | IP หรือ domain ของ server เช่น 203.0.113.10 |
| SERVER_USER | username login ssh เช่น ubuntu หรือ deploy |
| SSH_PRIVATE_KEY | private key ทั้งไฟล์ (รวม -----BEGIN ... -----END) |
สำคัญ: private key ที่ใส่นี้ต้องมี public key คู่กันอยู่ในไฟล์ ~/.ssh/authorized_keys บน server
วิธีสร้าง key คู่ใหม่:
# สร้าง key คู่ใหม่ (อย่าใส่ passphrase)
ssh-keygen -t ed25519 -f deploy_key -N ""
# copy public key ขึ้น server
cat deploy_key.pub | ssh ubuntu@your-server \
"cat >> ~/.ssh/authorized_keys"
# เนื้อหาในไฟล์ deploy_key (private) → ใส่ใน secret SSH_PRIVATE_KEY
cat deploy_key
อย่าใช้ key ที่ใช้กับเครื่องตัวเอง — สร้าง key ใหม่เฉพาะสำหรับ deploy
ขั้นที่ 4: เตรียม server
บน server ต้องมี:
# clone repo (ครั้งแรกเท่านั้น)
cd /var/www
sudo git clone https://github.com/your-org/myapp.git
sudo chown -R $USER:$USER myapp
cd myapp
# ติดตั้งทุกอย่าง
npm ci
npm run build
# start ด้วย pm2
pm2 start ecosystem.config.js
pm2 save
# ตั้ง pm2 ให้ start ตอน reboot
pm2 startup
ไฟล์ ecosystem.config.js ตัวอย่าง:
module.exports = {
apps: [{
name: 'myapp',
script: 'npm',
args: 'start',
cwd: '/var/www/myapp',
env: {
NODE_ENV: 'production',
PORT: 3000,
},
max_memory_restart: '500M',
}]
}
ขั้นที่ 5: ทดสอบ
git add .github/workflows/deploy.yml
git commit -m "ci: add deploy workflow"
git push origin main
เปิด GitHub repo → tab Actions จะเห็น workflow กำลังรัน
ถ้าผ่านหมด — เข้า server ดู pm2 list ควรเห็น app uptime เป็นเลขเล็กๆ (เพิ่ง restart)
ปัญหาที่เจอบ่อย
SSH connection timeout → ตรวจสอบว่า:
- ใส่ port ถ้า server ใช้ port อื่นที่ไม่ใช่ 22 (เพิ่ม
port: 2222ใน step) - IP ของ GitHub Actions runner ไม่ได้ block ใน firewall (Actions ใช้ IP range หลายช่วง อย่าใส่ allow-list ลงไป)
Permission denied (publickey) → 99% เกิดจาก private key ใน secret ไม่ตรงกับ public key บน server
git pull ขอ password → ตอน clone ครั้งแรกใช้ HTTPS แล้วต้องเปลี่ยน remote เป็น SSH:
git remote set-url origin [email protected]:your-org/myapp.git
npm ci ฟ้อง package-lock ไม่ตรง → อย่าลืม commit package-lock.json
ขยายต่อ
ลอง enhancement พวกนี้เพิ่มทีหลัง:
- Slack notification — ใช้ action
slackapi/slack-github-actionแจ้งเตือนเมื่อ deploy เสร็จ - Health check หลัง deploy —
curl -f https://yourdomain.com/health || exit 1 - Rollback — เก็บ commit hash ก่อน deploy ใน file ถ้าพังก็ checkout กลับ
- Multi-environment — แยก workflow
deploy-staging.ymlกับdeploy-prod.yml
ต่อไปเรามี CI/CD ที่ใช้งานได้จริงแล้ว ทุกครั้งที่ push code ขึ้น main ระบบจะ deploy ให้เอง ตื่นนอนเขียน feature ก่อนนอนกด push พรุ่งนี้ลูกค้าได้ใช้เลย