Vừa bấm nút khởi tạo VPS, 60 giây sau bạn có IP và mật khẩu root. Đa số người mới sẽ SSH vào bằng root, cài đại Docker rồi chạy app. Vài tuần sau log đầy Failed password for root từ bot khắp thế giới. Bài này là playbook hoàn chỉnh để setup Ubuntu Server VPS chuẩn cho dev: vừa an toàn, vừa có sẵn Docker, code-server (VS Code trên trình duyệt), terminal đẹp, swap. Mọi lệnh đều copy-paste được, làm theo thứ tự là xong.
Trước khi bắt đầu
Bài này giả định bạn dùng Ubuntu Server 24.04 LTS (bản LTS mới, hỗ trợ dài hạn), đã có IP và mật khẩu root từ nhà cung cấp. Bạn cần một SSH key trên máy local. Nếu chưa có, tạo trên máy của bạn (không phải trên VPS):
# Chạy trên MÁY LOCAL của bạn
ssh-keygen -t ed25519 -C "ten-cua-ban@local"
# Enter hết, nó tạo ~/.ssh/id_ed25519 (private) và id_ed25519.pub (public)
SSH vào VPS lần đầu bằng root để bắt đầu cấu hình:
ssh root@IP_CUA_VPS
Bước 1: Cập nhật hệ thống
Việc đầu tiên luôn là update để vá lỗ hổng và lấy bản package mới:
apt update && apt upgrade -y
Cài vài công cụ cơ bản sẽ dùng xuyên suốt:
apt install -y curl wget git ufw fail2ban htop unzip ca-certificates
Bước 2: Tạo user non-root có quyền sudo
Đăng nhập root trực tiếp là điều bot luôn nhắm tới. Tạo một user thường, cấp quyền sudo, rồi từ đó về sau làm việc bằng user này.
# Thay 'dev' bằng tên bạn muốn
adduser dev
usermod -aG sudo dev
Copy SSH public key của bạn sang user mới để đăng nhập không cần mật khẩu:
mkdir -p /home/dev/.ssh
# Dán nội dung file id_ed25519.pub vào dòng dưới
echo "ssh-ed25519 AAAA... ten-cua-ban@local" > /home/dev/.ssh/authorized_keys
chmod 700 /home/dev/.ssh
chmod 600 /home/dev/.ssh/authorized_keys
chown -R dev:dev /home/dev/.ssh
ssh dev@IP_CUA_VPS NGAY BÂY GIỜ, trước khi tắt đăng nhập mật khẩu ở bước sau. Nếu key chưa hoạt động mà bạn đã khóa password, bạn sẽ tự nhốt mình ra ngoài.Bước 3: Khóa SSH - chỉ dùng key, cấm root login
Sau khi chắc chắn user dev đăng nhập bằng key được, siết SSH. Mở file cấu hình:
sudo nano /etc/ssh/sshd_config
Chỉnh (hoặc thêm) các dòng sau:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
Lưu lại rồi khởi động lại dịch vụ SSH:
sudo systemctl restart ssh
Port 2222 vào sshd_config, nhớ mở cổng đó trên firewall ở bước sau và SSH bằng ssh -p 2222 dev@IP.Bước 4: Bật firewall UFW
UFW là firewall đơn giản trên Ubuntu. Logic: chặn hết, chỉ mở những cổng cần.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH # hoặc 'sudo ufw allow 2222' nếu đổi cổng
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
Kiểm tra trạng thái:
sudo ufw status verbose
Bước 5: Cài fail2ban chống brute-force
fail2ban đọc log, thấy IP nào thử sai mật khẩu nhiều lần thì ban tạm thời. Đã cài ở bước 1, giờ tạo file cấu hình riêng (không sửa file gốc để khỏi bị ghi đè khi update):
sudo nano /etc/fail2ban/jail.local
Nội dung cơ bản cho SSH:
[sshd]
enabled = true
port = ssh
maxretry = 3
bantime = 3600
findtime = 600
Bật và khởi động:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Bước 6: Tạo swap file
VPS RAM nhỏ (1-2GB) dễ bị OOM khi build Docker image hoặc chạy nhiều container. Swap là phao cứu sinh. Tạo 2GB swap:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# Cho swap tự bật lại sau khi reboot
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Giảm swappiness để hệ thống ưu tiên RAM, chỉ dùng swap khi gần hết:
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Bước 7: Cài Docker và Docker Compose
Cài Docker từ repo chính thức để có bản mới nhất. Đăng nhập bằng user dev:
# Thêm GPG key chính thức của Docker
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Thêm repo Docker
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Cho user dev chạy Docker không cần sudo:
sudo usermod -aG docker dev
# Đăng xuất rồi đăng nhập lại để nhóm có hiệu lực, hoặc:
newgrp docker
Kiểm tra:
docker run --rm hello-world
docker compose version
-p 127.0.0.1:8080:8080 thay vì -p 8080:8080. Hoặc đặt reverse proxy (Nginx/Caddy/Traefik) phía trước.Bước 8: Cài code-server (VS Code trên trình duyệt)
code-server cho bạn mở nguyên VS Code trong trình duyệt, code thẳng trên VPS từ bất kỳ máy nào, kể cả iPad. Cài bằng script chính thức:
curl -fsSL https://code-server.dev/install.sh | sh
Chạy như một service systemd cho user dev:
sudo systemctl enable --now code-server@dev
Lấy mật khẩu tự sinh trong file config:
cat ~/.config/code-server/config.yaml
Mặc định code-server chỉ nghe ở 127.0.0.1:8080 - tốt cho bảo mật. Đừng mở thẳng cổng 8080 ra internet. Cách an toàn để truy cập từ máy local là SSH tunnel:
# Chạy trên MÁY LOCAL
ssh -L 8080:127.0.0.1:8080 dev@IP_CUA_VPS
# Rồi mở trình duyệt vào http://localhost:8080
Nếu muốn truy cập qua domain với HTTPS, đặt Caddy làm reverse proxy. Caddy tự xin cert Let's Encrypt:
# Cài Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy
Cấu hình /etc/caddy/Caddyfile:
code.tenmien.com {
reverse_proxy 127.0.0.1:8080
}
sudo systemctl reload caddy
Nhớ trỏ DNS code.tenmien.com về IP VPS và mở cổng 80, 443 trên UFW (đã làm ở bước 4).
Bước 9: Terminal đẹp với Tabby (hoặc cấu hình shell ngon)
Tabby là một terminal emulator đẹp, cài trên máy local (Windows/Mac/Linux), không phải trên VPS. Bạn lưu profile SSH vào Tabby để kết nối VPS một cú click, có sẵn split pane, sync settings, hỗ trợ SSH key. Tải tại tabby.sh.
Còn trên VPS, để gõ lệnh sướng hơn, cài Zsh + Oh My Zsh:
sudo apt install -y zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Thêm plugin auto-suggestion để terminal gợi ý lệnh từ lịch sử:
git clone https://github.com/zsh-users/zsh-autosuggestions \
${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
# Mở ~/.zshrc, thêm zsh-autosuggestions vào dòng plugins=(...)
Bước 10: Tự động cập nhật bảo mật và sao lưu
Server dựng xong không phải là xong mãi mãi. Lỗ hổng mới xuất hiện liên tục. Bật cập nhật bảo mật tự động để không phải nhớ:
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Chọn "Yes" để bật. Hệ thống sẽ tự cài các bản vá bảo mật quan trọng. Với những app trong Docker, nhớ định kỳ docker compose pull rồi docker compose up -d để lấy image mới đã vá lỗi.
Về sao lưu, nguyên tắc vàng: chưa test restore thì coi như chưa có backup. Một cách đơn giản là dump database và đẩy lên storage ngoài qua cron. Ví dụ backup Postgres trong container mỗi đêm:
# Thêm vào crontab: sudo crontab -e
0 3 * * * docker exec my_postgres pg_dump -U postgres mydb | gzip > /home/dev/backups/db-$(date +\%F).sql.gz
Theo dõi tài nguyên
VPS nhỏ dễ bị nghẽn khi container ngốn RAM/CPU. Vài lệnh quen thuộc để soi nhanh:
htop # tổng quan CPU, RAM, process
docker stats # tài nguyên từng container realtime
df -h # dung lượng đĩa còn lại
free -h # RAM và swap đang dùng
sudo journalctl -u code-server@dev -f # xem log code-server
Nếu thường xuyên chạm trần RAM, đó là tín hiệu nên nâng cấu hình VPS thay vì sống nhờ swap. Phần lớn nhà cung cấp cho nâng cấp gói mà giữ nguyên dữ liệu, không phải dựng lại từ đầu.
Checklist hoàn tất
| Hạng mục | Lệnh kiểm tra | Trạng thái mong muốn |
|---|---|---|
| User non-root | whoami |
dev (không phải root) |
| SSH key-only | Thử ssh root@IP |
Bị từ chối |
| Firewall | sudo ufw status |
active, chỉ mở cổng cần |
| fail2ban | sudo fail2ban-client status sshd |
Đang chạy |
| Swap | free -h |
Có dòng Swap 2GB |
| Docker | docker run --rm hello-world |
Chạy không cần sudo |
| code-server | systemctl status code-server@dev |
active (running) |
Kết luận
Quy trình này biến một VPS trắng thành workstation dev an toàn trong khoảng 20-30 phút. Ba thứ quan trọng nhất là: khóa SSH chỉ dùng key, bật firewall + fail2ban, và không phơi service nội bộ ra internet (dùng SSH tunnel hoặc reverse proxy). Làm đúng từ đầu thì bạn ngủ ngon, không lo log đầy bot dò mật khẩu.
Tốc độ trải nghiệm cũng phụ thuộc vào chất lượng VPS: ổ SSD NVMe build Docker image nhanh, RAM ECC ít lỗi, latency thấp khi bạn ngồi Việt Nam SSH vào. Nếu bạn đang chọn máy, xem thêm bài VPS cho vibe coder để biết cấu hình nào hợp với loại app của bạn.
Cần một con VPS chuẩn để chạy playbook này?
TND Cloud VPS SSD NVMe, RAM ECC, khởi tạo chỉ 60 giây, đặt tại Việt Nam latency thấp. Gói VPS 20 chỉ 199k/tháng (1vCPU/1GB/20GB) đủ cho code-server + vài container nhẹ; VPS 30 299k (2vCPU/2GB/30GB) thoải mái build Docker; VPS 50 639k (4vCPU/4GB/50GB) cho dự án nặng hơn.

