Sự cố thường gặp
| Triệu chứng | Nguyên nhân thường gặp | Cách kiểm tra / xử lý |
|---|---|---|
docker compose up chạy nhầm code cũ | Dùng nhầm docker-compose.yml (dev) thay vì docker-compose.prod.yml | Luôn chỉ định rõ -f docker-compose.prod.yml |
| Backend crash-loop lúc start | Sai DATABASE_URL/POSTGRES_PASSWORD, hoặc migration lỗi | docker compose -f docker-compose.prod.yml logs backend |
Ngay sau deploy/rollback/restore, web trả 502 (Cloudflare) dù backend healthy; log nginx có connect() failed (111: Connection refused) while connecting to upstream | nginx giữ IP của container backend/frontend cũ (chỉ phân giải tên lúc khởi động, không được tạo lại khi chỉ đổi image). Các script từ v1.2.1 đã tự reload nginx | docker compose -f docker-compose.prod.yml exec nginx nginx -s reload (hoặc restart nginx) |
Backend crash-loop, log 0041_gold_gem_currencies stopped: unsupported currency rows found | Còn dữ liệu dùng mã tiền tệ khác GOLD/GEM (thiết kế cố ý dừng) | Xử lý từng dòng trong danh sách theo §8.5, rồi restart backend |
Backend không khởi động, lỗi PUBLIC_ASSET_BASE_URL must be an absolute https:// URL hoặc SERVE_MEDIA_LOCALLY must be false | Thiếu biến Phase N trong .env | Thêm 3 biến ở §3.1 |
Upload ảnh báo lỗi 500, log Permission denied: '/data/media/...' | Volume ảnh tạo trước khi image có chown, đang thuộc root | Lệnh chown ở §8.4 bước 2 |
Icon trong game không hiện, curl /media/... trả 404 | Nginx chưa có location /media/ (deploy thiếu nginx/ mới) hoặc chưa mount volume ảnh | Đối chiếu nginx/nginx.conf.template và docker-compose.prod.yml, docker compose ... restart nginx |
/guide/ trả 404 hoặc có shell nhưng thiếu nội dung | Gói deploy thiếu guide-site/, build chưa được copy hoặc thư mục mount sai | Kiểm tra /opt/web_admin/guide-site/index.html, volume ./guide-site:/usr/share/nginx/guide:ro, rồi đóng gói/copy lại và restart nginx |
/guide/ chuyển về /login liên tục dù vừa đăng nhập | Cookie access_token không được gửi tới /guide/ (path/domain/Secure) hoặc phiên đã hết hạn | Dùng HTTPS cùng host Portal, kiểm tra cookie có Path=/, đăng nhập lại; sau login mở lại /guide/ vì next chưa tự tiếp tục |
| Sản phẩm có trong Shop nhưng không hiện trong cửa hàng của game | Sản phẩm đang để “Không bán” (Phase R), vật phẩm chưa có icon (cửa hàng tự ẩn), sản phẩm chưa published, hoặc là sản phẩm tiền thật khi flag iap tắt | Portal → Shop (bật bán, thêm icon, publish) / Feature flags |
Game nhận 422 khi kết thúc màn (/runs/{id}/finish) | App dùng SDK cũ hơn v0.3.0, không gửi result.duration_ms | Nâng SDK lên v0.3.0 (§13) |
/sync trả 409 server_authoritative_mode | Game đã chuyển chế độ server nhưng app còn gửi số dư kiểu cũ | Bình thường với app cũ — gate cập nhật sẽ chặn; app mới không gọi /sync số dư |
Mua tiền thật trả 403 iap_disabled | Flag iap của game đang tắt | §8.5 “Bật IAP” |
Mua tiền thật trả 409 account_mismatch | Token mua thuộc tài khoản người chơi khác | Bình thường (chống dùng lại token); app phải mua bằng đúng player_uid |
rollback_to_version.sh từ chối, báo migration | Image cũ không có migration DB đang ở; qua Phase O thì 0043–0045 không lùi được, qua Phase Q/R thì 0051/0052 từ chối downgrade | §7 “Migration không lùi được”: restore backup trước deploy |
Backup báo không đủ dung lượng | Đĩa chứa /opt/backups còn ít hơn max(2 × bản gần nhất, 1 GiB) | Dọn hoặc tăng đĩa; ./scripts/backup_database.sh --dry-run để xem các bản sẽ bị dọn |
Backup/restore báo backup lock timeout | Một backup hoặc restore khác đang giữ /opt/backups/.lock quá 30 phút | Chờ job kia xong (ps aux | grep -E "backup|restore"), rồi chạy lại |
restore.sh báo Required backend image ... is not loaded (hoặc frontend) | Image ghi trong manifest không còn trên máy | load_images.sh đúng version đó, hoặc truyền --backend-image/--frontend-image |
restore.sh báo FAILED khi kiểm SHA256, hoặc archive structure validation failed | File backup đã chọn bị hỏng/bị sửa, hoặc sai khóa age | Chưa có gì thay đổi; chọn bản khác (--db-file hoặc thư mục ngày khác), kiểm lại BACKUP_AGE_IDENTITY_FILE |
restore.sh báo Row-count differences hoặc Alembic revision mismatch | Dump restore ra không khớp manifest | App vẫn tắt, DB đang dở dang; restore bản khác |
| Nginx không lên được, báo lỗi thiếu cert | Chưa chạy init_letsencrypt.sh, hoặc chạy khi DNS chưa trỏ đúng | Kiểm tra dig portal.tinysoft.io.vn trỏ đúng IP VPS trước khi chạy lại |
curl từ máy ngoài báo Connection refused ở port 80/443 dù container đang chạy và ss -tlnp trên VPS thấy có LISTEN | Firewall tầng cloud (Security Group/NSG/Firewall rules) chưa mở port 80/443 — mặc định nhiều provider chỉ mở sẵn port 22 | Vào console nhà cung cấp cloud, kiểm tra inbound rules; xem §1 |
Certbot báo too many failed authorizations (5) for "<domain>" | Đã thử xin cert nhiều lần thất bại trong 1 giờ cho cùng domain (thường do thử lại khi port 80 chưa mở) — giới hạn tính theo domain, đổi email không giúp gì | Đợi đúng thời điểm ghi trong thông báo lỗi (retry after ...) rồi thử lại |
Certbot báo live directory exists for <domain> khi chạy lại | Thư mục /etc/letsencrypt/live/<domain> từ lần chạy trước (dummy cert hoặc lần fail trước) chưa được dọn sạch | Xóa live/, archive/, renewal/<domain>.conf trước khi chạy lại certonly — xem cuối §4 |
| Trình duyệt báo cảnh báo chứng chỉ | Domain trong .env (DOMAIN) không khớp domain thật đang truy cập | Đối chiếu lại .env và DNS |
| Cookie không được set khi đăng nhập | COOKIE_SECURE=true nhưng đang truy cập qua http:// thay vì https:// | Luôn test qua domain HTTPS thật, không test qua IP/http |
docker compose ... down -v | Không bao giờ chạy lệnh này trên production — xóa volume certbot_certs (gây rate-limit Let’s Encrypt khi xin lại), admin_portal_pgdata_prod (mất toàn bộ dữ liệu) và admin_portal_media_prod (mất toàn bộ ảnh) | — |
export_images.sh/deploy_local.sh báo “Image … not found” | Chưa build image đúng tag đã khai trong docker-compose.prod.yml (máy dev), hoặc chưa load_images.sh (VPS) | docker images | grep admin_portal, đối chiếu tag với docker-compose.prod.yml |
App game nhận 401 khi link, log backend identity verification failed | Game chưa cấu hình OAuth web client Play Games trên Portal (§8.1 bước 4), hoặc app build thiếu PLAY_GAMES_WEB_CLIENT_ID | Game Registry → biểu tượng khiên phải ở trạng thái “Đã cấu hình”; kiểm tra env/prod.json của app |
App game nhận 404 ở mọi request /api/v2/... | Portal trên VPS còn là bản trước Phase K | Kiểm tra version ở §5; deploy bản mới trước khi phát hành app |
/sync trả 422 currency_not_syncable | Tiền app gửi lên không bật “Đồng bộ từ app” trên Portal | Portal → Tiền tệ của game đó |
| Đổi remote config / bảo trì / Catalog nhưng app chưa thấy | bootstrap và cửa hàng cache 30 giây trong mỗi worker | Chờ 30 giây rồi mở lại app |
Chạy ./scripts/create_super_admin.py báo Permission denied, chmod +x báo Operation not permitted | Script được COPY vào image trước dòng USER appuser trong Dockerfile nên thuộc sở hữu user build (root); container production không có sudo, appuser không đủ quyền tự cấp bit thực thi | Không chạy trực tiếp bằng ./; luôn gọi qua python scripts/create_super_admin.py ... như §6 |
Áp dụng cho Portal v1.2.2