[{"data":1,"prerenderedAt":1830},["ShallowReactive",2],{"search-posts-dataset":3,"post-detail-/posts/docker-compose-production":159,"all-published-articles-list":1766,"series-posts-/posts/docker-compose-production":1826},[4,20,35,48,62,75,87,99,111,122,135,149],{"path":5,"title":6,"description":7,"categories":8,"tags":11,"date":16,"image":17},"/posts/incident-checklist","Checklist xử lí sự cố máy chủ Linux: Phục hồi sau thảm họa","Qui trình phản ứng và xử lí sự cố máy chủ Linux khi hệ thống bị sập, tràn RAM/HDD hoặc nghi ngờ bị xâm nhập: Các bước chuẩn đoán, cô lập, phân tích log và khôi phục.",[9,10],"linux","devops",[12,13,14,15],"incident","troubleshooting","security","sysadmin","2026-08-15T00:00:00.000Z",{"src":18,"alt":19},"/img/incident-response.webp","Xử lí sự cố máy chủ Linux",{"path":21,"title":22,"description":23,"categories":24,"tags":27,"date":31,"image":32},"/posts/backup-postgres-docker","Sao lưu tự động PostgreSQL trong Docker với cron job và gzip","Hướng dẫn xây dựng script tự động backup database PostgreSQL chạy trong Docker container: gzip, cron hàng ngày, tự động xóa bản sao lưu cũ và kiểm thử phục hồi.",[25,26],"docker","database",[28,29,30,10],"postgresql","backup","automation","2025-10-20T00:00:00.000Z",{"src":33,"alt":34},"/img/postgres-backup.webp","Sao lưu tự động PostgreSQL Docker",{"path":36,"title":37,"description":38,"categories":39,"tags":40,"date":44,"image":45},"/posts/docker-compose-production","Thiết kế Docker compose chuẩn Production","Hướng dẫn thực chiến xây dựng docker-compose.yml hoàn chỉnh cho Production: healthchecks, restart policies, resource limits, quản lí .env và Persistent Volumes",[25,10],[41,42,43],"production","compose","backend","2025-10-15T00:00:00.000Z",{"src":46,"alt":47},"/img/docker-compose.webp","Docker Compose Production Best Practices",{"path":49,"title":50,"description":51,"categories":52,"tags":53,"date":58,"image":59},"/posts/monitoring-server-basics","Giám sát server Linux từ cơ bản đến nâng cao: htop, ncdu, prometheus và Uptime Kuma","Cẩm nang toàn diện về giám sát hiệu năng máy chủ Linux: Khai thác công cụ CLI thời gian thực (Htop, Btop, Ncdu), thiết lập hệ thống cảnh báo sự cố Uptime Kuma qua Telegram và thu thập chỉ số với Prometheus & Grafana.",[9,10],[54,55,56,57],"monitoring","grafana","prometheus","uptime","2024-10-18T00:00:00.000Z",{"src":60,"alt":61},"/img/monitoring.webp","Giám sát máy chủ Linux",{"path":63,"title":64,"description":65,"categories":66,"tags":68,"date":71,"image":72},"/posts/nginx-reverse-proxy","Hướng dẫn cấu hình Nginx Reverse Proxy với SSL Certbot và Docker chuẩn Production","Cẩm nang toàn diện cấu hình Nginx Reverse Proxy trên Ubuntu: Tích hợp chứng chỉ SSL Let's Encrypt miễn phí qua Certbot, hỗ trợ WebSockets, HTTP/2, nén Brotli/Gzip và Rate Limiting chống DDoS.",[9,67],"nginx",[10,69,70],"ssl","webserver","2024-10-10T00:00:00.000Z",{"src":73,"alt":74},"/img/nginx.webp","Nginx Reverse Proxy với SSL",{"path":76,"title":77,"description":78,"categories":79,"tags":80,"date":83,"image":84},"/posts/how-to-secure-a-vps","Bảo mật máy chủ Linux VPS: Cẩm nang toàn diện 8 bước chống tấn công","Hướng dẫn thực chiến từng bước thiết lập bảo mật máy chủ Linux VPS mới: Vô hiệu hóa mật khẩu SSH, thiết lập SSH Key Ed25519, cấu hình Fail2ban, tường lửa UFW và cập nhật tự động Unattended-Upgrades.",[9,14],[81,82,10],"vps","hardening","2024-10-05T00:00:00.000Z",{"src":85,"alt":86},"/img/linux-security.webp","Bảo mật máy chủ Linux VPS",{"path":88,"title":89,"description":90,"categories":91,"tags":92,"date":95,"image":96},"/posts/systemd-node-service","Quản lí ứng dụng Node.js trong Production với Systemd Service và Journalctl","Hướng dẫn triển khai ứng dụng Node.js, Go hoặc Python dưới dạng Systemd Service trên Linux: Tự động khởi động lại khi crash, quản lý biến môi trường, giới hạn bộ nhớ RAM và theo dõi log thời gian thực với Journalctl.",[9,10],[93,94,43,41],"systemd","nodejs","2024-10-01T00:00:00.000Z",{"src":97,"alt":98},"/img/systemd.webp","Quản lý ứng dụng với Systemd Service",{"path":100,"title":101,"description":102,"categories":103,"tags":104,"date":107,"image":108},"/posts/how-to-install-docker-on-ubuntu-server","Hướng dẫn cài đặt Docker & Docker compose trên Ubuntu server","Hướng dẫn toàn diện cách cài đặt Docker Engine và Docker Compose V2 trên Ubuntu Server, cấu hình bảo mật non-root user, tối ưu daemon và xử lí xung đột tường lửa UFW",[9,25],[105,10,106],"beginner","ubuntu","2024-09-30T00:00:00.000Z",{"src":109,"alt":110},"/img/docker.webp","Cài đặt Docker trên Ubuntu Server",{"path":112,"title":113,"description":114,"categories":115,"tags":116,"date":118,"image":119},"/posts/ssh-key-authentication","Xác thực SSH Key từ cơ bản đến nâng cao: Ed25519, SSH Config và Bảo mật đa tầng","Cẩm nang toàn diện về xác thực SSH Key trên máy chủ Linux: So sánh Ed25519 vs RSA, cấu hình SSH Config quản lí hàng chục VPS, chuyển tiếp Agent Forwarding, và các qui tắc bảo mật chống lộ khóa.",[9,14],[117,10,15],"ssh","2024-09-25T00:00:00.000Z",{"src":120,"alt":121},"/img/ssh-keys.webp","Xác thực SSH Key Linux",{"path":123,"title":124,"description":125,"categories":126,"tags":127,"date":131,"image":132},"/posts/ufw-firewall-basics","Làm chủ tường lửa UFW trên Linux: Qui tắc, giới hạn kết nối và xử lí xung đột Docker","Hướng dẫn toàn diện làm chủ tường lửa UFW (Uncomplicated Firewall) trên Ubuntu: Thiết lập chính sách mặc định, mở cổng theo IP, giới hạn brute-force (Rate Limiting) và khắc phục lỗi Docker bypass tường lửa.",[9,14],[128,129,130,15],"ufw","firewall","networking","2024-09-20T00:00:00.000Z",{"src":133,"alt":134},"/img/ufw-firewall.webp","Cấu hình Tường lửa UFW Linux",{"path":136,"title":137,"description":138,"categories":139,"tags":141,"date":145,"image":146},"/posts/git-deploy-key","Tự động hóa triển khai với Git deploy keys: Thiết lập an toàn cho GitHub và GitLab","Hướng dẫn thiết lập Git Deploy Key chuẩn bảo mật để kéo mã nguồn tự động từ GitHub hoặc GitLab về máy chủ Production: Phân quyền Read-Only, cấu hình SSH Config và tích hợp Webhook tự động cập nhật.",[140,10],"git",[142,143,144,30],"github","gitlab","cicd","2024-09-18T00:00:00.000Z",{"src":147,"alt":148},"/img/git-deploy.webp","Git Deploy Keys cho máy chủ",{"path":150,"title":151,"description":152,"categories":153,"tags":154,"date":155,"image":156},"/posts/ubuntu-server-initial-setup","Qui trình thiết lập ban đầu cho Ubuntu Server: Swap, Timezone, User và Firewall","Hướng dẫn các bước thiết lập chuẩn mực ban đầu cho máy chủ Ubuntu Server mới: Cấu hình múi giờ Việt Nam (Asia/Ho_Chi_Minh), tạo phân vùng RAM ảo (Swap File), phân quyền Sudoer và kích hoạt tường lửa UFW.",[9],[106,105,15],"2024-09-15T00:00:00.000Z",{"src":157,"alt":158},"/img/ubuntu.webp","Thiết lập ban đầu Ubuntu Server",{"id":160,"title":37,"author":161,"body":162,"categories":1754,"date":44,"description":38,"draft":1755,"extension":1756,"image":1757,"meta":1758,"navigation":274,"path":36,"seo":1759,"series":1760,"series_order":271,"slug":1761,"stem":1762,"tags":1763,"updated":1764,"__hash__":1765},"post/posts/docker-compose-production.md","Dương Thụ",{"type":163,"value":164,"toc":1740},"minimal",[165,170,179,191,207,213,216,220,223,233,235,239,245,1348,1350,1354,1359,1371,1375,1390,1417,1433,1437,1440,1458,1462,1473,1519,1522,1524,1528,1535,1568,1571,1603,1619,1621,1625,1628,1727,1729,1733,1736],[166,167,169],"h2",{"id":168},"giới-thiệu-chuyển-dịch-từ-development-sang-production-với-docker-compose","Giới thiệu: Chuyển dịch từ Development sang Production với Docker Compose",[171,172,173,174,178],"p",{},"Docker Compose là công cụ tuyệt vời giúp khởi chạy cụm ứng dụng đa container (Multi-container Architecture) chỉ bằng một lệnh duy nhất: ",[175,176,177],"code",{},"docker compose up -d",".",[171,180,181,182,185,186,190],{},"Tuy nhiên, một file ",[175,183,184],{},"docker-compose.yml"," viết cho môi trường phát triển (Local Development) ",[187,188,189],"strong",{},"hoàn toàn khác biệt"," so với một file được thiết kế để vận hành thực tế trên máy chủ Production. Trong môi trường Production, bạn phải đối mặt với các bài toán:",[192,193,194,198,201,204],"ul",{},[195,196,197],"li",{},"Làm sao để container tự phục hồi khi bị crash?",[195,199,200],{},"Làm sao ngăn một container bị rò rỉ bộ nhớ (Memory Leak) làm sập toàn bộ máy chủ VPS?",[195,202,203],{},"Làm sao đảm bảo cơ sở dữ liệu (Database) đã sẵn sàng trước khi ứng dụng backend cố gắng kết nối?",[195,205,206],{},"Làm sao để dữ liệu không bao giờ bị mất mát khi container bị xóa bỏ hoặc cập nhật bản mới?",[171,208,209,210,178],{},"Bài viết này sẽ hướng dẫn bạn thiết kế một cấu trúc Docker Compose hoàn chỉnh chuẩn Production cho một hệ thống Web điển hình gồm: ",[187,211,212],{},"Node.js API + PostgreSQL + Redis Cache",[214,215],"hr",{},[166,217,219],{"id":218},"_1-cấu-trúc-thư-mục-dự-án-chuẩn-hóa","1. Cấu trúc thư mục dự án chuẩn hóa",[171,221,222],{},"Một cấu trúc thư mục rõ ràng giúp việc quản trị và sao lưu trở nên thuận tiện hơn bao giờ hết:",[224,225,231],"pre",{"className":226,"code":228,"language":229,"meta":230},[227],"language-text","/opt/my-app/\n├── .env.example          # Mẫu biến môi trường (cam kết vào Git)\n├── .env.production       # Biến môi trường bảo mật thực tế (KHÔNG cam kết vào Git)\n├── docker-compose.yml    # File compose chính\n├── nginx/\n│   └── default.conf      # File cấu hình proxy\n└── backups/              # Thư mục lưu trữ backup định kỳ\n","text","",[175,232,228],{"__ignoreMap":230},[214,234],{},[166,236,238],{"id":237},"_2-file-docker-compose-hoàn-chỉnh-chuẩn-production","2. File Docker Compose hoàn chỉnh chuẩn Production",[171,240,241,242,244],{},"Dưới đây là file ",[175,243,184],{}," mẫu đã được áp dụng toàn bộ các tiêu chuẩn vận hành tốt nhất:",[224,246,250],{"className":247,"code":248,"language":249,"meta":230,"style":230},"language-yaml shiki shiki-themes github-dark github-dark github-dark","version: '3.8'\n\nservices:\n  # ==========================================\n  # 1. Backend Application Service (Node.js)\n  # ==========================================\n  api:\n    image: my-company/backend:v1.4.2\n    container_name: production_api\n    restart: unless-stopped\n    env_file:\n      - .env.production\n    environment:\n      - NODE_ENV=production\n      - PORT=3000\n    depends_on:\n      db:\n        condition: service_healthy\n      redis:\n        condition: service_healthy\n    networks:\n      - app_network\n    # Chỉ bind cổng vào localhost nội bộ (Nginx Reverse Proxy sẽ kết nối tới đây)\n    ports:\n      - \"127.0.0.1:3000:3000\"\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:3000/health\"]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 40s\n    deploy:\n      resources:\n        limits:\n          cpus: '1.5'\n          memory: 1024M\n        reservations:\n          cpus: '0.25'\n          memory: 256M\n    logging:\n      driver: \"json-file\"\n      options:\n        max-size: \"10m\"\n        max-file: \"3\"\n\n  # ==========================================\n  # 2. Database Service (PostgreSQL 16)\n  # ==========================================\n  db:\n    image: postgres:16-alpine\n    container_name: production_postgres\n    restart: unless-stopped\n    env_file:\n      - .env.production\n    environment:\n      POSTGRES_DB: ${DB_NAME}\n      POSTGRES_USER: ${DB_USER}\n      POSTGRES_PASSWORD: ${DB_PASSWORD}\n    volumes:\n      - pgdata:/var/lib/postgresql/data\n    networks:\n      - app_network\n    # Không mở port ra ngoài Internet, chỉ giao tiếp nội bộ trong mạng app_network\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U ${DB_USER} -d ${DB_NAME}\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n      start_period: 15s\n    deploy:\n      resources:\n        limits:\n          cpus: '2.0'\n          memory: 2048M\n    logging:\n      driver: \"json-file\"\n      options:\n        max-size: \"10m\"\n        max-file: \"3\"\n\n  # ==========================================\n  # 3. In-memory Cache Service (Redis 7)\n  # ==========================================\n  redis:\n    image: redis:7-alpine\n    container_name: production_redis\n    restart: unless-stopped\n    command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes\n    volumes:\n      - redisdata:/data\n    networks:\n      - app_network\n    healthcheck:\n      test: [\"CMD\", \"redis-cli\", \"-a\", \"${REDIS_PASSWORD}\", \"ping\"]\n      interval: 10s\n      timeout: 5s\n      retries: 3\n      start_period: 5s\n    deploy:\n      resources:\n        limits:\n          cpus: '0.5'\n          memory: 512M\n    logging:\n      driver: \"json-file\"\n      options:\n        max-size: \"5m\"\n        max-file: \"2\"\n\n# ==========================================\n# Persistent Volumes (Dữ liệu bền vững)\n# ==========================================\nvolumes:\n  pgdata:\n    name: production_pgdata\n  redisdata:\n    name: production_redisdata\n\n# ==========================================\n# Isolated Network (Mạng nội bộ cách ly)\n# ==========================================\nnetworks:\n  app_network:\n    name: production_network\n    driver: bridge\n","yaml",[175,251,252,269,276,285,292,298,303,311,322,333,344,352,361,369,377,385,393,401,412,420,429,437,445,451,459,467,475,506,517,528,540,551,559,567,575,586,597,605,615,625,633,644,652,663,674,679,684,690,695,703,713,723,732,739,746,753,764,775,786,794,802,809,816,822,829,846,855,865,875,885,892,899,906,916,926,933,942,949,958,967,972,977,983,988,996,1006,1016,1025,1036,1043,1051,1058,1065,1072,1103,1112,1121,1130,1139,1146,1153,1160,1170,1180,1187,1196,1203,1213,1223,1228,1234,1240,1245,1253,1261,1272,1280,1290,1295,1300,1306,1311,1319,1327,1337],{"__ignoreMap":230},[253,254,257,261,265],"span",{"class":255,"line":256},"line",1,[253,258,260],{"class":259},"sRcpU","version",[253,262,264],{"class":263},"sFJ4l",": ",[253,266,268],{"class":267},"skqr8","'3.8'\n",[253,270,272],{"class":255,"line":271},2,[253,273,275],{"emptyLinePlaceholder":274},true,"\n",[253,277,279,282],{"class":255,"line":278},3,[253,280,281],{"class":259},"services",[253,283,284],{"class":263},":\n",[253,286,288],{"class":255,"line":287},4,[253,289,291],{"class":290},"sGGCZ","  # ==========================================\n",[253,293,295],{"class":255,"line":294},5,[253,296,297],{"class":290},"  # 1. Backend Application Service (Node.js)\n",[253,299,301],{"class":255,"line":300},6,[253,302,291],{"class":290},[253,304,306,309],{"class":255,"line":305},7,[253,307,308],{"class":259},"  api",[253,310,284],{"class":263},[253,312,314,317,319],{"class":255,"line":313},8,[253,315,316],{"class":259},"    image",[253,318,264],{"class":263},[253,320,321],{"class":267},"my-company/backend:v1.4.2\n",[253,323,325,328,330],{"class":255,"line":324},9,[253,326,327],{"class":259},"    container_name",[253,329,264],{"class":263},[253,331,332],{"class":267},"production_api\n",[253,334,336,339,341],{"class":255,"line":335},10,[253,337,338],{"class":259},"    restart",[253,340,264],{"class":263},[253,342,343],{"class":267},"unless-stopped\n",[253,345,347,350],{"class":255,"line":346},11,[253,348,349],{"class":259},"    env_file",[253,351,284],{"class":263},[253,353,355,358],{"class":255,"line":354},12,[253,356,357],{"class":263},"      - ",[253,359,360],{"class":267},".env.production\n",[253,362,364,367],{"class":255,"line":363},13,[253,365,366],{"class":259},"    environment",[253,368,284],{"class":263},[253,370,372,374],{"class":255,"line":371},14,[253,373,357],{"class":263},[253,375,376],{"class":267},"NODE_ENV=production\n",[253,378,380,382],{"class":255,"line":379},15,[253,381,357],{"class":263},[253,383,384],{"class":267},"PORT=3000\n",[253,386,388,391],{"class":255,"line":387},16,[253,389,390],{"class":259},"    depends_on",[253,392,284],{"class":263},[253,394,396,399],{"class":255,"line":395},17,[253,397,398],{"class":259},"      db",[253,400,284],{"class":263},[253,402,404,407,409],{"class":255,"line":403},18,[253,405,406],{"class":259},"        condition",[253,408,264],{"class":263},[253,410,411],{"class":267},"service_healthy\n",[253,413,415,418],{"class":255,"line":414},19,[253,416,417],{"class":259},"      redis",[253,419,284],{"class":263},[253,421,423,425,427],{"class":255,"line":422},20,[253,424,406],{"class":259},[253,426,264],{"class":263},[253,428,411],{"class":267},[253,430,432,435],{"class":255,"line":431},21,[253,433,434],{"class":259},"    networks",[253,436,284],{"class":263},[253,438,440,442],{"class":255,"line":439},22,[253,441,357],{"class":263},[253,443,444],{"class":267},"app_network\n",[253,446,448],{"class":255,"line":447},23,[253,449,450],{"class":290},"    # Chỉ bind cổng vào localhost nội bộ (Nginx Reverse Proxy sẽ kết nối tới đây)\n",[253,452,454,457],{"class":255,"line":453},24,[253,455,456],{"class":259},"    ports",[253,458,284],{"class":263},[253,460,462,464],{"class":255,"line":461},25,[253,463,357],{"class":263},[253,465,466],{"class":267},"\"127.0.0.1:3000:3000\"\n",[253,468,470,473],{"class":255,"line":469},26,[253,471,472],{"class":259},"    healthcheck",[253,474,284],{"class":263},[253,476,478,481,484,487,490,493,495,498,500,503],{"class":255,"line":477},27,[253,479,480],{"class":259},"      test",[253,482,483],{"class":263},": [",[253,485,486],{"class":267},"\"CMD\"",[253,488,489],{"class":263},", ",[253,491,492],{"class":267},"\"curl\"",[253,494,489],{"class":263},[253,496,497],{"class":267},"\"-f\"",[253,499,489],{"class":263},[253,501,502],{"class":267},"\"http://localhost:3000/health\"",[253,504,505],{"class":263},"]\n",[253,507,509,512,514],{"class":255,"line":508},28,[253,510,511],{"class":259},"      interval",[253,513,264],{"class":263},[253,515,516],{"class":267},"30s\n",[253,518,520,523,525],{"class":255,"line":519},29,[253,521,522],{"class":259},"      timeout",[253,524,264],{"class":263},[253,526,527],{"class":267},"10s\n",[253,529,531,534,536],{"class":255,"line":530},30,[253,532,533],{"class":259},"      retries",[253,535,264],{"class":263},[253,537,539],{"class":538},"sKJT9","3\n",[253,541,543,546,548],{"class":255,"line":542},31,[253,544,545],{"class":259},"      start_period",[253,547,264],{"class":263},[253,549,550],{"class":267},"40s\n",[253,552,554,557],{"class":255,"line":553},32,[253,555,556],{"class":259},"    deploy",[253,558,284],{"class":263},[253,560,562,565],{"class":255,"line":561},33,[253,563,564],{"class":259},"      resources",[253,566,284],{"class":263},[253,568,570,573],{"class":255,"line":569},34,[253,571,572],{"class":259},"        limits",[253,574,284],{"class":263},[253,576,578,581,583],{"class":255,"line":577},35,[253,579,580],{"class":259},"          cpus",[253,582,264],{"class":263},[253,584,585],{"class":267},"'1.5'\n",[253,587,589,592,594],{"class":255,"line":588},36,[253,590,591],{"class":259},"          memory",[253,593,264],{"class":263},[253,595,596],{"class":267},"1024M\n",[253,598,600,603],{"class":255,"line":599},37,[253,601,602],{"class":259},"        reservations",[253,604,284],{"class":263},[253,606,608,610,612],{"class":255,"line":607},38,[253,609,580],{"class":259},[253,611,264],{"class":263},[253,613,614],{"class":267},"'0.25'\n",[253,616,618,620,622],{"class":255,"line":617},39,[253,619,591],{"class":259},[253,621,264],{"class":263},[253,623,624],{"class":267},"256M\n",[253,626,628,631],{"class":255,"line":627},40,[253,629,630],{"class":259},"    logging",[253,632,284],{"class":263},[253,634,636,639,641],{"class":255,"line":635},41,[253,637,638],{"class":259},"      driver",[253,640,264],{"class":263},[253,642,643],{"class":267},"\"json-file\"\n",[253,645,647,650],{"class":255,"line":646},42,[253,648,649],{"class":259},"      options",[253,651,284],{"class":263},[253,653,655,658,660],{"class":255,"line":654},43,[253,656,657],{"class":259},"        max-size",[253,659,264],{"class":263},[253,661,662],{"class":267},"\"10m\"\n",[253,664,666,669,671],{"class":255,"line":665},44,[253,667,668],{"class":259},"        max-file",[253,670,264],{"class":263},[253,672,673],{"class":267},"\"3\"\n",[253,675,677],{"class":255,"line":676},45,[253,678,275],{"emptyLinePlaceholder":274},[253,680,682],{"class":255,"line":681},46,[253,683,291],{"class":290},[253,685,687],{"class":255,"line":686},47,[253,688,689],{"class":290},"  # 2. Database Service (PostgreSQL 16)\n",[253,691,693],{"class":255,"line":692},48,[253,694,291],{"class":290},[253,696,698,701],{"class":255,"line":697},49,[253,699,700],{"class":259},"  db",[253,702,284],{"class":263},[253,704,706,708,710],{"class":255,"line":705},50,[253,707,316],{"class":259},[253,709,264],{"class":263},[253,711,712],{"class":267},"postgres:16-alpine\n",[253,714,716,718,720],{"class":255,"line":715},51,[253,717,327],{"class":259},[253,719,264],{"class":263},[253,721,722],{"class":267},"production_postgres\n",[253,724,726,728,730],{"class":255,"line":725},52,[253,727,338],{"class":259},[253,729,264],{"class":263},[253,731,343],{"class":267},[253,733,735,737],{"class":255,"line":734},53,[253,736,349],{"class":259},[253,738,284],{"class":263},[253,740,742,744],{"class":255,"line":741},54,[253,743,357],{"class":263},[253,745,360],{"class":267},[253,747,749,751],{"class":255,"line":748},55,[253,750,366],{"class":259},[253,752,284],{"class":263},[253,754,756,759,761],{"class":255,"line":755},56,[253,757,758],{"class":259},"      POSTGRES_DB",[253,760,264],{"class":263},[253,762,763],{"class":267},"${DB_NAME}\n",[253,765,767,770,772],{"class":255,"line":766},57,[253,768,769],{"class":259},"      POSTGRES_USER",[253,771,264],{"class":263},[253,773,774],{"class":267},"${DB_USER}\n",[253,776,778,781,783],{"class":255,"line":777},58,[253,779,780],{"class":259},"      POSTGRES_PASSWORD",[253,782,264],{"class":263},[253,784,785],{"class":267},"${DB_PASSWORD}\n",[253,787,789,792],{"class":255,"line":788},59,[253,790,791],{"class":259},"    volumes",[253,793,284],{"class":263},[253,795,797,799],{"class":255,"line":796},60,[253,798,357],{"class":263},[253,800,801],{"class":267},"pgdata:/var/lib/postgresql/data\n",[253,803,805,807],{"class":255,"line":804},61,[253,806,434],{"class":259},[253,808,284],{"class":263},[253,810,812,814],{"class":255,"line":811},62,[253,813,357],{"class":263},[253,815,444],{"class":267},[253,817,819],{"class":255,"line":818},63,[253,820,821],{"class":290},"    # Không mở port ra ngoài Internet, chỉ giao tiếp nội bộ trong mạng app_network\n",[253,823,825,827],{"class":255,"line":824},64,[253,826,472],{"class":259},[253,828,284],{"class":263},[253,830,832,834,836,839,841,844],{"class":255,"line":831},65,[253,833,480],{"class":259},[253,835,483],{"class":263},[253,837,838],{"class":267},"\"CMD-SHELL\"",[253,840,489],{"class":263},[253,842,843],{"class":267},"\"pg_isready -U ${DB_USER} -d ${DB_NAME}\"",[253,845,505],{"class":263},[253,847,849,851,853],{"class":255,"line":848},66,[253,850,511],{"class":259},[253,852,264],{"class":263},[253,854,527],{"class":267},[253,856,858,860,862],{"class":255,"line":857},67,[253,859,522],{"class":259},[253,861,264],{"class":263},[253,863,864],{"class":267},"5s\n",[253,866,868,870,872],{"class":255,"line":867},68,[253,869,533],{"class":259},[253,871,264],{"class":263},[253,873,874],{"class":538},"5\n",[253,876,878,880,882],{"class":255,"line":877},69,[253,879,545],{"class":259},[253,881,264],{"class":263},[253,883,884],{"class":267},"15s\n",[253,886,888,890],{"class":255,"line":887},70,[253,889,556],{"class":259},[253,891,284],{"class":263},[253,893,895,897],{"class":255,"line":894},71,[253,896,564],{"class":259},[253,898,284],{"class":263},[253,900,902,904],{"class":255,"line":901},72,[253,903,572],{"class":259},[253,905,284],{"class":263},[253,907,909,911,913],{"class":255,"line":908},73,[253,910,580],{"class":259},[253,912,264],{"class":263},[253,914,915],{"class":267},"'2.0'\n",[253,917,919,921,923],{"class":255,"line":918},74,[253,920,591],{"class":259},[253,922,264],{"class":263},[253,924,925],{"class":267},"2048M\n",[253,927,929,931],{"class":255,"line":928},75,[253,930,630],{"class":259},[253,932,284],{"class":263},[253,934,936,938,940],{"class":255,"line":935},76,[253,937,638],{"class":259},[253,939,264],{"class":263},[253,941,643],{"class":267},[253,943,945,947],{"class":255,"line":944},77,[253,946,649],{"class":259},[253,948,284],{"class":263},[253,950,952,954,956],{"class":255,"line":951},78,[253,953,657],{"class":259},[253,955,264],{"class":263},[253,957,662],{"class":267},[253,959,961,963,965],{"class":255,"line":960},79,[253,962,668],{"class":259},[253,964,264],{"class":263},[253,966,673],{"class":267},[253,968,970],{"class":255,"line":969},80,[253,971,275],{"emptyLinePlaceholder":274},[253,973,975],{"class":255,"line":974},81,[253,976,291],{"class":290},[253,978,980],{"class":255,"line":979},82,[253,981,982],{"class":290},"  # 3. In-memory Cache Service (Redis 7)\n",[253,984,986],{"class":255,"line":985},83,[253,987,291],{"class":290},[253,989,991,994],{"class":255,"line":990},84,[253,992,993],{"class":259},"  redis",[253,995,284],{"class":263},[253,997,999,1001,1003],{"class":255,"line":998},85,[253,1000,316],{"class":259},[253,1002,264],{"class":263},[253,1004,1005],{"class":267},"redis:7-alpine\n",[253,1007,1009,1011,1013],{"class":255,"line":1008},86,[253,1010,327],{"class":259},[253,1012,264],{"class":263},[253,1014,1015],{"class":267},"production_redis\n",[253,1017,1019,1021,1023],{"class":255,"line":1018},87,[253,1020,338],{"class":259},[253,1022,264],{"class":263},[253,1024,343],{"class":267},[253,1026,1028,1031,1033],{"class":255,"line":1027},88,[253,1029,1030],{"class":259},"    command",[253,1032,264],{"class":263},[253,1034,1035],{"class":267},"redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes\n",[253,1037,1039,1041],{"class":255,"line":1038},89,[253,1040,791],{"class":259},[253,1042,284],{"class":263},[253,1044,1046,1048],{"class":255,"line":1045},90,[253,1047,357],{"class":263},[253,1049,1050],{"class":267},"redisdata:/data\n",[253,1052,1054,1056],{"class":255,"line":1053},91,[253,1055,434],{"class":259},[253,1057,284],{"class":263},[253,1059,1061,1063],{"class":255,"line":1060},92,[253,1062,357],{"class":263},[253,1064,444],{"class":267},[253,1066,1068,1070],{"class":255,"line":1067},93,[253,1069,472],{"class":259},[253,1071,284],{"class":263},[253,1073,1075,1077,1079,1081,1083,1086,1088,1091,1093,1096,1098,1101],{"class":255,"line":1074},94,[253,1076,480],{"class":259},[253,1078,483],{"class":263},[253,1080,486],{"class":267},[253,1082,489],{"class":263},[253,1084,1085],{"class":267},"\"redis-cli\"",[253,1087,489],{"class":263},[253,1089,1090],{"class":267},"\"-a\"",[253,1092,489],{"class":263},[253,1094,1095],{"class":267},"\"${REDIS_PASSWORD}\"",[253,1097,489],{"class":263},[253,1099,1100],{"class":267},"\"ping\"",[253,1102,505],{"class":263},[253,1104,1106,1108,1110],{"class":255,"line":1105},95,[253,1107,511],{"class":259},[253,1109,264],{"class":263},[253,1111,527],{"class":267},[253,1113,1115,1117,1119],{"class":255,"line":1114},96,[253,1116,522],{"class":259},[253,1118,264],{"class":263},[253,1120,864],{"class":267},[253,1122,1124,1126,1128],{"class":255,"line":1123},97,[253,1125,533],{"class":259},[253,1127,264],{"class":263},[253,1129,539],{"class":538},[253,1131,1133,1135,1137],{"class":255,"line":1132},98,[253,1134,545],{"class":259},[253,1136,264],{"class":263},[253,1138,864],{"class":267},[253,1140,1142,1144],{"class":255,"line":1141},99,[253,1143,556],{"class":259},[253,1145,284],{"class":263},[253,1147,1149,1151],{"class":255,"line":1148},100,[253,1150,564],{"class":259},[253,1152,284],{"class":263},[253,1154,1156,1158],{"class":255,"line":1155},101,[253,1157,572],{"class":259},[253,1159,284],{"class":263},[253,1161,1163,1165,1167],{"class":255,"line":1162},102,[253,1164,580],{"class":259},[253,1166,264],{"class":263},[253,1168,1169],{"class":267},"'0.5'\n",[253,1171,1173,1175,1177],{"class":255,"line":1172},103,[253,1174,591],{"class":259},[253,1176,264],{"class":263},[253,1178,1179],{"class":267},"512M\n",[253,1181,1183,1185],{"class":255,"line":1182},104,[253,1184,630],{"class":259},[253,1186,284],{"class":263},[253,1188,1190,1192,1194],{"class":255,"line":1189},105,[253,1191,638],{"class":259},[253,1193,264],{"class":263},[253,1195,643],{"class":267},[253,1197,1199,1201],{"class":255,"line":1198},106,[253,1200,649],{"class":259},[253,1202,284],{"class":263},[253,1204,1206,1208,1210],{"class":255,"line":1205},107,[253,1207,657],{"class":259},[253,1209,264],{"class":263},[253,1211,1212],{"class":267},"\"5m\"\n",[253,1214,1216,1218,1220],{"class":255,"line":1215},108,[253,1217,668],{"class":259},[253,1219,264],{"class":263},[253,1221,1222],{"class":267},"\"2\"\n",[253,1224,1226],{"class":255,"line":1225},109,[253,1227,275],{"emptyLinePlaceholder":274},[253,1229,1231],{"class":255,"line":1230},110,[253,1232,1233],{"class":290},"# ==========================================\n",[253,1235,1237],{"class":255,"line":1236},111,[253,1238,1239],{"class":290},"# Persistent Volumes (Dữ liệu bền vững)\n",[253,1241,1243],{"class":255,"line":1242},112,[253,1244,1233],{"class":290},[253,1246,1248,1251],{"class":255,"line":1247},113,[253,1249,1250],{"class":259},"volumes",[253,1252,284],{"class":263},[253,1254,1256,1259],{"class":255,"line":1255},114,[253,1257,1258],{"class":259},"  pgdata",[253,1260,284],{"class":263},[253,1262,1264,1267,1269],{"class":255,"line":1263},115,[253,1265,1266],{"class":259},"    name",[253,1268,264],{"class":263},[253,1270,1271],{"class":267},"production_pgdata\n",[253,1273,1275,1278],{"class":255,"line":1274},116,[253,1276,1277],{"class":259},"  redisdata",[253,1279,284],{"class":263},[253,1281,1283,1285,1287],{"class":255,"line":1282},117,[253,1284,1266],{"class":259},[253,1286,264],{"class":263},[253,1288,1289],{"class":267},"production_redisdata\n",[253,1291,1293],{"class":255,"line":1292},118,[253,1294,275],{"emptyLinePlaceholder":274},[253,1296,1298],{"class":255,"line":1297},119,[253,1299,1233],{"class":290},[253,1301,1303],{"class":255,"line":1302},120,[253,1304,1305],{"class":290},"# Isolated Network (Mạng nội bộ cách ly)\n",[253,1307,1309],{"class":255,"line":1308},121,[253,1310,1233],{"class":290},[253,1312,1314,1317],{"class":255,"line":1313},122,[253,1315,1316],{"class":259},"networks",[253,1318,284],{"class":263},[253,1320,1322,1325],{"class":255,"line":1321},123,[253,1323,1324],{"class":259},"  app_network",[253,1326,284],{"class":263},[253,1328,1330,1332,1334],{"class":255,"line":1329},124,[253,1331,1266],{"class":259},[253,1333,264],{"class":263},[253,1335,1336],{"class":267},"production_network\n",[253,1338,1340,1343,1345],{"class":255,"line":1339},125,[253,1341,1342],{"class":259},"    driver",[253,1344,264],{"class":263},[253,1346,1347],{"class":267},"bridge\n",[214,1349],{},[166,1351,1353],{"id":1352},"_3-phân-tích-các-nguyên-tắc-then-chốt-trong-cấu-hình-production","3. Phân tích các nguyên tắc then chốt trong cấu hình Production",[1355,1356,1358],"h3",{"id":1357},"a-cơ-chế-khởi-động-lại-restart-policy","A. Cơ chế Khởi động lại (Restart Policy)",[192,1360,1361],{},[195,1362,1363,1366,1367,1370],{},[175,1364,1365],{},"restart: unless-stopped",": Đảm bảo container sẽ luôn tự động khởi động lại khi bị crash hoặc khi máy chủ VPS khởi động lại sau bảo trì, trừ khi bạn cố ý gõ lệnh dừng thủ công (",[175,1368,1369],{},"docker compose stop",").",[1355,1372,1374],{"id":1373},"b-healthcheck-khởi-động-tuần-tự-có-điều-kiện-service_healthy","B. Healthcheck & Khởi động tuần tự có điều kiện (service_healthy)",[171,1376,1377,1378,1381,1382,1385,1386,1389],{},"Trong quá khứ, lệnh ",[175,1379,1380],{},"depends_on: ['db']"," chỉ chờ container database được bật lên chứ không biết database đã thực sự nạp xong dữ liệu hay chưa.\nBằng cách định nghĩa ",[175,1383,1384],{},"healthcheck"," trên service ",[175,1387,1388],{},"db"," và sử dụng:",[224,1391,1393],{"className":247,"code":1392,"language":249,"meta":230,"style":230},"depends_on:\n  db:\n    condition: service_healthy\n",[175,1394,1395,1402,1408],{"__ignoreMap":230},[253,1396,1397,1400],{"class":255,"line":256},[253,1398,1399],{"class":259},"depends_on",[253,1401,284],{"class":263},[253,1403,1404,1406],{"class":255,"line":271},[253,1405,700],{"class":259},[253,1407,284],{"class":263},[253,1409,1410,1413,1415],{"class":255,"line":278},[253,1411,1412],{"class":259},"    condition",[253,1414,264],{"class":263},[253,1416,411],{"class":267},[171,1418,1419,1420,1423,1424,1427,1428,1432],{},"Container ",[175,1421,1422],{},"api"," sẽ chỉ được khởi động khi lệnh ",[175,1425,1426],{},"pg_isready"," trả về mã thành công, loại bỏ hoàn toàn lỗi ",[1429,1430,1431],"em",{},"\"Database connection refused\""," khi vừa reboot.",[1355,1434,1436],{"id":1435},"c-giới-hạn-tài-nguyên-phần-cứng-resource-limits","C. Giới hạn tài nguyên phần cứng (Resource Limits)",[171,1438,1439],{},"Ngăn chặn một container bị lỗi rò rỉ bộ nhớ (Memory Leak) tiêu thụ 100% RAM của VPS dẫn đến cơ chế OOM Killer của Linux tiêu diệt các tiến trình quan trọng khác:",[192,1441,1442,1450],{},[195,1443,1444,1449],{},[187,1445,1446],{},[175,1447,1448],{},"limits.memory: 1024M",": Container chỉ được phép dùng tối đa 1GB RAM.",[195,1451,1452,1457],{},[187,1453,1454],{},[175,1455,1456],{},"limits.cpus: '1.5'",": Container chỉ được phép dùng tối đa 1.5 nhân CPU.",[1355,1459,1461],{"id":1460},"d-giới-hạn-dung-lượng-log-logging-driver","D. Giới hạn dung lượng Log (Logging Driver)",[171,1463,1464,1465,1468,1469,1472],{},"Mặc định Docker ghi lại mọi output ",[175,1466,1467],{},"stdout","/",[175,1470,1471],{},"stderr"," không giới hạn, rất dễ làm đầy 100% ổ cứng (Disk full).",[224,1474,1476],{"className":247,"code":1475,"language":249,"meta":230,"style":230},"logging:\n  driver: \"json-file\"\n  options:\n    max-size: \"10m\"\n    max-file: \"3\"\n",[175,1477,1478,1485,1494,1501,1510],{"__ignoreMap":230},[253,1479,1480,1483],{"class":255,"line":256},[253,1481,1482],{"class":259},"logging",[253,1484,284],{"class":263},[253,1486,1487,1490,1492],{"class":255,"line":271},[253,1488,1489],{"class":259},"  driver",[253,1491,264],{"class":263},[253,1493,643],{"class":267},[253,1495,1496,1499],{"class":255,"line":278},[253,1497,1498],{"class":259},"  options",[253,1500,284],{"class":263},[253,1502,1503,1506,1508],{"class":255,"line":287},[253,1504,1505],{"class":259},"    max-size",[253,1507,264],{"class":263},[253,1509,662],{"class":267},[253,1511,1512,1515,1517],{"class":255,"line":294},[253,1513,1514],{"class":259},"    max-file",[253,1516,264],{"class":263},[253,1518,673],{"class":267},[171,1520,1521],{},"Cấu hình này đảm bảo mỗi container không bao giờ chiếm quá 30MB dung lượng lưu trữ log.",[214,1523],{},[166,1525,1527],{"id":1526},"_4-quản-lý-biến-môi-trường-bảo-mật-envproduction","4. Quản lý biến môi trường bảo mật (.env.production)",[171,1529,1530,1531,1534],{},"Tạo file ",[175,1532,1533],{},".env.production"," và cấp quyền bảo mật chỉ cho user hiện tại được đọc:",[224,1536,1540],{"className":1537,"code":1538,"language":1539,"meta":230,"style":230},"language-bash shiki shiki-themes github-dark github-dark github-dark","touch .env.production\nchmod 600 .env.production\nnano .env.production\n","bash",[175,1541,1542,1551,1561],{"__ignoreMap":230},[253,1543,1544,1548],{"class":255,"line":256},[253,1545,1547],{"class":1546},"sb7EE","touch",[253,1549,1550],{"class":267}," .env.production\n",[253,1552,1553,1556,1559],{"class":255,"line":271},[253,1554,1555],{"class":1546},"chmod",[253,1557,1558],{"class":538}," 600",[253,1560,1550],{"class":267},[253,1562,1563,1566],{"class":255,"line":278},[253,1564,1565],{"class":1546},"nano",[253,1567,1550],{"class":267},[171,1569,1570],{},"Nội dung file:",[224,1572,1576],{"className":1573,"code":1574,"language":1575,"meta":230,"style":230},"language-ini shiki shiki-themes github-dark github-dark github-dark","DB_NAME=core_production\nDB_USER=pgadmin\nDB_PASSWORD=SuperSecretPassword2024!\nREDIS_PASSWORD=AnotherVeryStrongPassword2024!\nJWT_SECRET=your-random-jwt-token-string-here\n","ini",[175,1577,1578,1583,1588,1593,1598],{"__ignoreMap":230},[253,1579,1580],{"class":255,"line":256},[253,1581,1582],{},"DB_NAME=core_production\n",[253,1584,1585],{"class":255,"line":271},[253,1586,1587],{},"DB_USER=pgadmin\n",[253,1589,1590],{"class":255,"line":278},[253,1591,1592],{},"DB_PASSWORD=SuperSecretPassword2024!\n",[253,1594,1595],{"class":255,"line":287},[253,1596,1597],{},"REDIS_PASSWORD=AnotherVeryStrongPassword2024!\n",[253,1599,1600],{"class":255,"line":294},[253,1601,1602],{},"JWT_SECRET=your-random-jwt-token-string-here\n",[1604,1605,1606],"blockquote",{},[171,1607,1608,1611,1612,1614,1615,1618],{},[253,1609,1610],{},"!CAUTION","\nLuôn thêm file ",[175,1613,1533],{}," vào danh sách ",[175,1616,1617],{},".gitignore"," để không bao giờ vô tình đẩy mật khẩu lên GitHub hoặc GitLab.",[214,1620],{},[166,1622,1624],{"id":1623},"_5-quy-trình-vận-hành-và-triển-khai-deployment-workflow","5. Quy trình Vận hành và Triển khai (Deployment Workflow)",[171,1626,1627],{},"Khi triển khai phiên bản mới hoặc cập nhật cấu hình:",[224,1629,1631],{"className":1537,"code":1630,"language":1539,"meta":230,"style":230},"# 1. Kéo image mới nhất về máy\ndocker compose --env-file .env.production pull\n\n# 2. Khởi chạy lại container ở chế độ nền (Zero/Minimal Downtime)\ndocker compose --env-file .env.production up -d --remove-orphans\n\n# 3. Kiểm tra trạng thái sức khỏe (Health status)\ndocker compose ps\n\n# 4. Xem log theo dõi thời gian thực\ndocker compose logs -f --tail=100 api\n",[175,1632,1633,1638,1654,1658,1663,1682,1686,1691,1700,1704,1709],{"__ignoreMap":230},[253,1634,1635],{"class":255,"line":256},[253,1636,1637],{"class":290},"# 1. Kéo image mới nhất về máy\n",[253,1639,1640,1642,1645,1648,1651],{"class":255,"line":271},[253,1641,25],{"class":1546},[253,1643,1644],{"class":267}," compose",[253,1646,1647],{"class":538}," --env-file",[253,1649,1650],{"class":267}," .env.production",[253,1652,1653],{"class":267}," pull\n",[253,1655,1656],{"class":255,"line":278},[253,1657,275],{"emptyLinePlaceholder":274},[253,1659,1660],{"class":255,"line":287},[253,1661,1662],{"class":290},"# 2. Khởi chạy lại container ở chế độ nền (Zero/Minimal Downtime)\n",[253,1664,1665,1667,1669,1671,1673,1676,1679],{"class":255,"line":294},[253,1666,25],{"class":1546},[253,1668,1644],{"class":267},[253,1670,1647],{"class":538},[253,1672,1650],{"class":267},[253,1674,1675],{"class":267}," up",[253,1677,1678],{"class":538}," -d",[253,1680,1681],{"class":538}," --remove-orphans\n",[253,1683,1684],{"class":255,"line":300},[253,1685,275],{"emptyLinePlaceholder":274},[253,1687,1688],{"class":255,"line":305},[253,1689,1690],{"class":290},"# 3. Kiểm tra trạng thái sức khỏe (Health status)\n",[253,1692,1693,1695,1697],{"class":255,"line":313},[253,1694,25],{"class":1546},[253,1696,1644],{"class":267},[253,1698,1699],{"class":267}," ps\n",[253,1701,1702],{"class":255,"line":324},[253,1703,275],{"emptyLinePlaceholder":274},[253,1705,1706],{"class":255,"line":335},[253,1707,1708],{"class":290},"# 4. Xem log theo dõi thời gian thực\n",[253,1710,1711,1713,1715,1718,1721,1724],{"class":255,"line":346},[253,1712,25],{"class":1546},[253,1714,1644],{"class":267},[253,1716,1717],{"class":267}," logs",[253,1719,1720],{"class":538}," -f",[253,1722,1723],{"class":538}," --tail=100",[253,1725,1726],{"class":267}," api\n",[214,1728],{},[166,1730,1732],{"id":1731},"tổng-kết","Tổng kết",[171,1734,1735],{},"Một file Docker Compose được thiết kế chuẩn Production không chỉ giúp hệ thống chạy ổn định mà còn giúp các kĩ sư vận hành dễ dàng chẩn đoán lỗi, nâng cấp phiên bản và mở rộng qui mô một cách an toàn và tự tin.",[1737,1738,1739],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .sRcpU, html code.shiki .sRcpU{--shiki-default:#85E89D;--shiki-dark:#85E89D;--shiki-light:#85E89D}html pre.shiki code .sFJ4l, html code.shiki .sFJ4l{--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-light:#E1E4E8}html pre.shiki code .skqr8, html code.shiki .skqr8{--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-light:#9ECBFF}html pre.shiki code .sGGCZ, html code.shiki .sGGCZ{--shiki-default:#6A737D;--shiki-dark:#6A737D;--shiki-light:#6A737D}html pre.shiki code .sKJT9, html code.shiki .sKJT9{--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-light:#79B8FF}html pre.shiki code .sb7EE, html code.shiki .sb7EE{--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-light:#B392F0}",{"title":230,"searchDepth":271,"depth":271,"links":1741},[1742,1743,1744,1745,1751,1752,1753],{"id":168,"depth":271,"text":169},{"id":218,"depth":271,"text":219},{"id":237,"depth":271,"text":238},{"id":1352,"depth":271,"text":1353,"children":1746},[1747,1748,1749,1750],{"id":1357,"depth":278,"text":1358},{"id":1373,"depth":278,"text":1374},{"id":1435,"depth":278,"text":1436},{"id":1460,"depth":278,"text":1461},{"id":1526,"depth":271,"text":1527},{"id":1623,"depth":271,"text":1624},{"id":1731,"depth":271,"text":1732},[25,10],false,"md",{"src":46,"alt":47},{},{"title":37,"description":38},"Tự học Docker từ A-Z","docker-compose-production","posts/docker-compose-production",[41,42,43],"2026-08-21","4WN8msWdDF",[1767,1772,1777,1781,1786,1791,1796,1801,1806,1811,1816,1821],{"path":5,"title":6,"categories":1768,"tags":1769,"date":16,"draft":1755,"slug":1770,"description":7,"image":1771},[9,10],[12,13,14,15],"incident-checklist",{"src":18,"alt":19},{"path":21,"title":22,"categories":1773,"tags":1774,"date":31,"draft":1755,"slug":1775,"description":23,"image":1776},[25,26],[28,29,30,10],"backup-postgres-docker",{"src":33,"alt":34},{"path":36,"title":37,"categories":1778,"tags":1779,"date":44,"draft":1755,"slug":1761,"description":38,"image":1780},[25,10],[41,42,43],{"src":46,"alt":47},{"path":49,"title":50,"categories":1782,"tags":1783,"date":58,"draft":1755,"slug":1784,"description":51,"image":1785},[9,10],[54,55,56,57],"monitoring-server-basics",{"src":60,"alt":61},{"path":63,"title":64,"categories":1787,"tags":1788,"date":71,"draft":1755,"slug":1789,"description":65,"image":1790},[9,67],[10,69,70],"nginx-reverse-proxy",{"src":73,"alt":74},{"path":76,"title":77,"categories":1792,"tags":1793,"date":83,"draft":1755,"slug":1794,"description":78,"image":1795},[9,14],[81,82,10],"how-to-secure-a-vps",{"src":85,"alt":86},{"path":88,"title":89,"categories":1797,"tags":1798,"date":95,"draft":1755,"slug":1799,"description":90,"image":1800},[9,10],[93,94,43,41],"systemd-node-service",{"src":97,"alt":98},{"path":100,"title":101,"categories":1802,"tags":1803,"date":107,"draft":1755,"slug":1804,"description":102,"image":1805},[9,25],[105,10,106],"how-to-install-docker-on-ubuntu-server",{"src":109,"alt":110},{"path":112,"title":113,"categories":1807,"tags":1808,"date":118,"draft":1755,"slug":1809,"description":114,"image":1810},[9,14],[117,10,15],"ssh-key-authentication",{"src":120,"alt":121},{"path":123,"title":124,"categories":1812,"tags":1813,"date":131,"draft":1755,"slug":1814,"description":125,"image":1815},[9,14],[128,129,130,15],"ufw-firewall-basics",{"src":133,"alt":134},{"path":136,"title":137,"categories":1817,"tags":1818,"date":145,"draft":1755,"slug":1819,"description":138,"image":1820},[140,10],[142,143,144,30],"git-deploy-key",{"src":147,"alt":148},{"path":150,"title":151,"categories":1822,"tags":1823,"date":155,"draft":1755,"slug":1824,"description":152,"image":1825},[9],[106,105,15],"ubuntu-server-initial-setup",{"src":157,"alt":158},[1827,1828,1829],{"path":100,"title":101,"series":1760,"series_order":256,"date":107,"draft":1755,"slug":1804},{"path":36,"title":37,"series":1760,"series_order":271,"date":44,"draft":1755,"slug":1761},{"path":21,"title":22,"series":1760,"series_order":278,"date":31,"draft":1755,"slug":1775},1789616168204]