{"id":40320,"date":"2026-03-18T09:35:07","date_gmt":"2026-03-18T02:35:07","guid":{"rendered":"https:\/\/interdata.vn\/blog\/?p=40320"},"modified":"2026-03-18T10:24:34","modified_gmt":"2026-03-18T03:24:34","slug":"huong-dan-deploy-nodejs-tren-vps","status":"publish","type":"post","link":"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/","title":{"rendered":"H\u01b0\u1edbng D\u1eabn Deploy Node.js Tr\u00ean VPS: PM2, Nginx &#038; SSL Chi Ti\u1ebft [2026]"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter ez-toc-white ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">N\u1ed8I DUNG<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 eztoc-toggle-hide-by-default' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Can-chuan-bi-gi-truoc-khi-dua-web-Nodejs-len-VPS\" >C\u1ea7n chu\u1ea9n b\u1ecb g\u00ec tr\u01b0\u1edbc khi \u0111\u01b0a web Node.js l\u00ean VPS?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Buoc-1-Ket-noi-SSH-va-cai-moi-truong-Nodejs-qua-NVM\" >B\u01b0\u1edbc 1: K\u1ebft n\u1ed1i SSH v\u00e0 c\u00e0i m\u00f4i tr\u01b0\u1eddng Node.js qua NVM<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Cach-cai-dat-Nodejs-bang-NVM-Node-Version-Manager\" >C\u00e1ch c\u00e0i \u0111\u1eb7t Node.js b\u1eb1ng NVM (Node Version Manager)<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Buoc-2-Clone-Source-Code-Cau-hinh-env-va-Cai-thu-vien\" >B\u01b0\u1edbc 2: Clone Source Code, C\u1ea5u h\u00ecnh .env v\u00e0 C\u00e0i th\u01b0 vi\u1ec7n<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Dua-code-len-VPS-va-bao-mat-file-moi-truong\" >\u0110\u01b0a code l\u00ean VPS v\u00e0 b\u1ea3o m\u1eadt file m\u00f4i tr\u01b0\u1eddng<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Buoc-3-Giu-app-Nodejs-luon-chay-ngam-voi-PM2\" >B\u01b0\u1edbc 3: Gi\u1eef app Node.js lu\u00f4n ch\u1ea1y ng\u1ea7m v\u1edbi PM2<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#PM2-la-gi-va-tai-sao-bat-buoc-phai-dung-khi-deploy-Nodejs\" >PM2 l\u00e0 g\u00ec v\u00e0 t\u1ea1i sao b\u1eaft bu\u1ed9c ph\u1ea3i d\u00f9ng khi deploy Node.js?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Buoc-4-Cau-hinh-Nginx-lam-Reverse-Proxy-va-mo-Firewall\" >B\u01b0\u1edbc 4: C\u1ea5u h\u00ecnh Nginx l\u00e0m Reverse Proxy v\u00e0 m\u1edf Firewall<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Reverse-Proxy-trong-Nginx-dong-vai-tro-gi\" >Reverse Proxy trong Nginx \u0111\u00f3ng vai tr\u00f2 g\u00ec?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Buoc-5-Cai-dat-chung-chi-SSL-HTTPS-mien-phi-voi-Certbot\" >B\u01b0\u1edbc 5: C\u00e0i \u0111\u1eb7t ch\u1ee9ng ch\u1ec9 SSL HTTPS mi\u1ec5n ph\u00ed v\u1edbi Certbot<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Bao-mat-ung-dung-bang-Lets-Encrypt\" >B\u1ea3o m\u1eadt \u1ee9ng d\u1ee5ng b\u1eb1ng Let&#8217;s Encrypt<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#VPS-Gia-Re-InterData-%E2%80%94-San-Sang-Deploy-Nodejs-Ngay\" >VPS Gi\u00e1 R\u1ebb InterData \u2014 S\u1eb5n S\u00e0ng Deploy Node.js Ngay<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#FAQs-%E2%80%94-Cau-hoi-thuong-gap-khi-deploy-ung-dung-Nodejs\" >FAQs \u2014 C\u00e2u h\u1ecfi th\u01b0\u1eddng g\u1eb7p khi deploy \u1ee9ng d\u1ee5ng Node.js<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Cap-nhat-code-moi-len-VPS-deploy-lai-nhu-the-nao\" >C\u1eadp nh\u1eadt code m\u1edbi l\u00ean VPS (deploy l\u1ea1i) nh\u01b0 th\u1ebf n\u00e0o?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Lam-sao-de-xem-nguyen-nhan-app-Nodejs-bi-sap-tren-VPS\" >L\u00e0m sao \u0111\u1ec3 xem nguy\u00ean nh\u00e2n app Node.js b\u1ecb s\u1eadp tr\u00ean VPS?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#App-Nodejs-ngon-qua-nhieu-RAM-cua-VPS-thi-xu-ly-sao\" >App Node.js ng\u1ed1n qu\u00e1 nhi\u1ec1u RAM c\u1ee7a VPS th\u00ec x\u1eed l\u00fd sao?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/interdata.vn\/blog\/huong-dan-deploy-nodejs-tren-vps\/#Ket-luan\" >K\u1ebft lu\u1eadn<\/a><\/li><\/ul><\/nav><\/div>\n<div class=\"summary\">\n<p><strong>T\u00f3m t\u1eaft nhanh:<\/strong> Deploy Node.js tr\u00ean <a href=\"https:\/\/interdata.vn\/blog\/vps-la-gi\/\">VPS<\/a> l\u00e0 qu\u00e1 tr\u00ecnh chuy\u1ec3n <a href=\"https:\/\/interdata.vn\/blog\/source-code-la-gi\/\">m\u00e3 ngu\u1ed3n<\/a> \u1ee9ng d\u1ee5ng t\u1eeb m\u00e1y t\u00ednh c\u00e1 nh\u00e2n l\u00ean <a href=\"https:\/\/interdata.vn\/blog\/may-chu-server-la-gi\/\">m\u00e1y ch\u1ee7<\/a> \u1ea3o ch\u1ea1y <a href=\"https:\/\/interdata.vn\/blog\/he-dieu-hanh-linux-la-gi\/\">Linux<\/a> \u0111\u1ec3 web ho\u1ea1t \u0111\u1ed9ng public tr\u00ean <a href=\"https:\/\/interdata.vn\/blog\/mang-internet\/\">internet<\/a>. \u0110\u1ec3 ch\u1ea1y \u1ed5n \u0111\u1ecbnh chu\u1ea9n production, quy tr\u00ecnh c\u1ea7n 4 th\u00e0nh ph\u1ea7n b\u1eaft bu\u1ed9c: Node.js c\u00e0i qua NVM (qu\u1ea3n l\u00fd m\u00f4i tr\u01b0\u1eddng), PM2 (gi\u1eef ti\u1ebfn tr\u00ecnh ch\u1ea1y ng\u1ea7m 24\/7, t\u1ef1 restart khi crash), <a href=\"https:\/\/interdata.vn\/blog\/nginx-la-gi\/\">Nginx<\/a> (Reverse Proxy \u0111\u1ecbnh tuy\u1ebfn request t\u1eeb port 80\/443 v\u1ec1 port n\u1ed9i b\u1ed9) v\u00e0 Certbot (c\u1ea5p ch\u1ee9ng ch\u1ec9 <a href=\"https:\/\/interdata.vn\/blog\/giao-thuc-https-la-gi\/\">HTTPS<\/a> t\u1eeb Let&#8217;s Encrypt mi\u1ec5n ph\u00ed). Thi\u1ebfu b\u1ea5t k\u1ef3 th\u00e0nh ph\u1ea7n n\u00e0o, \u1ee9ng d\u1ee5ng s\u1ebd kh\u00f4ng \u0111\u1ea1t ti\u00eau chu\u1ea9n production.<\/p>\n<ul>\n<li>C\u00e0i Node.js an to\u00e0n qua NVM \u0111\u1ec3 d\u1ec5 chuy\u1ec3n \u0111\u1ed5i version gi\u1eefa c\u00e1c d\u1ef1 \u00e1n.<\/li>\n<li>D\u00f9ng PM2 thay cho <code>node app.js<\/code> tr\u1ef1c ti\u1ebfp \u2014 \u1ee9ng d\u1ee5ng s\u1ebd kh\u00f4ng s\u1eadp khi \u0111\u00f3ng SSH.<\/li>\n<li>C\u1ea5u h\u00ecnh Nginx Reverse Proxy \u0111\u1ec3 ng\u01b0\u1eddi d\u00f9ng truy c\u1eadp qua <a href=\"https:\/\/interdata.vn\/blog\/domain-la-gi\/\">domain<\/a> thay v\u00ec port :3000.<\/li>\n<li>M\u1edf \u0111\u00fang port <a href=\"https:\/\/interdata.vn\/blog\/ufw-la-gi\/\">UFW<\/a> <a href=\"https:\/\/interdata.vn\/blog\/tuong-lua-firewall\/\">Firewall<\/a>, tr\u00e1nh block Nginx sau khi c\u1ea5u h\u00ecnh.<\/li>\n<li>C\u00e0i <a href=\"https:\/\/interdata.vn\/blog\/chung-chi-ssl\/\">SSL<\/a> Let&#8217;s Encrypt qua Certbot \u2014 ch\u1ec9 1 l\u1ec7nh, t\u1ef1 \u0111\u1ed9ng redirect HTTP sang HTTPS.<\/li>\n<\/ul>\n<\/div>\n<p><!-- INTRODUCTION HOOK --><\/p>\n<p>Code xong app Node.js, ch\u1ea1y <code>node server.js<\/code> tr\u00ean VPS th\u1ea5y web l\u00ean ngon. Nh\u01b0ng v\u1eeba t\u1eaft c\u1eeda s\u1ed5 terminal SSH \u2014 web l\u1eadp t\u1ee9c tr\u1ea3 v\u1ec1 <em>This site can&#8217;t be reached<\/em>. Ho\u1eb7c t\u1ec7 h\u01a1n: app ch\u1ea1y \u0111\u01b0\u1ee3c nh\u01b0ng tr\u00ecnh duy\u1ec7t hi\u1ec7n bi\u1ec3u t\u01b0\u1ee3ng kh\u00f3a \u0111\u1ecf k\u00e8m c\u1ea3nh b\u00e1o <em>Not Secure<\/em>, khi\u1ebfn kh\u00e1ch h\u00e0ng ng\u1ea7n ng\u1ea1i nh\u1ea5p v\u00e0o. \u0110\u00e2y l\u00e0 hai l\u1ed7i ph\u1ed5 bi\u1ebfn nh\u1ea5t g\u1eb7p ph\u1ea3i khi l\u1ea7n \u0111\u1ea7u \u0111\u01b0a web Node.js l\u00ean VPS \u2014 v\u00e0 c\u1ea3 hai \u0111\u1ec1u c\u00f3 nguy\u00ean nh\u00e2n r\u00f5 r\u00e0ng, s\u1eeda \u0111\u01b0\u1ee3c ho\u00e0n to\u00e0n.<\/p>\n<p>B\u00e0i vi\u1ebft n\u00e0y h\u01b0\u1edbng d\u1eabn c\u00e1ch deploy Node.js tr\u00ean VPS theo <a href=\"https:\/\/interdata.vn\/blog\/stack-la-gi\/\">stack<\/a> chu\u1ea9n production m\u00e0 \u0111\u1ed9i ng\u0169 k\u1ef9 thu\u1eadt th\u1ef1c t\u1ebf s\u1eed d\u1ee5ng: <strong>NVM<\/strong> \u0111\u1ec3 qu\u1ea3n l\u00fd m\u00f4i tr\u01b0\u1eddng Node.js, <strong>PM2<\/strong> \u0111\u1ec3 \u1ee9ng d\u1ee5ng s\u1ed1ng dai kh\u00f4ng s\u1eadp, <strong>Nginx<\/strong> l\u00e0m Reverse Proxy m\u1edf \u0111\u01b0\u1eddng cho domain, <strong>UFW<\/strong> \u0111\u1ec3 kh\u00f3a firewall \u0111\u00fang c\u00e1ch, v\u00e0 <strong>Certbot<\/strong> \u0111\u1ec3 c\u1ea5p SSL HTTPS mi\u1ec5n ph\u00ed. Kh\u00f4ng ph\u1ea3i h\u01b0\u1edbng d\u1eabn ch\u1ea1y th\u1eed \u2014 m\u00e0 l\u00e0 quy tr\u00ecnh s\u1eb5n s\u00e0ng go-live th\u1ef1c s\u1ef1. B\u1ea1n c\u1ea7n chu\u1ea9n b\u1ecb s\u1eb5n m\u1ed9t <a href=\"\/vps-linux\/\" target=\"_blank\" rel=\"noopener\">VPS Linux<\/a> tr\u01b0\u1edbc khi b\u1eaft \u0111\u1ea7u.<\/p>\n<figure id=\"attachment_40371\" aria-describedby=\"caption-attachment-40371\" style=\"width: 800px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-40371\" src=\"https:\/\/interdata.vn\/blog\/wp-content\/uploads\/2026\/03\/So-do-kien-truc-stack-production.webp\" alt=\"S\u01a1 \u0111\u1ed3 ki\u1ebfn tr\u00fac stack production\" width=\"800\" height=\"537\" title=\"\" srcset=\"https:\/\/interdata.vn\/blog\/wp-content\/uploads\/2026\/03\/So-do-kien-truc-stack-production.webp 800w, https:\/\/interdata.vn\/blog\/wp-content\/uploads\/2026\/03\/So-do-kien-truc-stack-production-300x201.webp 300w, https:\/\/interdata.vn\/blog\/wp-content\/uploads\/2026\/03\/So-do-kien-truc-stack-production-768x516.webp 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption id=\"caption-attachment-40371\" class=\"wp-caption-text\">S\u01a1 \u0111\u1ed3 ki\u1ebfn tr\u00fac stack production<\/figcaption><\/figure>\n<p><!-- SECTION: CHU\u1ea8N B\u1eca --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Can-chuan-bi-gi-truoc-khi-dua-web-Nodejs-len-VPS\"><\/span>C\u1ea7n chu\u1ea9n b\u1ecb g\u00ec tr\u01b0\u1edbc khi \u0111\u01b0a web Node.js l\u00ean VPS?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Tr\u01b0\u1edbc khi g\u00f5 b\u1ea5t k\u1ef3 l\u1ec7nh n\u00e0o, h\u00e3y x\u00e1c nh\u1eadn \u0111\u1ee7 4 th\u1ee9 sau. Thi\u1ebfu m\u1ed9t trong s\u1ed1 n\u00e0y, c\u00e1c b\u01b0\u1edbc ph\u00eda d\u01b0\u1edbi s\u1ebd g\u1eb7p l\u1ed7i gi\u1eefa ch\u1eebng v\u00e0 kh\u00f3 <a href=\"https:\/\/interdata.vn\/blog\/wordpress-debug-la-gi\/\">debug<\/a> h\u01a1n.<\/p>\n<ul>\n<li><strong>VPS ch\u1ea1y Ubuntu 22.04 ho\u1eb7c 24.04 LTS<\/strong> \u2014 \u0111\u00e2y l\u00e0 hai phi\u00ean b\u1ea3n \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3 d\u00e0i h\u1ea1n, t\u01b0\u01a1ng th\u00edch t\u1ed1t nh\u1ea5t v\u1edbi PM2, Nginx v\u00e0 Certbot. InterData cung c\u1ea5p s\u1eb5n c\u1ea3 hai image.<\/li>\n<li><strong><a href=\"https:\/\/interdata.vn\/blog\/root-access-la-gi\/\">Quy\u1ec1n root<\/a> ho\u1eb7c sudo<\/strong> \u2014 c\u1ea7n thi\u1ebft \u0111\u1ec3 c\u00e0i package v\u00e0 c\u1ea5u h\u00ecnh Nginx\/UFW.<\/li>\n<li><strong>Domain \u0111\u00e3 tr\u1ecf <a href=\"https:\/\/interdata.vn\/blog\/ban-ghi-a-la-gi\/\">b\u1ea3n ghi A<\/a> v\u1ec1 <a href=\"https:\/\/interdata.vn\/blog\/dia-chi-ip-la-gi\/\">IP<\/a> VPS<\/strong> \u2014 Certbot kh\u00f4ng th\u1ec3 c\u1ea5p SSL n\u1ebfu domain ch\u01b0a resolve v\u1ec1 \u0111\u00fang m\u00e1y ch\u1ee7. Th\u1eddi gian propagate <a href=\"https:\/\/interdata.vn\/blog\/dns-la-gi\/\">DNS<\/a> th\u01b0\u1eddng t\u1eeb 15 ph\u00fat \u0111\u1ebfn 1 gi\u1edd.<\/li>\n<li><strong>Source code Node.js \u0111\u00e3 push l\u00ean GitHub<\/strong> (ho\u1eb7c GitLab) \u2014 c\u00e1ch deploy chu\u1ea9n nh\u1ea5t l\u00e0 k\u00e9o code qua <code>git clone<\/code>, kh\u00f4ng upload th\u1ee7 c\u00f4ng.<\/li>\n<\/ul>\n<p>N\u1ebfu ch\u01b0a c\u00f3 VPS, c\u00f3 th\u1ec3 tham kh\u1ea3o <a href=\"https:\/\/interdata.vn\/blog\/cach-chon-cau-hinh-vps-phu-hop\/\" target=\"_blank\" rel=\"noopener\">h\u01b0\u1edbng d\u1eabn ch\u1ecdn g\u00f3i VPS ph\u00f9 h\u1ee3p<\/a> tr\u01b0\u1edbc khi ti\u1ebfp t\u1ee5c. C\u00f2n n\u1ebfu \u0111\u00e3 \u0111\u1ee7 \u0111i\u1ec1u ki\u1ec7n \u2014 b\u1eaft \u0111\u1ea7u ngay t\u1eeb B\u01b0\u1edbc 1.<\/p>\n<p><!-- B\u01af\u1edaC 1 --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Buoc-1-Ket-noi-SSH-va-cai-moi-truong-Nodejs-qua-NVM\"><\/span>B\u01b0\u1edbc 1: K\u1ebft n\u1ed1i SSH v\u00e0 c\u00e0i m\u00f4i tr\u01b0\u1eddng Node.js qua NVM<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Cach-cai-dat-Nodejs-bang-NVM-Node-Version-Manager\"><\/span>C\u00e1ch c\u00e0i \u0111\u1eb7t Node.js b\u1eb1ng NVM (Node Version Manager)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>C\u00e0i Node.js tr\u1ef1c ti\u1ebfp qua <code>apt install nodejs<\/code> kh\u00f4ng sai, nh\u01b0ng version th\u01b0\u1eddng b\u1ecb l\u1ed7i th\u1eddi so v\u1edbi LTS m\u1edbi nh\u1ea5t. Quan tr\u1ecdng h\u01a1n: khi b\u1ea1n ch\u1ea1y nhi\u1ec1u project Node.js tr\u00ean c\u00f9ng m\u1ed9t VPS v\u1edbi c\u00e1c version kh\u00e1c nhau (v\u00ed d\u1ee5: project A d\u00f9ng Node 18, project B d\u00f9ng Node 20), <code>apt<\/code> kh\u00f4ng th\u1ec3 x\u1eed l\u00fd \u0111\u01b0\u1ee3c. NVM sinh ra \u0111\u1ec3 gi\u1ea3i quy\u1ebft ch\u00ednh x\u00e1c v\u1ea5n \u0111\u1ec1 \u0111\u00f3.<\/p>\n<p>SSH v\u00e0o VPS b\u1eb1ng l\u1ec7nh <code>ssh root@[IP_VPS_CUA_BAN]<\/code>, sau \u0111\u00f3 c\u1eadp nh\u1eadt package <a href=\"https:\/\/interdata.vn\/blog\/list-trong-python\/\">list<\/a>:<\/p>\n<pre><code>apt update &amp;&amp; apt upgrade -y<\/code><\/pre>\n<p>C\u00e0i NVM b\u1eb1ng script ch\u00ednh th\u1ee9c t\u1eeb GitHub:<\/p>\n<pre><code>curl -o- https:\/\/raw.githubusercontent.com\/nvm-sh\/nvm\/v0.39.7\/install.sh | bash<\/code><\/pre>\n<p>Sau khi c\u00e0i xong, t\u1ea3i l\u1ea1i shell \u0111\u1ec3 NVM c\u00f3 hi\u1ec7u l\u1ef1c:<\/p>\n<pre><code>source ~\/.bashrc<\/code><\/pre>\n<p>Ki\u1ec3m tra NVM \u0111\u00e3 nh\u1eadn ch\u01b0a:<\/p>\n<pre><code>nvm --version<\/code><\/pre>\n<p>C\u00e0i Node.js phi\u00ean b\u1ea3n LTS m\u1edbi nh\u1ea5t:<\/p>\n<pre><code>nvm install --lts\r\nnvm use --lts<\/code><\/pre>\n<p>X\u00e1c nh\u1eadn phi\u00ean b\u1ea3n \u0111\u00e3 c\u00e0i:<\/p>\n<pre><code>node -v\r\nnpm -v<\/code><\/pre>\n<p>K\u1ebft qu\u1ea3 s\u1ebd tr\u1ea3 v\u1ec1 s\u1ed1 version \u2014 v\u00ed d\u1ee5 <code>v20.x.x<\/code> v\u00e0 <code>10.x.x<\/code>. N\u1ebfu th\u1ea5y output n\u00e0y, m\u00f4i tr\u01b0\u1eddng Node.js \u0111\u00e3 s\u1eb5n s\u00e0ng. L\u01b0u \u00fd: <strong>\u0111\u1eebng b\u1ecf qua b\u01b0\u1edbc <code>nvm use --lts<\/code><\/strong> \u2014 NVM cho ph\u00e9p c\u00e0i nhi\u1ec1u version c\u00f9ng l\u00fac, nh\u01b0ng b\u1ea1n ph\u1ea3i ch\u1ec9 \u0111\u1ecbnh version n\u00e0o \u0111ang d\u00f9ng trong session hi\u1ec7n t\u1ea1i.<\/p>\n<figure id=\"attachment_40354\" aria-describedby=\"caption-attachment-40354\" style=\"width: 379px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-40354\" src=\"https:\/\/interdata.vn\/blog\/wp-content\/uploads\/2026\/03\/NVM-cai-dat-thanh-cong.png\" alt=\"NVM c\u00e0i \u0111\u1eb7t th\u00e0nh c\u00f4ng\" width=\"379\" height=\"118\" title=\"\" srcset=\"https:\/\/interdata.vn\/blog\/wp-content\/uploads\/2026\/03\/NVM-cai-dat-thanh-cong.png 379w, https:\/\/interdata.vn\/blog\/wp-content\/uploads\/2026\/03\/NVM-cai-dat-thanh-cong-300x93.png 300w\" sizes=\"auto, (max-width: 379px) 100vw, 379px\" \/><figcaption id=\"caption-attachment-40354\" class=\"wp-caption-text\">NVM c\u00e0i \u0111\u1eb7t th\u00e0nh c\u00f4ng<\/figcaption><\/figure>\n<p><!-- B\u01af\u1edaC 2 --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Buoc-2-Clone-Source-Code-Cau-hinh-env-va-Cai-thu-vien\"><\/span>B\u01b0\u1edbc 2: Clone Source Code, C\u1ea5u h\u00ecnh .env v\u00e0 C\u00e0i th\u01b0 vi\u1ec7n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Dua-code-len-VPS-va-bao-mat-file-moi-truong\"><\/span>\u0110\u01b0a code l\u00ean VPS v\u00e0 b\u1ea3o m\u1eadt file m\u00f4i tr\u01b0\u1eddng<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>T\u1ea1o th\u01b0 m\u1ee5c ch\u1ee9a project t\u1ea1i <code>\/var\/www\/<\/code> \u2014 \u0111\u00e2y l\u00e0 convention chu\u1ea9n tr\u00ean Linux cho <a href=\"https:\/\/interdata.vn\/blog\/web-application-la-gi\/\">web application<\/a>:<\/p>\n<pre><code>mkdir -p \/var\/www\/my-app\r\ncd \/var\/www\/my-app<\/code><\/pre>\n<p>K\u00e9o source code t\u1eeb GitHub v\u1ec1:<\/p>\n<pre><code>git clone https:\/\/github.com\/[USERNAME]\/[REPO_NAME] .<\/code><\/pre>\n<p>D\u1ea5u ch\u1ea5m (<code>.<\/code>) cu\u1ed1i l\u1ec7nh c\u00f3 ngh\u0129a l\u00e0 clone v\u00e0o th\u01b0 m\u1ee5c hi\u1ec7n t\u1ea1i thay v\u00ec t\u1ea1o <a href=\"https:\/\/interdata.vn\/blog\/subfolder-la-gi\/\">subfolder<\/a> m\u1edbi. Sau khi clone xong, c\u00e0i dependencies:<\/p>\n<pre><code>npm install<\/code><\/pre>\n<p><strong>Quan tr\u1ecdng \u2014 file <code>.env<\/code>:<\/strong> Tuy\u1ec7t \u0111\u1ed1i kh\u00f4ng push file <code>.env<\/code> l\u00ean Git. Tr\u00ean VPS, b\u1ea1n ph\u1ea3i t\u1ea1o th\u1ee7 c\u00f4ng:<\/p>\n<pre><code>nano .env<\/code><\/pre>\n<p>\u0110i\u1ec1n v\u00e0o c\u00e1c bi\u1ebfn m\u00f4i tr\u01b0\u1eddng nh\u01b0 <code>PORT<\/code>, <code>DATABASE_URL<\/code>, <code>JWT_SECRET<\/code>&#8230; \u0111\u00fang v\u1edbi m\u00f4i tr\u01b0\u1eddng production. L\u01b0u b\u1eb1ng <code>Ctrl+O<\/code>, tho\u00e1t b\u1eb1ng <code>Ctrl+X<\/code>.<\/p>\n<p>N\u1ebfu project d\u00f9ng TypeScript ho\u1eb7c NestJS, c\u1ea7n build tr\u01b0\u1edbc khi ch\u1ea1y:<\/p>\n<pre><code>npm run build<\/code><\/pre>\n<p>L\u1ec7nh n\u00e0y t\u1ea1o th\u01b0 m\u1ee5c <code>dist\/<\/code> ch\u1ee9a <a href=\"https:\/\/interdata.vn\/blog\/javascript-la-gi\/\">JavaScript<\/a> \u0111\u00e3 bi\u00ean d\u1ecbch. B\u01b0\u1edbc kh\u1edfi ch\u1ea1y PM2 ph\u00eda sau s\u1ebd tr\u1ecf v\u00e0o file trong <code>dist\/<\/code> thay v\u00ec file TypeScript g\u1ed1c.<\/p>\n<p><!-- B\u01af\u1edaC 3 --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Buoc-3-Giu-app-Nodejs-luon-chay-ngam-voi-PM2\"><\/span>B\u01b0\u1edbc 3: Gi\u1eef app Node.js lu\u00f4n ch\u1ea1y ng\u1ea7m v\u1edbi PM2<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"PM2-la-gi-va-tai-sao-bat-buoc-phai-dung-khi-deploy-Nodejs\"><\/span>PM2 l\u00e0 g\u00ec v\u00e0 t\u1ea1i sao b\u1eaft bu\u1ed9c ph\u1ea3i d\u00f9ng khi deploy Node.js?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>PM2 l\u00e0 Process Manager chuy\u00ean d\u1ee5ng cho Node.js, cho ph\u00e9p \u1ee9ng d\u1ee5ng ch\u1ea1y n\u1ec1n (daemonize) \u0111\u1ed9c l\u1eadp v\u1edbi phi\u00ean SSH, t\u1ef1 \u0111\u1ed9ng restart khi app crash, v\u00e0 t\u1ef1 kh\u1edfi \u0111\u1ed9ng l\u1ea1i sau khi VPS reboot. \u0110\u00e2y l\u00e0 l\u00fd do PM2 tr\u1edf th\u00e0nh ti\u00eau chu\u1ea9n production thay cho l\u1ec7nh <code>node app.js<\/code> tr\u1ef1c ti\u1ebfp: khi ch\u1ea1y b\u1eb1ng <code>node<\/code> thu\u1ea7n, process s\u1ebd ch\u1ebft ngay khi \u0111\u00f3ng terminal \u2014 PM2 t\u00e1ch bi\u1ec7t ho\u00e0n to\u00e0n v\u00f2ng \u0111\u1eddi c\u1ee7a \u1ee9ng d\u1ee5ng kh\u1ecfi phi\u00ean SSH.<\/p>\n<p>C\u00e0i PM2 to\u00e0n c\u1ee5c:<\/p>\n<pre><code>npm install pm2 -g<\/code><\/pre>\n<p>Kh\u1edfi ch\u1ea1y \u1ee9ng d\u1ee5ng v\u1edbi PM2 (thay <code>app.js<\/code> b\u1eb1ng entry point th\u1ef1c t\u1ebf c\u1ee7a project, v\u00ed d\u1ee5 <code>dist\/main.js<\/code> v\u1edbi NestJS):<\/p>\n<pre><code>pm2 start app.js --name \"my-app\"<\/code><\/pre>\n<p>Xem tr\u1ea1ng th\u00e1i \u0111\u1ec3 x\u00e1c nh\u1eadn app \u0111ang ch\u1ea1y:<\/p>\n<pre><code>pm2 status<\/code><\/pre>\n<p>C\u1ed9t <code>status<\/code> hi\u1ec7n <code>online<\/code> l\u00e0 th\u00e0nh c\u00f4ng. B\u01b0\u1edbc quan tr\u1ecdng ti\u1ebfp theo \u2014 l\u01b0u c\u1ea5u h\u00ecnh v\u00e0 \u0111\u0103ng k\u00fd startup:<\/p>\n<pre><code>pm2 save\r\npm2 startup<\/code><\/pre>\n<p>L\u1ec7nh <code>pm2 startup<\/code> s\u1ebd in ra m\u1ed9t l\u1ec7nh <code>sudo env PATH=...<\/code> \u2014 b\u1ea1n c\u1ea7n <strong>copy v\u00e0 ch\u1ea1y l\u1ec7nh \u0111\u00f3<\/strong> \u0111\u1ec3 PM2 t\u1ef1 kh\u1edfi \u0111\u1ed9ng sau khi VPS reboot. Nhi\u1ec1u ng\u01b0\u1eddi b\u1ecf qua b\u01b0\u1edbc n\u00e0y, r\u1ed3i th\u1eafc m\u1eafc t\u1ea1i sao web t\u1eaft sau khi restart VPS. \u0110\u1eebng b\u1ecf qua.<\/p>\n<p>M\u1ed9t v\u00e0i l\u1ec7nh PM2 h\u1eefu d\u1ee5ng khi v\u1eadn h\u00e0nh:<\/p>\n<ul>\n<li><code>pm2 logs my-app<\/code> \u2014 xem log realtime<\/li>\n<li><code>pm2 restart my-app<\/code> \u2014 restart app (d\u00f9ng khi deploy l\u1ea1i)<\/li>\n<li><code>pm2 monit<\/code> \u2014 dashboard theo d\u00f5i <a href=\"https:\/\/interdata.vn\/blog\/cpu-server\/\">CPU<\/a>, <a href=\"https:\/\/interdata.vn\/blog\/ram-server\/\">RAM<\/a> theo th\u1eddi gian th\u1ef1c<\/li>\n<\/ul>\n<p><!-- B\u01af\u1edaC 4 --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Buoc-4-Cau-hinh-Nginx-lam-Reverse-Proxy-va-mo-Firewall\"><\/span>B\u01b0\u1edbc 4: C\u1ea5u h\u00ecnh Nginx l\u00e0m Reverse Proxy v\u00e0 m\u1edf Firewall<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Reverse-Proxy-trong-Nginx-dong-vai-tro-gi\"><\/span>Reverse Proxy trong Nginx \u0111\u00f3ng vai tr\u00f2 g\u00ec?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nginx ho\u1ea1t \u0111\u1ed9ng nh\u01b0 c\u1ea7u n\u1ed1i gi\u1eefa internet v\u00e0 \u1ee9ng d\u1ee5ng Node.js \u0111ang l\u1eafng nghe tr\u00ean port n\u1ed9i b\u1ed9 (th\u01b0\u1eddng l\u00e0 3000). Thay v\u00ec ng\u01b0\u1eddi d\u00f9ng ph\u1ea3i g\u00f5 <code>yourdomain.com:3000<\/code>, Nginx nh\u1eadn request tr\u00ean port 80 (HTTP) ho\u1eb7c 443 (HTTPS) r\u1ed3i chuy\u1ec3n ti\u1ebfp (<code>proxy_pass<\/code>) v\u1ec1 <code>localhost:3000<\/code>. Ngo\u00e0i ra, Nginx c\u00f2n x\u1eed l\u00fd t\u1ed1t h\u01a1n Node.js trong vi\u1ec7c serve static files, x\u1eed l\u00fd SSL termination, v\u00e0 ch\u1ecbu t\u1ea3i connection \u0111\u1ed3ng th\u1eddi \u2014 \u0111\u00e2y l\u00e0 l\u00fd do stack production lu\u00f4n \u0111\u1eb7t Nginx ph\u00eda tr\u01b0\u1edbc Node.js thay v\u00ec expose tr\u1ef1c ti\u1ebfp.<\/p>\n<p>C\u00e0i Nginx:<\/p>\n<pre><code>apt install nginx -y<\/code><\/pre>\n<p>T\u1ea1o file c\u1ea5u h\u00ecnh cho domain (thay <code>yourdomain.com<\/code> b\u1eb1ng domain th\u1ef1c c\u1ee7a b\u1ea1n):<\/p>\n<pre><code>nano \/etc\/nginx\/sites-available\/yourdomain.com<\/code><\/pre>\n<p>D\u00e1n v\u00e0o n\u1ed9i dung Server Block sau:<\/p>\n<pre><code>server {\r\n    listen 80;\r\n    server_name yourdomain.com <a href=\"https:\/\/interdata.vn\/blog\/world-wide-web\/\">www<\/a>.yourdomain.com;\r\n\r\n    location \/ {\r\n        proxy_pass http:\/\/localhost:3000;\r\n        proxy_http_version 1.1;\r\n        proxy_set_header Upgrade $http_upgrade;\r\n        proxy_set_header Connection 'upgrade';\r\n        proxy_set_header Host $host;\r\n        proxy_set_header X-Real-IP $remote_addr;\r\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\r\n        proxy_set_header X-Forwarded-Proto $scheme;\r\n        proxy_cache_bypass $http_upgrade;\r\n    }\r\n}<\/code><\/pre>\n<p>K\u00edch ho\u1ea1t c\u1ea5u h\u00ecnh b\u1eb1ng c\u00e1ch t\u1ea1o symlink sang <code>sites-enabled<\/code>:<\/p>\n<pre><code>ln -s \/etc\/nginx\/sites-available\/yourdomain.com \/etc\/nginx\/sites-enabled\/\r\nnginx -t<\/code><\/pre>\n<p>L\u1ec7nh <code>nginx -t<\/code> ki\u1ec3m tra syntax. N\u1ebfu output tr\u1ea3 v\u1ec1 <code>syntax is ok<\/code> v\u00e0 <code>test is successful<\/code>, m\u1edbi reload:<\/p>\n<pre><code>systemctl reload nginx<\/code><\/pre>\n<p><strong>M\u1edf Firewall UFW \u2014 b\u01b0\u1edbc hay b\u1ecb qu\u00ean:<\/strong> Sau khi c\u00e0i Nginx, c\u1ea7n c\u1ea5p quy\u1ec1n cho UFW m\u1edbi nh\u1eadn \u0111\u01b0\u1ee3c request t\u1eeb ngo\u00e0i v\u00e0o:<\/p>\n<pre><code>ufw allow 'Nginx Full'\r\nufw allow OpenSSH\r\nufw enable\r\nufw status<\/code><\/pre>\n<p>L\u1ec7nh <code>Nginx Full<\/code> m\u1edf c\u1ea3 port 80 l\u1eabn 443. L\u1ec7nh <code>OpenSSH<\/code> b\u1eaft bu\u1ed9c ph\u1ea3i allow tr\u01b0\u1edbc khi enable UFW \u2014 n\u1ebfu kh\u00f4ng, b\u1ea1n s\u1ebd b\u1ecb lock out kh\u1ecfi ch\u00ednh VPS c\u1ee7a m\u00ecnh qua SSH.<\/p>\n<p><!-- B\u01af\u1edaC 5 --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Buoc-5-Cai-dat-chung-chi-SSL-HTTPS-mien-phi-voi-Certbot\"><\/span>B\u01b0\u1edbc 5: C\u00e0i \u0111\u1eb7t ch\u1ee9ng ch\u1ec9 SSL HTTPS mi\u1ec5n ph\u00ed v\u1edbi Certbot<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Bao-mat-ung-dung-bang-Lets-Encrypt\"><\/span>B\u1ea3o m\u1eadt \u1ee9ng d\u1ee5ng b\u1eb1ng Let&#8217;s Encrypt<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Let&#8217;s Encrypt l\u00e0 <a href=\"https:\/\/interdata.vn\/blog\/certificate-authority-ca-la-gi\/\">Certificate Authority<\/a> phi l\u1ee3i nhu\u1eadn cung c\u1ea5p SSL mi\u1ec5n ph\u00ed, \u0111\u01b0\u1ee3c tin c\u1eady b\u1edfi t\u1ea5t c\u1ea3 tr\u00ecnh duy\u1ec7t hi\u1ec7n \u0111\u1ea1i. Certbot l\u00e0 tool ch\u00ednh th\u1ee9c \u0111\u1ec3 xin v\u00e0 t\u1ef1 \u0111\u1ed9ng gia h\u1ea1n ch\u1ee9ng ch\u1ec9 n\u00e0y. Quan tr\u1ecdng: domain c\u1ee7a b\u1ea1n ph\u1ea3i resolve v\u1ec1 \u0111\u00fang IP VPS tr\u01b0\u1edbc b\u01b0\u1edbc n\u00e0y, n\u1ebfu kh\u00f4ng Certbot s\u1ebd kh\u00f4ng x\u00e1c th\u1ef1c \u0111\u01b0\u1ee3c v\u00e0 tr\u1ea3 l\u1ed7i.<\/p>\n<p>C\u00e0i Certbot v\u1edbi <a href=\"https:\/\/interdata.vn\/blog\/plugin-la-gi\/\">plugin<\/a> Nginx:<\/p>\n<pre><code>apt install python3-certbot-nginx -y<\/code><\/pre>\n<p>Ch\u1ea1y l\u1ec7nh c\u1ea5p ch\u1ee9ng ch\u1ec9 (thay b\u1eb1ng domain th\u1ef1c):<\/p>\n<pre><code>certbot --nginx -d yourdomain.com -d www.yourdomain.com<\/code><\/pre>\n<p>Certbot s\u1ebd h\u1ecfi email \u0111\u1ec3 nh\u1eadn th\u00f4ng b\u00e1o khi ch\u1ee9ng ch\u1ec9 s\u1eafp h\u1ebft h\u1ea1n, sau \u0111\u00f3 t\u1ef1 \u0111\u1ed9ng ch\u1ec9nh s\u1eeda file c\u1ea5u h\u00ecnh Nginx, b\u1ed5 sung SSL v\u00e0 redirect HTTP sang HTTPS. Kh\u00f4ng c\u1ea7n ch\u1ec9nh th\u1ee7 c\u00f4ng.<\/p>\n<p>Ki\u1ec3m tra ch\u1ee9ng ch\u1ec9 \u0111\u00e3 \u0111\u01b0\u1ee3c c\u00e0i \u0111\u00fang:<\/p>\n<pre><code>certbot certificates<\/code><\/pre>\n<p>Ch\u1ee9ng ch\u1ec9 Let&#8217;s Encrypt c\u00f3 th\u1eddi h\u1ea1n 90 ng\u00e0y. Certbot t\u1ef1 c\u00e0i cronjob \u0111\u1ec3 gia h\u1ea1n t\u1ef1 \u0111\u1ed9ng \u2014 b\u1ea1n kh\u00f4ng c\u1ea7n l\u00e0m g\u00ec th\u00eam. \u0110\u1ec3 ki\u1ec3m tra qu\u00e1 tr\u00ecnh gia h\u1ea1n c\u00f3 ho\u1ea1t \u0111\u1ed9ng kh\u00f4ng:<\/p>\n<pre><code>certbot renew --dry-run<\/code><\/pre>\n<p>N\u1ebfu kh\u00f4ng c\u00f3 l\u1ed7i, \u1ee9ng d\u1ee5ng Node.js c\u1ee7a b\u1ea1n \u0111\u00e3 ch\u1ea1y tr\u00ean HTTPS \u0111\u1ea7y \u0111\u1ee7. Truy c\u1eadp <code>https:\/\/yourdomain.com<\/code> \u0111\u1ec3 x\u00e1c nh\u1eadn bi\u1ec3u t\u01b0\u1ee3ng kh\u00f3a xanh tr\u00ean tr\u00ecnh duy\u1ec7t.<\/p>\n<p><!-- CTA BOX --><\/p>\n<div style=\"background: linear-gradient(135deg, #1a3c6e 0%, #0f6cbf 100%); border-radius: 12px; padding: 28px 32px; margin: 40px 0; max-width: 100%; box-shadow: 0 4px 20px rgba(15,108,191,0.25);\">\n<div style=\"display: inline-block; background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); border-radius: 20px; padding: 4px 14px; margin-bottom: 16px;\"><span style=\"color: #ffffff; font-size: 12px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase;\">InterData<\/span><\/div>\n<h3 style=\"color: #ffffff; font-size: 22px; font-weight: bold; margin: 0 0 8px 0; line-height: 1.3;\"><span class=\"ez-toc-section\" id=\"VPS-Gia-Re-InterData-%E2%80%94-San-Sang-Deploy-Nodejs-Ngay\"><\/span>VPS Gi\u00e1 R\u1ebb InterData \u2014 S\u1eb5n S\u00e0ng Deploy Node.js Ngay<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p style=\"color: rgba(255,255,255,0.85); font-size: 15px; margin: 0 0 20px 0; line-height: 1.6;\">VPS gi\u00e1 r\u1ebb t\u1ea1i InterData \u0111\u01b0\u1ee3c c\u00e0i s\u1eb5n Ubuntu 22.04\/24.04, k\u1ebft n\u1ed1i b\u0103ng th\u00f4ng t\u1ed1c \u0111\u1ed9 cao, datacenter \u0111\u1eb7t t\u1ea1i H\u00e0 N\u1ed9i v\u00e0 TP.HCM \u2014 th\u00edch h\u1ee3p \u0111\u1ec3 tri\u1ec3n khai Node.js, NestJS, Express theo h\u01b0\u1edbng d\u1eabn n\u00e0y.<\/p>\n<ul style=\"list-style: none; padding: 0; margin: 0 0 24px 0;\">\n<li style=\"color: rgba(255,255,255,0.9); font-size: 14px; padding: 5px 0; display: flex; align-items: flex-start;\"><span style=\"color: #4fc3f7; font-size: 16px; margin-right: 8px; flex-shrink: 0;\">\u2713<\/span>\u1ed4 c\u1ee9ng SSD NVMe U.2 \u2014 I\/O nhanh, ph\u00f9 h\u1ee3p Node.js k\u00e8m database<\/li>\n<li style=\"color: rgba(255,255,255,0.9); font-size: 14px; padding: 5px 0; display: flex; align-items: flex-start;\"><span style=\"color: #4fc3f7; font-size: 16px; margin-right: 8px; flex-shrink: 0;\">\u2713<\/span>To\u00e0n quy\u1ec1n qu\u1ea3n tr\u1ecb VPS, t\u1ef1 do c\u00e0i PM2, Nginx, Certbot<\/li>\n<li style=\"color: rgba(255,255,255,0.9); font-size: 14px; padding: 5px 0; display: flex; align-items: flex-start;\"><span style=\"color: #4fc3f7; font-size: 16px; margin-right: 8px; flex-shrink: 0;\">\u2713<\/span>H\u1ed7 tr\u1ee3 k\u1ef9 thu\u1eadt 24\/7 \u2014 hotline v\u00e0 ticket<\/li>\n<\/ul>\n<p><a style=\"display: inline-block; background: #ffffff; color: #1a3c6e; font-size: 15px; font-weight: bold; text-decoration: none; padding: 12px 28px; border-radius: 8px;\" href=\"https:\/\/interdata.vn\/thue-vps\/\" target=\"_blank\" rel=\"noopener\">Tham Kh\u1ea3o C\u00e1c G\u00f3i VPS Gi\u00e1 R\u1ebb \u2192<\/a><\/p>\n<\/div>\n<p><!-- FAQs --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"FAQs-%E2%80%94-Cau-hoi-thuong-gap-khi-deploy-ung-dung-Nodejs\"><\/span>FAQs \u2014 C\u00e2u h\u1ecfi th\u01b0\u1eddng g\u1eb7p khi deploy \u1ee9ng d\u1ee5ng Node.js<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Cap-nhat-code-moi-len-VPS-deploy-lai-nhu-the-nao\"><\/span>C\u1eadp nh\u1eadt code m\u1edbi l\u00ean VPS (deploy l\u1ea1i) nh\u01b0 th\u1ebf n\u00e0o?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Quy tr\u00ecnh deploy l\u1ea1i \u0111\u01a1n gi\u1ea3n h\u01a1n l\u1ea7n \u0111\u1ea7u nhi\u1ec1u. SSH v\u00e0o VPS, di chuy\u1ec3n v\u00e0o th\u01b0 m\u1ee5c project r\u1ed3i k\u00e9o code m\u1edbi v\u1ec1:<\/p>\n<pre><code>cd \/var\/www\/my-app\r\ngit pull origin main<\/code><\/pre>\n<p>N\u1ebfu c\u00f3 th\u00eam dependency m\u1edbi, ch\u1ea1y <code>npm install<\/code>. V\u1edbi project TypeScript\/NestJS, c\u1ea7n build l\u1ea1i: <code>npm run build<\/code>. Sau \u0111\u00f3 restart app qua PM2:<\/p>\n<pre><code>pm2 restart my-app<\/code><\/pre>\n<p>PM2 s\u1ebd t\u1ea3i version m\u1edbi l\u00ean trong kho\u1ea3ng v\u00e0i gi\u00e2y, downtime g\u1ea7n nh\u01b0 b\u1eb1ng kh\u00f4ng. N\u1ebfu mu\u1ed1n zero-downtime deployment, d\u00f9ng l\u1ec7nh <code>pm2 reload my-app<\/code> thay v\u00ec <code>restart<\/code>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Lam-sao-de-xem-nguyen-nhan-app-Nodejs-bi-sap-tren-VPS\"><\/span>L\u00e0m sao \u0111\u1ec3 xem nguy\u00ean nh\u00e2n app Node.js b\u1ecb s\u1eadp tr\u00ean VPS?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>D\u00f9ng l\u1ec7nh <code>pm2 logs my-app<\/code> \u0111\u1ec3 xem log realtime ngay tr\u00ean terminal. PM2 s\u1ebd hi\u1ec3n th\u1ecb ch\u00ednh x\u00e1c stack trace c\u1ee7a l\u1ed7i, bao g\u1ed3m t\u00ean file v\u00e0 s\u1ed1 d\u00f2ng g\u00e2y ra crash. N\u1ebfu mu\u1ed1n xem log c\u1ee7a c\u00e1c l\u1ea7n s\u1eadp tr\u01b0\u1edbc \u0111\u00f3 (kh\u00f4ng ch\u1ec9 session hi\u1ec7n t\u1ea1i), th\u00eam flag <code>--lines 200<\/code> \u0111\u1ec3 l\u1ea5y 200 d\u00f2ng g\u1ea7n nh\u1ea5t:<\/p>\n<pre><code>pm2 logs my-app --lines 200<\/code><\/pre>\n<p>L\u1ec7nh <code>pm2 monit<\/code> m\u1edf dashboard theo d\u00f5i CPU, RAM v\u00e0 log \u0111\u1ed3ng th\u1eddi \u2014 ti\u1ec7n h\u01a1n khi c\u1ea7n quan s\u00e1t l\u00e2u d\u00e0i thay v\u00ec ch\u1ec9 debug m\u1ed9t s\u1ef1 c\u1ed1 c\u1ee5 th\u1ec3.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"App-Nodejs-ngon-qua-nhieu-RAM-cua-VPS-thi-xu-ly-sao\"><\/span>App Node.js ng\u1ed1n qu\u00e1 nhi\u1ec1u RAM c\u1ee7a VPS th\u00ec x\u1eed l\u00fd sao?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>PM2 c\u00f3 t\u00ednh n\u0103ng gi\u1edbi h\u1ea1n RAM v\u00e0 t\u1ef1 restart khi v\u01b0\u1ee3t ng\u01b0\u1ee1ng \u2014 h\u1eefu \u00edch khi app c\u00f3 memory leak ho\u1eb7c x\u1eed l\u00fd request l\u1edbn kh\u00f4ng gi\u1ea3i ph\u00f3ng memory \u0111\u00fang c\u00e1ch:<\/p>\n<pre><code>pm2 start app.js --name \"my-app\" --max-memory-restart 500M<\/code><\/pre>\n<p>Thay <code>500M<\/code> b\u1eb1ng m\u1ee9c gi\u1edbi h\u1ea1n ph\u00f9 h\u1ee3p v\u1edbi g\u00f3i VPS \u0111ang d\u00f9ng. Tuy nhi\u00ean n\u1ebfu app li\u00ean t\u1ee5c restart v\u00ec RAM, \u0111\u00f3 l\u00e0 d\u1ea5u hi\u1ec7u c\u1ea7n xem l\u1ea1i code ho\u1eb7c n\u00e2ng c\u1ea5p c\u1ea5u h\u00ecnh VPS \u2014 <code>--max-memory-restart<\/code> ch\u1ec9 l\u00e0 gi\u1ea3i ph\u00e1p t\u1ea1m th\u1eddi, kh\u00f4ng ph\u1ea3i v\u00e1 l\u1ed7i g\u1ed1c.<\/p>\n<p><!-- K\u1ebeT LU\u1eacN --><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Ket-luan\"><\/span>K\u1ebft lu\u1eadn<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Tri\u1ec3n khai Node.js tr\u00ean VPS chu\u1ea9n production kh\u00f4ng ph\u1ee9c t\u1ea1p khi b\u1ea1n hi\u1ec3u r\u00f5 vai tr\u00f2 c\u1ee7a t\u1eebng th\u00e0nh ph\u1ea7n: <strong>NVM<\/strong> qu\u1ea3n l\u00fd m\u00f4i tr\u01b0\u1eddng linh ho\u1ea1t, <strong>PM2<\/strong> \u0111\u1ea3m b\u1ea3o app kh\u00f4ng bao gi\u1edd t\u1eaft ngo\u00e0i \u00fd mu\u1ed1n, <strong>Nginx<\/strong> \u0111\u1ee9ng tr\u01b0\u1edbc l\u00e0m Reverse Proxy v\u00e0 x\u1eed l\u00fd SSL termination, <strong>Certbot<\/strong> c\u1ea5p HTTPS mi\u1ec5n ph\u00ed t\u1ef1 \u0111\u1ed9ng gia h\u1ea1n. B\u1ed1n th\u1ee9 n\u00e0y k\u1ebft h\u1ee3p v\u1edbi nhau t\u1ea1o ra stack v\u1eeba \u1ed5n \u0111\u1ecbnh v\u1eeba b\u1ea3o m\u1eadt \u2014 \u0111\u1ee7 \u0111\u1ec3 go-live th\u1ef1c s\u1ef1, kh\u00f4ng ch\u1ec9 ch\u1ea1y th\u1eed.<\/p>\n<p>M\u1ed9t \u0111i\u1ec3m d\u1ec5 b\u1ecf qua: sau b\u01b0\u1edbc <code>pm2 startup<\/code>, nh\u1edb ch\u1ea1y l\u1ec7nh sudo m\u00e0 PM2 in ra \u2014 \u0111\u00e2y l\u00e0 b\u01b0\u1edbc \u0111\u0103ng k\u00fd service v\u1edbi systemd \u0111\u1ec3 PM2 t\u1ef1 kh\u1edfi \u0111\u1ed9ng sau reboot. Thi\u1ebfu b\u01b0\u1edbc n\u00e0y, m\u1ecdi c\u1ea5u h\u00ecnh s\u1ebd b\u1ecb m\u1ea5t sau l\u1ea7n t\u1eaft m\u00e1y VPS \u0111\u1ea7u ti\u00ean.<\/p>\n<p>N\u1ebfu mu\u1ed1n \u0111i s\u00e2u h\u01a1n v\u00e0o ph\u1ea7n h\u1ea1 t\u1ea7ng, b\u00e0i <a href=\"https:\/\/interdata.vn\/blog\/huong-dan-su-dung-vps\/\" target=\"_blank\" rel=\"noopener\">c\u1ea9m nang s\u1eed d\u1ee5ng VPS t\u1eeb A \u0111\u1ebfn Z<\/a> s\u1ebd gi\u00fap b\u1ea1n n\u1eafm to\u00e0n c\u1ea3nh tr\u01b0\u1edbc khi b\u1eaft tay v\u00e0o c\u00e1c c\u1ea5u h\u00ecnh n\u00e2ng cao h\u01a1n nh\u01b0 <a href=\"https:\/\/interdata.vn\/blog\/load-balancing\/\">load balancing<\/a> ho\u1eb7c multi-process v\u1edbi PM2 cluster mode.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>T\u00f3m t\u1eaft nhanh: Deploy Node.js tr\u00ean VPS l\u00e0 qu\u00e1 tr\u00ecnh chuy\u1ec3n m\u00e3 ngu\u1ed3n \u1ee9ng d\u1ee5ng t\u1eeb m\u00e1y t\u00ednh c\u00e1 nh\u00e2n l\u00ean m\u00e1y ch\u1ee7 \u1ea3o ch\u1ea1y Linux \u0111\u1ec3 web ho\u1ea1t \u0111\u1ed9ng public tr\u00ean internet. \u0110\u1ec3 ch\u1ea1y \u1ed5n \u0111\u1ecbnh chu\u1ea9n production, quy tr\u00ecnh c\u1ea7n 4 th\u00e0nh ph\u1ea7n b\u1eaft bu\u1ed9c: Node.js c\u00e0i qua NVM (qu\u1ea3n l\u00fd m\u00f4i tr\u01b0\u1eddng),<\/p>\n","protected":false},"author":2,"featured_media":40353,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49],"tags":[],"class_list":["post-40320","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-vps"],"_links":{"self":[{"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/posts\/40320","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/comments?post=40320"}],"version-history":[{"count":6,"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/posts\/40320\/revisions"}],"predecessor-version":[{"id":40372,"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/posts\/40320\/revisions\/40372"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/media\/40353"}],"wp:attachment":[{"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/media?parent=40320"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/categories?post=40320"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/interdata.vn\/blog\/wp-json\/wp\/v2\/tags?post=40320"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}