<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[FromTiny's TechBlog]]></title><description><![CDATA[A journey of FromTiny to TinyPlus]]></description><link>https://www.fromtiny.com</link><image><url>https://substackcdn.com/image/fetch/$s_!7Kzk!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33089124-6e8e-4b9b-a10c-8ba06f962f5d_1280x1280.png</url><title>FromTiny&apos;s TechBlog</title><link>https://www.fromtiny.com</link></image><generator>Substack</generator><lastBuildDate>Thu, 28 May 2026 15:20:51 GMT</lastBuildDate><atom:link href="https://www.fromtiny.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[FromTiny Co., Ltd.]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[fromtiny@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[fromtiny@substack.com]]></itunes:email><itunes:name><![CDATA[Kiet Duong Hung]]></itunes:name></itunes:owner><itunes:author><![CDATA[Kiet Duong Hung]]></itunes:author><googleplay:owner><![CDATA[fromtiny@substack.com]]></googleplay:owner><googleplay:email><![CDATA[fromtiny@substack.com]]></googleplay:email><googleplay:author><![CDATA[Kiet Duong Hung]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[rsync - Khi scp không còn đủ dùng nữa]]></title><description><![CDATA[scp th&#236; copy. rsync th&#236; sync. Nghe t&#432;&#7903;ng gi&#7889;ng nhau - nh&#432;ng kh&#225;c nhau ho&#224;n to&#224;n khi m&#7885;i th&#7913; &#273;i sai.]]></description><link>https://www.fromtiny.com/p/rsync-khi-scp-khong-con-u-dung-nua</link><guid isPermaLink="false">https://www.fromtiny.com/p/rsync-khi-scp-khong-con-u-dung-nua</guid><dc:creator><![CDATA[Kiet Duong Hung]]></dc:creator><pubDate>Wed, 27 May 2026 18:05:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7Kzk!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33089124-6e8e-4b9b-a10c-8ba06f962f5d_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>B&#224;i tr&#432;&#7899;c t&#244;i vi&#7871;t v&#7873; <code>scp</code> - nhanh, g&#7885;n, kh&#244;ng c&#7847;n setup g&#236;. N&#7871;u b&#7841;n ch&#432;a &#273;&#7885;c, <a href="#">link &#7903; &#273;&#226;y</a>.</p><p>Nh&#432;ng th&#7853;t ra t&#244;i d&#249;ng <code>scp</code> ng&#224;y c&#224;ng &#237;t h&#417;n. Kh&#244;ng ph&#7843;i v&#236; n&#243; t&#7879;, m&#224; v&#236; <code>rsync</code> l&#224;m &#273;&#432;&#7907;c t&#7845;t c&#7843; nh&#7919;ng g&#236; <code>scp</code> l&#224;m, c&#7897;ng th&#234;m m&#7897;t &#273;&#7889;ng th&#7913; m&#224; <code>scp</code> kh&#244;ng bao gi&#7901; l&#224;m &#273;&#432;&#7907;c.</p><p>Hai c&#225;i hay nh&#7845;t: <strong>ch&#7881; transfer ph&#7847;n thay &#273;&#7893;i</strong> v&#224; <strong>resume &#273;&#432;&#7907;c khi &#273;&#7913;t k&#7871;t n&#7889;i</strong>. V&#7899;i file l&#7899;n ho&#7863;c deploy th&#432;&#7901;ng xuy&#234;n, hai &#273;i&#7875;m n&#224;y th&#244;i l&#224; &#273;&#7911; &#273;&#7875; chuy&#7875;n sang rsync r&#7891;i.</p><div><hr></div><h2>C&#250; ph&#225;p c&#417; b&#7843;n</h2><pre><code><code>rsync [options] source destination</code></code></pre><p>Nh&#236;n quen kh&#244;ng? &#272;&#250;ng r&#7891;i - gi&#7889;ng h&#7879;t <code>scp</code>. N&#7871;u b&#7841;n &#273;&#227; d&#249;ng scp th&#224;nh th&#7841;o th&#236; h&#7885;c rsync ch&#7881; m&#7845;t th&#234;m 10 ph&#250;t.</p><div><hr></div><h2>Trailing slash - th&#7913; g&#226;y confuse nhi&#7873;u nh&#7845;t</h2><p>&#272;&#226;y l&#224; &#273;i&#7875;m kh&#225;c bi&#7879;t l&#7899;n nh&#7845;t so v&#7899;i <code>scp</code>, v&#224; c&#361;ng l&#224; th&#7913; t&#244;i th&#7845;y m&#7885;i ng&#432;&#7901;i hay b&#7883; nh&#7847;m nh&#7845;t.</p><pre><code><code># C&#243; slash - copy N&#7896;I DUNG b&#234;n trong folder
rsync -av ./dist/ user@server:/var/www/
# K&#7871;t qu&#7843;: /var/www/index.html, /var/www/app.js ...

# Kh&#244;ng c&#243; slash &#8212; copy C&#7842; folder (k&#232;m t&#234;n)
rsync -av ./dist user@server:/var/www/
# K&#7871;t qu&#7843;: /var/www/dist/index.html, /var/www/dist/app.js ...</code></code></pre><p>Quy t&#7855;c &#273;&#417;n gi&#7843;n &#273;&#7875; nh&#7899;: <strong>d&#7845;u slash = m&#7903; folder ra, l&#7845;y n&#7897;i dung b&#234;n trong.</strong></p><p>Khi deploy web app, h&#7847;u h&#7871;t tr&#432;&#7901;ng h&#7907;p b&#7841;n mu&#7889;n c&#243; slash - copy n&#7897;i dung <code>dist/</code> th&#7859;ng v&#224;o <code>/var/www/</code>, kh&#244;ng ph&#7843;i t&#7841;o th&#234;m folder <code>dist</code> l&#7891;ng b&#234;n trong.</p><div><hr></div><h2>Combo m&#7863;c &#273;&#7883;nh n&#234;n d&#249;ng</h2><pre><code><code>rsync -avzP</code></code></pre><p>B&#7889;n flag n&#224;y t&#244;i g&#7847;n nh&#432; lu&#244;n d&#249;ng c&#249;ng nhau:</p><ul><li><p><code>-a</code> - Archive mode, g&#7897;p <code>-rlptgoD</code>: recursive + gi&#7919; nguy&#234;n permission, timestamps, symlinks...</p></li><li><p><code>-v</code> - Verbose, th&#7845;y file n&#224;o &#273;ang &#273;&#432;&#7907;c transfer</p></li><li><p><code>-z</code> - Compress, gi&#7843;m data transfer - h&#7919;u &#237;ch v&#7899;i file text, code</p></li><li><p><code>-P</code> - Hi&#7879;n progress bar + resume &#273;&#432;&#7907;c khi &#273;&#7913;t gi&#7919;a ch&#7915;ng</p></li></ul><div><hr></div><h2>C&#225;c options hay d&#249;ng</h2><ul><li><p><code>-n</code><strong> ho&#7863;c </strong><code>--dry-run</code> - Gi&#7843; l&#7853;p, kh&#244;ng th&#7921;c s&#7921; copy. Lu&#244;n ch&#7841;y c&#225;i n&#224;y tr&#432;&#7899;c khi th&#7921;c thi l&#7847;n &#273;&#7847;u</p></li><li><p><code>--delete</code> - X&#243;a file &#7903; &#273;&#237;ch n&#7871;u &#7903; ngu&#7891;n &#273;&#227; x&#243;a. D&#249;ng khi mu&#7889;n sync th&#7921;c s&#7921;</p></li><li><p><code>--exclude</code> - B&#7887; qua file/folder ch&#7881; &#273;&#7883;nh</p></li><li><p><code>--include</code> - Include l&#7841;i sau khi exclude</p></li><li><p><code>-e</code> - Ch&#7881; &#273;&#7883;nh SSH command (key, port)</p></li><li><p><code>--checksum</code> - So s&#225;nh b&#7857;ng checksum thay v&#236; size + timestamp</p></li><li><p><code>--bwlimit=1000</code> - Gi&#7899;i h&#7841;n bandwidth (KB/s)</p></li><li><p><code>--backup</code> - Backup file tr&#432;&#7899;c khi override</p></li></ul><div><hr></div><h2>Upload - Local to Remote</h2><pre><code><code># Upload folder build l&#234;n server
rsync -avzP ./dist/ ubuntu@server:/var/www/html/

# V&#7899;i SSH key
rsync -avzP -e "ssh -i ~/.ssh/key.pem" ./dist/ ubuntu@server:/var/www/html/

# V&#7899;i SSH config alias &#8212; ti&#7879;n nh&#7845;t
rsync -avzP ./dist/ myserver:/var/www/html/

# Dry run tr&#432;&#7899;c &#273;&#7875; ki&#7875;m tra
rsync -avzP --dry-run ./dist/ myserver:/var/www/html/</code></code></pre><div><hr></div><h2>Download - Remote to Local</h2><pre><code><code># Download folder t&#7915; server v&#7873;
rsync -avzP user@server:/var/www/html/ ./local-backup/

# Backup database dump
rsync -avzP user@db-server:/tmp/dumps/ ~/backups/db/

# Download log files
rsync -avzP user@server:/var/log/nginx/ ./logs/</code></code></pre><div><hr></div><h2><code>--delete</code> - Sync th&#7921;c s&#7921;</h2><p>M&#7863;c &#273;&#7883;nh rsync ch&#7881; th&#234;m v&#224; c&#7853;p nh&#7853;t, kh&#244;ng x&#243;a. Mu&#7889;n &#273;&#237;ch gi&#7889;ng h&#7879;t ngu&#7891;n:</p><pre><code><code>rsync -avzP --delete ./dist/ user@server:/var/www/html/</code></code></pre><blockquote><p>&#9888;&#65039; <strong>C&#7849;n th&#7853;n v&#7899;i </strong><code>--delete</code> - file &#7903; server m&#224; kh&#244;ng c&#243; &#7903; local s&#7869; b&#7883; x&#243;a v&#297;nh vi&#7877;n. Lu&#244;n <code>--dry-run</code> tr&#432;&#7899;c khi d&#249;ng l&#7847;n &#273;&#7847;u.</p></blockquote><pre><code><code># Ki&#7875;m tra tr&#432;&#7899;c
rsync -avzP --delete --dry-run ./dist/ user@server:/var/www/html/

# Th&#7845;y &#7893;n r&#7891;i m&#7899;i ch&#7841;y th&#7853;t
rsync -avzP --delete ./dist/ user@server:/var/www/html/</code></code></pre><div><hr></div><h2><code>--exclude</code> - B&#7887; qua file kh&#244;ng c&#7847;n thi&#7871;t</h2><pre><code><code># Exclude 1 folder
rsync -avzP --exclude 'node_modules' ./ user@server:/app/

# Exclude nhi&#7873;u th&#7913;
rsync -avzP \
  --exclude 'node_modules' \
  --exclude '.git' \
  --exclude '.env' \
  --exclude '*.log' \
  --exclude 'dist' \
  ./ user@server:/app/

# D&#249;ng file exclude &#8212; gi&#7889;ng .gitignore
rsync -avzP --exclude-from='.rsyncignore' ./ user@server:/app/</code></code></pre><p>File <code>.rsyncignore</code>:</p><pre><code><code>node_modules/
.git/
.env
*.log
dist/
__pycache__/
*.pyc</code></code></pre><div><hr></div><h2>Usecase th&#7921;c t&#7871;</h2><p><strong>Deploy web app</strong></p><pre><code><code>npm run build

rsync -avzP --delete \
  --exclude '.env' \
  ./dist/ ubuntu@myserver:/var/www/myapp/</code></code></pre><p><strong>Backup &#273;&#7883;nh k&#7923; v&#7899;i timestamp</strong></p><pre><code><code># Backup th&#7911; c&#244;ng
rsync -avzP user@server:/var/data/ ~/backups/$(date +%Y-%m-%d)/

# K&#7871;t h&#7907;p cron &#8212; backup m&#7895;i ng&#224;y l&#250;c 2am
# crontab -e
0 2 * * * rsync -avzP user@server:/var/data/ ~/backups/$(date +\%Y-\%m-\%d)/</code></code></pre><p><strong>Backup v&#7899;i </strong><code>--backup</code><strong> - gi&#7919; l&#7841;i file c&#361; tr&#432;&#7899;c khi overwrite</strong></p><pre><code><code>rsync -avzP --backup --backup-dir=/backup/$(date +%Y%m%d) \
  user@server:/important/ ./local/</code></code></pre><p><strong>Sync qua port SSH kh&#225;c</strong></p><pre><code><code>rsync -avzP -e "ssh -p 2222 -i ~/.ssh/key.pem" \
  ./dist/ user@server:/var/www/</code></code></pre><p><strong>Resume file l&#7899;n b&#7883; &#273;&#7913;t gi&#7919;a ch&#7915;ng</strong></p><p><code>-P</code> &#273;&#227; bao g&#7891;m <code>--partial</code> n&#234;n ch&#7881; c&#7847;n ch&#7841;y l&#7841;i &#273;&#250;ng l&#7879;nh c&#361; - rsync t&#7921; ti&#7871;p t&#7909;c t&#7915; ch&#7895; d&#7915;ng.</p><pre><code><code>rsync -avzP largefile.iso user@server:/tmp/
# B&#7883; &#273;&#7913;t &#8594; ch&#7841;y l&#7841;i y chang, n&#243; ti&#7871;p t&#7909;c t&#7915; ch&#7895; d&#7915;ng</code></code></pre><div><hr></div><h2>M&#7897;t l&#7895;i nh&#7887; trong b&#7843;n g&#7889;c</h2><p>Trong b&#7843;ng options ban &#273;&#7847;u c&#243; ghi <code>--postgres</code> - &#273;&#226;y l&#224; typo, kh&#244;ng c&#243; flag n&#224;o t&#234;n v&#7853;y. <code>-P</code> th&#7921;c ra l&#224; vi&#7871;t t&#7855;t c&#7911;a <code>--progress --partial</code>. T&#244;i &#273;&#227; s&#7917;a l&#7841;i trong b&#224;i n&#224;y r&#7891;i.</p><div><hr></div><p>V&#7853;y l&#224; xong ph&#7847;n core c&#7911;a rsync. T&#7915; gi&#7901; m&#7895;i khi deploy hay backup, thay <code>scp</code> b&#7857;ng <code>rsync -avzP</code> l&#224; an to&#224;n h&#417;n nhi&#7873;u r&#7891;i.</p><p>B&#224;i ti&#7871;p theo t&#244;i s&#7869; vi&#7871;t v&#7873; <code>step-ca</code> - t&#7921; d&#7921;ng private Certificate Authority cho internal services. N&#7871;u b&#7841;n &#273;ang ch&#7841;y homelab ho&#7863;c internal tooling, b&#224;i &#273;&#243; s&#7869; h&#7919;u &#237;ch.</p>]]></content:encoded></item><item><title><![CDATA[scp - Cách copy file qua SSH mà dev nào cũng nên biết]]></title><description><![CDATA[Kh&#244;ng ph&#7843;i man page &#8212; ch&#7881; nh&#7919;ng th&#7913; t&#244;i th&#7921;c s&#7921; d&#249;ng trong c&#244;ng vi&#7879;c h&#224;ng ng&#224;y.]]></description><link>https://www.fromtiny.com/p/scp-cach-copy-file-qua-ssh-ma-dev</link><guid isPermaLink="false">https://www.fromtiny.com/p/scp-cach-copy-file-qua-ssh-ma-dev</guid><dc:creator><![CDATA[Kiet Duong Hung]]></dc:creator><pubDate>Wed, 27 May 2026 17:59:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7Kzk!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33089124-6e8e-4b9b-a10c-8ba06f962f5d_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>N&#7871;u b&#7841;n &#273;ang l&#224;m vi&#7879;c v&#7899;i server Linux, s&#7899;m mu&#7897;n g&#236; b&#7841;n c&#361;ng s&#7869; c&#7847;n chuy&#7875;n file qua l&#7841;i gi&#7919;a m&#225;y local v&#224; remote. C&#243; nhi&#7873;u c&#225;ch &#273;&#7875; l&#224;m &#273;i&#7873;u n&#224;y - FTP, rsync, SFTP client c&#243; GUI - nh&#432;ng <code>scp</code> v&#7851;n l&#224; th&#7913; t&#244;i d&#249;ng nhi&#7873;u nh&#7845;t v&#236; l&#253; do &#273;&#417;n gi&#7843;n: <strong>n&#243; c&#243; s&#7861;n &#7903; kh&#7855;p n&#417;i, kh&#244;ng c&#7847;n c&#224;i th&#234;m g&#236;, v&#224; c&#250; ph&#225;p &#273;&#7911; ng&#7855;n &#273;&#7875; nh&#7899;.</strong></p><p>B&#224;i n&#224;y kh&#244;ng ph&#7843;i man page. T&#244;i s&#7869; ch&#7881; ghi l&#7841;i nh&#7919;ng th&#7913; t&#244;i th&#7921;c s&#7921; d&#249;ng trong c&#244;ng vi&#7879;c h&#224;ng ng&#224;y.</p><div><hr></div><h2>SCP l&#224; g&#236;?</h2><p><code>scp</code> (Secure Copy Protocol) l&#224; c&#244;ng c&#7909; copy file ch&#7841;y tr&#234;n n&#7873;n SSH. Ngh&#297;a l&#224; m&#7885;i th&#7913; b&#7841;n transfer &#273;&#7873;u &#273;&#432;&#7907;c m&#227; h&#243;a, v&#224; b&#7841;n d&#249;ng l&#7841;i &#273;&#250;ng SSH key/config m&#224; b&#7841;n &#273;&#227; c&#243; - kh&#244;ng c&#7847;n setup th&#234;m g&#236;.</p><div><hr></div><h2>C&#250; ph&#225;p c&#417; b&#7843;n</h2><pre><code><code>scp [options] source destination</code></code></pre><p>Trong &#273;&#243; <code>source</code> ho&#7863;c <code>destination</code> c&#243; th&#7875; l&#224; local ho&#7863;c <code>user@host:path</code>. Ch&#7881; c&#7847;n nh&#7899; quy t&#7855;c n&#224;y l&#224; d&#249;ng &#273;&#432;&#7907;c 90% c&#225;c tr&#432;&#7901;ng h&#7907;p.</p><div><hr></div><h2>Upload - Local to Remote</h2><pre><code><code># Copy 1 file
scp file.txt user@192.168.1.10:/home/user/

# Copy v&#224;o th&#432; m&#7909;c c&#7909; th&#7875; v&#7899;i t&#234;n m&#7899;i
scp file.txt user@192.168.1.10:/home/user/newname.txt

# Copy c&#7843; folder (recursive)
scp -r ./myproject user@192.168.1.10:/home/user/

# D&#249;ng SSH key thay v&#236; password
scp -i ~/.ssh/my_key.pem file.txt ubuntu@13.214.x.x:/home/ubuntu/
</code></code></pre><blockquote><p><strong>L&#432;u &#253; nh&#7887;:</strong> N&#7871;u b&#7841;n &#273;&#227; config <code>~/.ssh/config</code> v&#7899;i alias cho server th&#236; d&#249;ng lu&#244;n alias &#273;&#243; &#273;&#432;&#7907;c, kh&#244;ng c&#7847;n g&#245; IP d&#224;i. V&#237; d&#7909;: <code>scp file.txt myserver:/home/ubuntu/</code></p></blockquote><div><hr></div><h2>Download - Remote to Local</h2><pre><code><code># Download 1 file v&#7873; th&#432; m&#7909;c hi&#7879;n t&#7841;i
scp user@192.168.1.10:/home/user/file.txt .

# Download v&#7873; path c&#7909; th&#7875;
scp user@192.168.1.10:/home/user/file.txt ~/Downloads/file.txt

# Download c&#7843; folder
scp -r user@192.168.1.10:/home/user/myproject ./local-copy
</code></code></pre><p>C&#225;i hay &#7903; &#273;&#226;y l&#224; ch&#7881; c&#7847;n &#273;&#7893;i v&#7883; tr&#237; <code>source</code> v&#224; <code>destination</code> so v&#7899;i l&#250;c upload. Kh&#244;ng c&#243; l&#7879;nh ri&#234;ng cho &#8220;download&#8221; - logic ho&#224;n to&#224;n &#273;&#7889;i x&#7913;ng.</p><div><hr></div><h2>Remote to Remote</h2><pre><code><code># Copy th&#7859;ng t&#7915; server A sang server B (kh&#244;ng qua local)
scp user1@server1:/path/file.txt user2@server2:/path/</code></code></pre><p>C&#225;i n&#224;y &#237;t ng&#432;&#7901;i bi&#7871;t. Thay v&#236; download v&#7873; local r&#7891;i upload l&#234;n, b&#7841;n c&#243; th&#7875; copy th&#7859;ng gi&#7919;a 2 server. H&#7919;u &#237;ch khi file l&#7899;n v&#224; b&#259;ng th&#244;ng local b&#7883; h&#7841;n ch&#7871;.</p><blockquote><p><strong>C&#7843;nh b&#225;o:</strong> T&#237;nh n&#259;ng n&#224;y ho&#7841;t &#273;&#7897;ng b&#7857;ng c&#225;ch m&#225;y local m&#7903; 2 k&#7871;t n&#7889;i SSH song song. M&#7897;t s&#7889; c&#7845;u h&#236;nh server strict c&#243; th&#7875; block ho&#7863;c kh&#244;ng ho&#7841;t &#273;&#7897;ng nh&#432; k&#7923; v&#7885;ng. N&#7871;u g&#7863;p v&#7845;n &#273;&#7873;, d&#249;ng <code>rsync</code> ho&#7863;c SSH v&#224;o server A r&#7891;i <code>scp</code> t&#7915; &#273;&#243; s&#7869; ch&#7855;c ch&#7855;n h&#417;n.</p></blockquote><div><hr></div><h2>C&#225;c options hay d&#249;ng</h2><ul><li><p><code>-i key.pem</code> - Ch&#7881; &#273;&#7883;nh SSH private key</p></li><li><p><code>-P 2222</code> - SSH port kh&#225;c (ch&#250; &#253; -P vi&#7871;t hoa, kh&#225;c v&#7899;i ssh -p th&#432;&#7901;ng)</p></li><li><p><code>-r</code> - Recursive, copy c&#7843; folder</p></li><li><p><code>-p</code> - Gi&#7919; nguy&#234;n permission v&#224; timestamps</p></li><li><p><code>-C</code> - Compress data khi transfer, h&#7919;u &#237;ch v&#7899;i file text l&#7899;n</p></li><li><p><code>-v</code> - Verbose, b&#7853;t khi debug l&#7895;i k&#7871;t n&#7889;i</p></li><li><p><code>-q</code> - Quiet, t&#7855;t progress bar, d&#249;ng trong script</p></li><li><p><code>-l 1000</code> - Gi&#7899;i h&#7841;n bandwidth (Kbit/s), d&#249;ng khi kh&#244;ng mu&#7889;n chi&#7871;m h&#7871;t &#273;&#432;&#7901;ng truy&#7873;n</p></li></ul><div><hr></div><h2>Khi n&#224;o th&#236; d&#249;ng rsync thay v&#236; scp?</h2><p><code>scp</code> t&#7889;t cho vi&#7879;c copy &#273;&#417;n gi&#7843;n. Nh&#432;ng n&#7871;u b&#7841;n &#273;ang:</p><ul><li><p>Sync folder l&#7899;n v&#224; mu&#7889;n <strong>ch&#7881; transfer ph&#7847;n thay &#273;&#7893;i</strong> (kh&#244;ng copy l&#7841;i to&#224;n b&#7897;)</p></li><li><p>C&#7847;n <strong>resume</strong> khi k&#7871;t n&#7889;i b&#7883; &#273;&#7913;t gi&#7919;a ch&#7915;ng</p></li><li><p>Deploy code th&#432;&#7901;ng xuy&#234;n l&#234;n server</p></li></ul><p>...th&#236; <code>rsync</code> s&#7869; ph&#249; h&#7907;p h&#417;n. T&#244;i s&#7869; vi&#7871;t v&#7873; rsync trong b&#224;i sau.</p><div><hr></div><h2>M&#7897;t v&#224;i l&#7895;i th&#432;&#7901;ng g&#7863;p</h2><p><strong>&#8220;Permission denied&#8221;</strong> - Th&#432;&#7901;ng do SSH key sai ho&#7863;c user kh&#244;ng c&#243; quy&#7873;n ghi v&#224;o th&#432; m&#7909;c &#273;&#237;ch. Ki&#7875;m tra l&#7841;i <code>-i</code> key v&#224; quy&#7873;n c&#7911;a folder destination.</p><p><strong>&#8220;No such file or directory&#8221;</strong> - Path tr&#234;n remote c&#7847;n t&#7891;n t&#7841;i tr&#432;&#7899;c. <code>scp</code> kh&#244;ng t&#7921; t&#7841;o folder nh&#432; <code>rsync &#8212;-mkpath</code>. SSH v&#224;o server t&#7841;o folder tr&#432;&#7899;c r&#7891;i m&#7899;i copy.</p><p><strong>Port kh&#244;ng ph&#7843;i 22</strong> - Nh&#7899; d&#249;ng <code>-P</code> vi&#7871;t hoa (kh&#225;c v&#7899;i <code>ssh -p</code> th&#432;&#7901;ng). &#272;&#226;y l&#224; c&#225;i t&#244;i v&#7851;n hay g&#245; sai.</p><div><hr></div><p>B&#224;i ti&#7871;p theo t&#244;i s&#7869; vi&#7871;t v&#7873; <code>rsync</code> - m&#7841;nh h&#417;n <code>scp</code> trong h&#7847;u h&#7871;t use case th&#7921;c t&#7871;, v&#224; m&#7897;t s&#7889; pattern t&#244;i hay d&#249;ng khi deploy. N&#7871;u c&#243; c&#226;u h&#7887;i g&#236; v&#7873; b&#224;i n&#224;y, comment b&#234;n d&#432;&#7899;i nh&#233;.</p>]]></content:encoded></item><item><title><![CDATA[IoC, DI và DIP trong lập trình backend]]></title><description><![CDATA[T&#243;m t&#7855;t m&#7897;t v&#224;i n&#7897;i dung xoay quanh IoC, DI v&#224; DIP trong l&#7853;p tr&#236;nh backend, gi&#250;p b&#7841;n hi&#7875;u h&#417;n v&#7873; nh&#7919;ng thu&#7853;t ng&#7919; quan tr&#7885;ng]]></description><link>https://www.fromtiny.com/p/giai-thich-kho-hieu-ve-ioc-di-va</link><guid isPermaLink="false">https://www.fromtiny.com/p/giai-thich-kho-hieu-ve-ioc-di-va</guid><dc:creator><![CDATA[Kiet Duong Hung]]></dc:creator><pubDate>Thu, 25 Dec 2025 08:50:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7Kzk!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33089124-6e8e-4b9b-a10c-8ba06f962f5d_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>1. Inversion of Control - S&#7921; tr&#7915;u t&#432;&#7907;ng ho&#225; lu&#7891;ng &#273;i&#7873;u khi&#7875;n</h3><p>V&#7873; m&#7863;c l&#253; thuy&#7871;t, IoC l&#224; m&#7897;t nguy&#234;n l&#253; thi&#7871;t k&#7871; m&#224; trong &#273;&#243; lu&#7891;ng &#273;i&#7873;u khi&#7875;n (flow of control) c&#7911;a m&#7897;t ch&#432;&#417;ng tr&#236;nh b&#7883; &#273;&#7843;o ng&#432;&#7907;c so v&#7899;i l&#7853;p tr&#236;nh c&#7845;u tr&#250;c truy&#7873;n th&#7889;ng.</p><ul><li><p><strong>Trong l&#7853;p tr&#236;nh truy&#7873;n th&#7889;ng</strong>: M&#227; ngu&#7891;n c&#7911;a nh&#224; ph&#225;t tri&#7875;n (high-level code) tr&#7921;c ti&#7871;p g&#7885;i c&#225;c th&#432; vi&#7879;n ho&#7863;c c&#225;c h&#224;m &#273;&#7875; th&#7921;c th&#7883; logic. Nh&#224; ph&#225;t tri&#7875;n n&#7855;m quy&#7873;n ki&#7875;m so&#225;t to&#224;n b&#7897; v&#242;ng &#273;&#7901;i c&#7911;a th&#7921;c th&#7875;.</p></li><li><p><strong>Trong IoC</strong>: M&#7897;t framework ho&#7863;c m&#7897;t th&#224;nh ph&#7847;n h&#7841; t&#7847;ng &#273;&#243;ng vai tr&#242; l&#224; <strong>chu&#417;ng tr&#236;nh ch&#237;nh</strong>. N&#243; s&#7869; tri&#7879;u h&#7891;i (call back) m&#227; ngu&#7891;n c&#7911;a nh&#224; ph&#225;t tri&#7875;n t&#7841;i c&#225;c th&#7901;i &#273;i&#7875;m m&#7903; r&#7897;ng (extension points) &#273;&#227; &#273;&#7883;nh ngh&#297;a tr&#432;&#7899;c.</p></li></ul><p><strong>&#272;&#7883;nh ngh&#297;a h&#224;n l&#226;m:</strong> IoC l&#224; s&#7921; d&#7883;ch chuy&#7875;n tr&#225;ch nhi&#7879;m qu&#7843;n l&#253; lu&#7891;ng th&#7921;c thi v&#224; v&#242;ng &#273;&#7901;i &#273;&#7889;i t&#432;&#7907;ng t&#7915; m&#227; ngu&#7891;n &#7913;ng d&#7909;ng sang m&#7897;t container ho&#7863;c framework.</p><h3>2. Dependency Injection (DI) - Hi&#7879;n th&#7921;c ho&#225; s&#7921; l&#7887;ng l&#7867;o (Loose Coupling)</h3><p><strong>DI</strong> &#273;&#432;&#7907;c coi l&#224; m&#7897;t m&#7851;u h&#236;nh &#273;&#7863;c bi&#7879;t c&#7911;a IoC, t&#7853;p trung v&#224;o vi&#7879;c qu&#7843;n l&#253; c&#225;c m&#7889;i quan h&#7879; (dependencies) gi&#7919;a c&#225;c th&#224;nh ph&#7847;n.</p><p>Theo quan &#273;i&#7875;m h&#7879; th&#7889;ng, m&#7897;t &#273;&#7889;i t&#432;&#7907;ng kh&#244;ng n&#234;n c&#243; tri th&#7913;c v&#7873; c&#225;ch c&#7845;u h&#236;nh ho&#7863;c kh&#7903;i t&#7841;o s&#7921; ph&#7909; thu&#7897;c c&#7911;a n&#243;. Thay v&#224;o &#273;&#243;, tr&#225;ch nhi&#7879;m n&#224;y &#273;&#432;&#7907;c t&#225;ch r&#7901;i (decoupled) v&#224; chuy&#7875;n giao cho m&#7897;t th&#7921;c th&#7875; b&#234;n ngo&#224;i (injector).</p><p><strong>C&#243; 3 th&#224;nh ph&#7847;n trong m&#244; h&#236;nh DI:</strong></p><ol><li><p><strong>Client</strong>: &#272;&#7889;i t&#432;&#7907;ng c&#7847;n s&#7917; d&#7909;ng d&#7883;ch v&#7909;</p></li><li><p><strong>Service (Dependency)</strong>: &#272;&#7889;i t&#432;&#7907;ng cung c&#7845;p d&#7883;ch v&#7909;</p></li><li><p><strong>Injector</strong>: Th&#224;nh ph&#7847;n th&#7921;c hi&#7879;n vi&#7879;c c&#224;i &#273;&#7863;t (inject) Service v&#224;o Client</p></li></ol><h3>3. M&#7889;i quan h&#7879; v&#7899;i Nguy&#234;n l&#253; Ngh&#7883;ch &#273;&#7843;o Ph&#7909; thu&#7897;c (Dependency Inversion Principle - DIP)</h3><p>&#272;&#7875; hi&#7875;u s&#226;u v&#7873; IoC/DI &#7903; m&#7913;c h&#224;n l&#226;m, ta ph&#7843;i nh&#7855;c &#273;&#7871;n <strong>DIP</strong> (D trong nguy&#234;n l&#253; SOLID). DIP &#273;&#432;a ra hai quy t&#7855;c c&#7889;t l&#245;i:</p><ol><li><p>C&#225;c module c&#7845;p cao kh&#244;ng n&#234;n ph&#7909; thu&#7897;c v&#224;o c&#225;c module c&#7845;p th&#7845;p. C&#7843; hau &#273;&#7873; ph&#7843;i ph&#7909; thu&#7897;c v&#224; s&#7921; <strong>tr&#7915;u t&#432;&#7907;ng (Abstractions)</strong></p></li><li><p>S&#7921; tr&#7915;u t&#432;&#7907;ng kh&#244;ng n&#234;n ph&#7909; thu&#7897;c v&#224;o chi ti&#7871;t. <strong>Chi ti&#7871;t ph&#7843;i ph&#7909; thu&#7897;c v&#224; s&#7921; tr&#7915;u t&#432;&#7907;ng</strong></p></li></ol><p><strong>L&#7853;p lu&#7853;n</strong>: DI ch&#237;nh l&#224; k&#7929; thu&#7853;t &#273;&#7875; th&#7921;c hi&#7879;n DIP. B&#7857;ng c&#225;ch &#8220;ti&#234;m&#8220; m&#7897;t interface v&#224;o constructor, ta &#273;&#7843;m b&#7843;o module c&#7845;p cao ch&#7881; giao ti&#7871;p v&#7899;i s&#7921; tr&#7915;u t&#432;&#7907;ng, t&#7915; &#273;&#243; tri&#7879;t ti&#234;u s&#7921; ph&#7909; thu&#7897;c v&#224; c&#224;i &#273;&#7863;t c&#7909; th&#7875; (Concrete Implementation).</p><p><em>HighLevelModule</em> &#8594; <em>Interface</em> &#8592; <em>LowLevelModule</em></p><h3>4. T&#7893;ng k&#7871;t</h3><ul><li><p><strong>IoC</strong> l&#224; m&#7897;t <strong>Meta-pattern</strong> (m&#7851;u h&#236;nh cao c&#7845;p) &#273;&#7883;nh ngh&#297;a l&#7841;i quy&#7873;n h&#7841;n c&#7911;a c&#225;c th&#224;nh ph&#7847;n trong h&#7879; th&#7889;ng.</p></li><li><p><strong>DI</strong> l&#224; m&#7897;t design pattern c&#7909; th&#7875; ho&#225; vi&#7879;c chuy&#7875;n giao tr&#225;ch nhi&#7879;m kh&#7903;i t&#7841;o &#273;&#7889;i t&#432;&#7907;ng</p></li><li><p><strong>IoC Container</strong> l&#224; m&#7897;t <strong>Management Layer</strong> (l&#7899;p qu&#7843;n l&#253;) ch&#7883;u tr&#225;ch nhi&#7879;m th&#7921;c thi c&#225;c quy t&#7855;c v&#7873; ph&#7841;m vi (Scope - Singleton, Transient, Scoped) v&#224; v&#242;ng &#273;&#7901;i (Lifecycle) c&#7911;a c&#225;c th&#224;nh ph&#7847;n trong h&#7879; th&#7889;ng.</p></li></ul><h3>5. Minh ho&#7841;</h3><pre><code><code>interface MessageService {
    send(message: string): string;
}

