
Trả lời nhanh: CI/CD là dây chuyền tự động giữa "viết xong code" và "khách dùng được": CI (Continuous Integration), mỗi lần push, hệ thống tự build và chạy test, hỏng là chặn ngay; CD (Continuous Deployment), qua được kiểm tra thì tự đưa lên server. Bộ đôi phổ biến nhất cho dự án cá nhân/đội nhỏ: GitHub Actions + VPS qua SSH, push lên nhánh main, hai phút sau bản mới đã sống trên server, không ai phải nhớ trình tự lệnh deploy nữa.
Deploy tay có hai vấn đề: phụ thuộc trí nhớ ("bước 3 là gì nhỉ?") và phụ thuộc con người ("đợi mình về nhà mở máy"). CI/CD biến trình tự đó thành văn bản chạy tự động, sai thì sửa văn bản, không sai vì quên. Bài này giải thích khái niệm rồi đi thẳng vào file workflow hoàn chỉnh deploy lên VPS, kèm các lỗi người mới hay vấp.
- CI = gác cổng tự động: build + test mỗi push, hỏng là đỏ, không ai merge nhầm code gãy
- CD = giao hàng tự động: qua cổng là lên server, quy trình nằm trong file YAML cạnh code
- GitHub Actions + SSH + deploy script trên VPS: bộ ba đủ dùng cho 90% dự án
- Secret (key SSH) cất trong GitHub Secrets, không bao giờ nằm trong code
CI/CD bằng một câu chuyện quen
Không CI/CD: sửa code → tự nhớ chạy test (hoặc quên) → SSH vào server → git pull, build, restart, sai một bước là site nằm, và cả quy trình sống trong đầu một người. Có CI/CD: sửa code → push → robot chạy test (đỏ thì dừng, báo ngay chỗ hỏng) → xanh thì robot tự deploy đúng trình tự, đúng từng lần như một. Giá trị không nằm ở "ngầu" mà ở loại con người khỏi khâu lặp lại, kể cả lúc 2h sáng, kể cả khi deploy là agent AI vừa xong việc tự bấm.
Chuẩn bị phía VPS: một script + một user
# tren VPS: script da co tu bai deploy Next.js
cat ~/deploy.sh # git pull && npm ci && npm run build && pm2 restart app
# tao SSH key rieng cho CI (khong dung key ca nhan)
ssh-keygen -t ed25519 -f ~/.ssh/ci_deploy -N ""
cat ~/.ssh/ci_deploy.pub >> ~/.ssh/authorized_keys
cat ~/.ssh/ci_deploy # private key, dan vao GitHub Secret o buoc sauVào repo GitHub → Settings → Secrets and variables → Actions, tạo 3 secret: VPS_HOST (IP), VPS_USER, VPS_SSH_KEY (nội dung private key). Nguyên tắc sắt: secret sống trong két của GitHub, không bao giờ trong code.
File workflow hoàn chỉnh
# .github/workflows/deploy.yml
name: CI-CD
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22, cache: npm }
- run: npm ci
- run: npm test --if-present
- run: npm run build
deploy:
needs: test # chi chay khi test xanh
runs-on: ubuntu-latest
steps:
- name: Deploy len VPS qua SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: ~/deploy.shĐọc theo tiếng người: khi push vào main → job test dựng môi trường sạch, cài, test, build; job deploy chỉ chạy khi test xanh, SSH vào VPS gọi đúng script bạn vẫn chạy tay. Từ nay "deploy" nghĩa là "push", lịch sử ai deploy gì lúc nào nằm sẵn trong tab Actions.
Lỗi người mới hay vấp - và nâng cấp khi lớn
- Permission denied: dán nhầm public key vào secret (cần private), hoặc quyền file authorized_keys sai (600).
- Test xanh trên CI, chạy sai trên server: lệch phiên bản Node/env, ghim node-version trong workflow khớp VPS, env đặt trên server chứ không hardcode.
- Deploy giữa giờ đông làm khựng site: pm2 reload (bài PM2) thay restart; nặng hơn thì build trên CI rồi rsync sản phẩm sang, server chỉ restart.
- Build chậm/ngốn phút miễn phí: cache npm đã bật ở trên; đội build dày cân nhắc runner tự host trên VPS, nhanh hơn hẳn và không đếm phút.
Bảo mật trước khi tiện lợi
| Việc | Vì sao bắt buộc |
|---|---|
| Tạo một tài khoản riêng để triển khai, không dùng tài khoản quản trị | Khóa bị lộ thì thiệt hại giới hạn ở thư mục ứng dụng |
| Dùng khóa riêng chỉ cho việc triển khai, không dùng lại khóa cá nhân | Thu hồi được riêng khi cần |
| Giới hạn lệnh khóa đó chạy được | Khóa bị lộ cũng không mở được phiên đăng nhập tùy ý |
| Lưu khóa trong kho bí mật của kho mã, không để trong tệp cấu hình | Tệp cấu hình nằm trong lịch sử phiên bản, xóa sau vẫn còn |
| Bật xác thực hai lớp cho tài khoản kho mã | Kho mã có quyền đẩy lên máy chủ của bạn |
Chuẩn bị phía máy chủ
# 1. Tao nguoi dung rieng cho viec trien khai adduser --disabled-password --gecos "" trienkhai mkdir -p /home/trienkhai/.ssh && chmod 700 /home/trienkhai/.ssh # 2. Dat khoa cong khai vao, kem gioi han lenh chay duoc echo 'command="/opt/trien-khai.sh",no-port-forwarding,no-pty ssh-ed25519 AAAA...' > /home/trienkhai/.ssh/authorized_keys chmod 600 /home/trienkhai/.ssh/authorized_keys chown -R trienkhai:trienkhai /home/trienkhai/.ssh # 3. Script trien khai, viet cho no dung mot viec cat > /opt/trien-khai.sh <<'SH' #!/bin/bash set -euo pipefail cd /var/www/ungdung git pull --ff-only docker compose pull docker compose up -d docker compose ps SH chmod +x /opt/trien-khai.sh
Dòng giới hạn lệnh trong tệp khóa công khai là dòng đáng chú ý nhất: nó biến khóa triển khai thành khóa chỉ chạy được đúng một tập lệnh, thay vì mở phiên đăng nhập đầy đủ vào máy chủ.
Ba lỗi người mới hay vấp
- Không có bước quay lui. Triển khai hỏng lúc 5 giờ chiều thứ sáu mà không quay lại được là tình huống nên tránh bằng cách giữ bản trước và một lệnh quay lui.
- Không kiểm sau khi triển khai. Thêm một bước gọi thử địa chỉ kiểm tra sức khỏe và báo lỗi nếu không phản hồi, thay vì coi triển khai xong là xong.
- Đặt khóa và mật khẩu trong tệp cấu hình đẩy lên kho mã. Xóa ở lần đẩy sau vẫn còn trong lịch sử, và phải coi khóa đó là đã lộ.
Với dự án nhỏ, quy trình này chạy trên một máy chủ là đủ. Khi lớn hơn, bước tiếp theo là tách môi trường thử và môi trường thật, mỗi nơi một máy, và chỉ triển khai lên môi trường thật sau khi bản thử chạy ổn.
Câu hỏi thường gặp
Dự án một mình có cần CI/CD không?
Càng một mình càng cần, không có đồng đội review thì bộ test tự động là người gác cổng duy nhất, và deploy một-push tiết kiệm đúng thứ bạn thiếu nhất: sự tập trung.
GitHub Actions miễn phí được bao nhiêu?
Repo public: không giới hạn phút. Private: có hạn mức phút/tháng khá rộng cho dự án nhỏ, vượt thì trả thêm hoặc chuyển runner tự host (không đếm phút).
CI/CD với Docker thì khác gì?
Trình tự thành: build image trên CI → đẩy registry → server pull + up. Cùng triết lý, thêm tính nhất quán môi trường, bài Docker build chậm có mẹo cache cho khúc CI này.
Rollback thế nào khi bản mới lỗi?
Cách gọn: git revert commit lỗi rồi push, dây chuyền tự deploy bản lành. Cách nhanh: giữ bản build trước đó trên server (thư mục releases + symlink) để trỏ ngược tức thì, nâng cấp đáng làm khi site có khách thật.
Bài viết liên quan
- CI/CD tự host trên VPS: nhanh và rẻ hơn
- GitHub Actions runner tự host: khi nào đáng
- VPS ổ Enterprise U.2 NVMe RAID 10 tại TND
- GPU VPS cho AI startup: ROI 2026
- Hermes spawn subagent: chạy nhiều agent song song xử lý batch task
- MCP là gì? Chuẩn cắm công cụ cho AI agent, nói dễ hiểu
- Nguyên nhân và Khắc Phục Website bị quá tải-Phần 1
- Chương trình tặng Voucher cho khách hàng mới dự sự kiện PingPong 2024
- Dùng OpenRouter trong code, n8n và Dify: hướng dẫn đủ bước



