Cách gọn gàng nhất để cài Docker trên VPS là dùng repository apt chính thức của Docker, thay vì gói docker.io của bản phân phối hay script cài đặt một dòng. Bạn sẽ có Docker Engine bản mới, plugin Compose và được cập nhật qua apt upgrade như mọi gói khác. Bài này hướng dẫn cài trên Ubuntu và Debian, chạy stack Compose đầu tiên, rồi đi vào phần mà nhiều hướng dẫn bỏ qua: mặc định các cổng container được publish sẽ đi vòng qua ufw, có thể làm lộ những dịch vụ bạn tưởng đã được firewall chặn.
Hãy bắt đầu từ một máy chủ đã được gia cố. Nếu máy còn mới tinh, hãy làm checklist bảo mật VPS trong giờ đầu tiên trước, và xem hướng dẫn các vị trí VPS nếu bạn vẫn đang chọn khu vực.
Cần chuẩn bị gì để cài Docker trên VPS
- Một VPS Linux chạy bản Ubuntu LTS hoặc Debian stable hiện hành. Danh sách hệ điều hành theo từng vị trí có trong console Cloudj.
- Một user có quyền
sudovà đăng nhập bằng SSH key. Xem bài tạo SSH key cho VPS nếu cần. - Đủ bộ nhớ cho các container. Bản thân Docker Engine khá nhẹ, ứng dụng của bạn mới quyết định cấu hình. Một stack thử nghiệm nhỏ chạy được trên các gói thấp nhất, và bạn có thể nâng CPU, RAM sau khi tải tăng lên.
Bước 1: gỡ các gói xung đột
Các gói của bản phân phối như docker.io hay podman-docker xung đột với gói chính thức của Docker. Hãy gỡ những gói đang có; apt sẽ báo các gói chưa được cài, điều đó không sao:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove -y $pkg; done
Lệnh này không xóa image và volume đang có trong /var/lib/docker/.
Bước 2: thêm repository chính thức của Docker
Các lệnh dưới đây chạy được trên cả Ubuntu lẫn Debian, vì chúng đọc tên bản phân phối và codename từ /etc/os-release. Chúng không dùng được trên các bản dẫn xuất như Linux Mint; với những bản đó, hãy làm theo hướng dẫn của bản phân phối gốc tương ứng.
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
. /etc/os-release
sudo curl -fsSL https://download.docker.com/linux/$ID/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$ID $VERSION_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
Repository được ký số, và tùy chọn signed-by giới hạn key đó chỉ dùng cho repository này. Nếu apt-get update báo không tìm thấy codename của bạn, hãy xem danh sách phiên bản được hỗ trợ trong hướng dẫn cài Docker Engine cho Ubuntu và bản dành cho Debian.
Bước 3: cài Docker Engine và Compose
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Trên Ubuntu và Debian, dịch vụ tự khởi động và được bật cùng hệ thống. Kiểm tra lại:
sudo systemctl status docker --no-pager
sudo docker run --rm hello-world
docker compose version
Lưu ý Compose giờ là một plugin, gọi bằng docker compose có dấu cách ở giữa. Bạn không cần binary docker-compose kiểu cũ nữa.
Bước 4: chọn cách chạy lệnh docker
Mặc định chỉ root mới giao tiếp được với Docker daemon. Bạn có thể thêm user của mình vào nhóm docker:
sudo usermod -aG docker $USER
Đăng xuất rồi đăng nhập lại để nhóm có hiệu lực. Hãy hiểu rõ điều này: thuộc nhóm docker gần như tương đương quyền root, vì user có thể chạy một container mount toàn bộ hệ thống file của máy chủ. Với máy chủ chỉ một người quản trị thì thường chấp nhận được. Với máy dùng chung, hãy tiếp tục dùng sudo docker hoặc tìm hiểu chế độ rootless của Docker.
Bước 5: thiết lập mặc định hợp lý cho daemon
Hai thiết lập sẽ giúp bạn đỡ rắc rối về sau. Log của container mặc định tăng không giới hạn và có thể làm đầy ổ đĩa nhỏ, còn các cổng publish sẽ bind vào mọi interface nếu bạn không chỉ định. Tạo file /etc/docker/daemon.json:
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" },
"ip": "127.0.0.1"
}
EOF
sudo systemctl restart docker
Thiết lập ip khiến -p 8080:80 bind vào 127.0.0.1, trừ khi bạn ghi rõ một địa chỉ khác. Giới hạn log chỉ áp dụng cho container tạo sau thay đổi; hãy tạo lại các container cũ để chúng nhận cấu hình mới.
Bước 6: chạy stack đầu tiên với Docker Compose
Tạo thư mục dự án và file compose.yaml:
mkdir -p ~/apps/hello && cd ~/apps/hello
cat > compose.yaml <<'EOF'
services:
web:
image: nginx:stable
ports:
- "127.0.0.1:8080:80"
restart: unless-stopped
EOF
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080
Bạn sẽ nhận được header HTTP/1.1 200 OK từ nginx. Một số lệnh hữu ích tiếp theo: docker compose logs -f để theo dõi log, docker compose pull && docker compose up -d để cập nhật image, và docker compose down để dừng và gỡ stack.
Bẫy firewall giữa Docker và ufw
Đây là phần quan trọng nhất. ufw lọc lưu lượng ở chain INPUT của máy chủ. Khi bạn publish một cổng, Docker tự thêm các rule iptables chuyển tiếp lưu lượng vào container trước khi rule của ufw kịp xét. Hệ quả: bạn chạy sudo ufw deny 5432, publish -p 5432:5432 cho cơ sở dữ liệu, và database vẫn truy cập được từ internet.
Các cách giữ an toàn, từ đơn giản đến phức tạp:
- Chỉ publish trên localhost. Ghi cổng dạng
127.0.0.1:8080:80, hoặc dựa vào thiết lập mặc định"ip": "127.0.0.1"ở trên. Sau đó đặt một reverse proxy ở cổng 80 và 443 phía trước. Bài cấu hình nginx reverse proxy kèm SSL hướng dẫn chi tiết. - Không publish các dịch vụ nội bộ. Các container trong cùng network của Compose gọi nhau bằng tên service, nên database thường không cần mục
ports:nào cả. - Lọc trong chain DOCKER-USER. Docker dành chain iptables này cho rule của bạn, được xét trước các rule chuyển tiếp của Docker. Cách này hiệu quả nhưng cần cẩn thận, và rule phải được lưu lại để còn sau khi reboot.
Hãy kiểm tra từ bên ngoài, đừng kiểm tra ngay trên máy chủ. Từ máy tính của bạn, thử kết nối tới một cổng lẽ ra phải đóng:
nc -vz 203.0.113.10 5432
Kết quả timeout hoặc bị từ chối là điều bạn mong muốn. Trên máy chủ, sudo ss -tlnp liệt kê mọi socket đang lắng nghe và địa chỉ mà nó bind vào. Xem bài cấu hình firewall ufw cho VPS để viết rule cho chính máy chủ.
Cập nhật Docker
Các gói Docker được cập nhật qua apt như mọi gói khác:
sudo apt-get update && sudo apt-get upgrade
Trên Ubuntu và Debian, unattended upgrades mặc định chỉ cài bản cập nhật bảo mật từ bản phân phối, không lấy từ repository của Docker, nên bạn cần lên lịch cập nhật thủ công. Image là chuyện riêng: hãy pull bản mới và tạo lại container định kỳ, rồi dọn image không dùng bằng docker image prune.
Câu hỏi thường gặp
Có nên dùng gói docker.io của Ubuntu cho nhanh không?
Gói đó vẫn chạy được, nhưng thường chậm hơn bản gốc và đóng gói Compose theo cách khác. Repository chính thức cho bạn bản mới nhất và plugin docker compose mà phần lớn tài liệu hiện nay mặc định.
Vì sao container vẫn truy cập được dù ufw đã chặn cổng?
Rule iptables của Docker cho các cổng publish được xét trước rule của ufw. Hãy bind cổng vào 127.0.0.1, bỏ mục ports: hoặc lọc trong chain DOCKER-USER.
Docker trên VPS cần bao nhiêu RAM?
Bản thân Docker dùng rất ít, các container mới là phần quyết định. Hãy theo dõi bộ nhớ trong phần số liệu của console và nâng cấu hình khi thường xuyên chạm ngưỡng.
Cài Docker trên Windows VPS được không?
Bài này chỉ nói về Linux. Để chạy container trên máy chủ, image Linux là lựa chọn đơn giản và phổ biến hơn.
Triển khai và bắt đầu xây dựng
Hãy triển khai một máy chủ Ubuntu hoặc Debian từ console Cloudj, làm theo các bước trên và stack Compose đầu tiên của bạn sẽ sớm chạy. Bạn có thể so sánh các vị trí trên trang máy chủ cloud, xem giá trực tiếp trên trang bảng giá và nạp tiền bằng chuyển khoản VND.