class SmsService implements MessageService {
    send(message: string) {
        return 'Sms Sent:' + message;
    }
}

class EmailService implements MessageService {
    send(message: string) {
        return 'Email Sent: ' + message;
    }
}

class NotificationService {
    private messageService: MessageService;

    constructor(messageService: MessageService) {
        this.messageService = messageService;
    }

    sendAuth(message: string) {
        console.log('Sending...');
        const result = this.messageService.send(message);
        console.log(result);
    }
}

const emailService = new EmailService();
const authService = new NotificationService(emailService);
authService.sendAuth('Hello, you got fired');</code></code></pre><p>Nh&#236;n v&#224;o &#273;o&#7841;n code m&#7851;u n&#224;y, ch&#250;ng ta s&#7869; th&#7845;y n&#243; c&#243; gi&#225; tr&#7883; khi ch&#250;ng ta c&#7847;n b&#7893; sung ho&#7863;c thay &#273;&#7893;i nh&#7919;ng h&#236;nh th&#7913;c g&#7917;i th&#244;ng b&#225;o. V&#237; d&#7909; ch&#250;ng ta c&#7847;n th&#234;m h&#236;nh th&#7913;c g&#7917;i qua Telegram, ch&#7881; c&#7847;n th&#234;m class TelegramService, sau &#273;&#243; s&#7917; d&#7909;ng m&#7897;t c&#225;ch &#273;i&#7879;u ngh&#7879; ph&#432;&#417;ng th&#7913;c m&#7899;i m&#224; kh&#244;ng c&#7847;n ph&#7843;i s&#7917;a b&#7845;t k&#7923; d&#242;ng code n&#224;o c&#7911;a NotificationService :)</p>]]></content:encoded></item></channel></rss>