Setup tmux cho freelancer làm 3 dự án song song trên 1 VPS

Chia sẻ bài viết

Mục lục
TL;DR
  • 1 VPS Cloud + tmux = chạy 3 dự án freelance song song, không tốn 3 con VPS riêng.
  • Mỗi khách hàng = 1 tmux session độc lập, dotfiles + alias + venv riêng, không lẫn lộn ENV.
  • Detach session khi mất mạng, attach lại vẫn nguyên context: dev server đang chạy, log đang scroll, REPL đang sống.
  • Layout pane chuẩn: editor lớn, terminal nhỏ, logs tailing. Một cú Ctrl-b z là full-screen pane.
  • Bonus: tmux + mosh = chốt deal cafe wifi rớt, ssh không drop, freelancer ngủ ngon.

Bạn là freelancer dev. Tháng này có 3 hợp đồng song song: 1 app Next.js cho khách Singapore, 1 backend FastAPI cho startup HCM, 1 site WordPress cho công ty xây dựng Hà Nội. Nếu mở 3 cửa sổ VS Code trên Macbook + 3 ngrok tunnel + 3 dev server, máy nóng như bàn ủi, pin tụt thấy rõ. Hơn nữa khách yêu cầu deploy demo URL chứ không phải localhost. Đáp án quen thuộc: thuê 3 VPS, mỗi con 1 dự án. Nhưng 3 VPS = 3 lần tiền, 3 lần backup, 3 lần monitor, 3 lần update OS. Quá tốn cho cá nhân.

Cách rẻ và sạch hơn: 1 con Cloud VPS tầm trung, cài tmux, mỗi khách hàng nhận 1 tmux session. Bạn ssh từ Macbook hoặc iPad vào, attach session, làm việc, detach. Tài nguyên dùng chung, ENV và port tách biệt. Bài này hướng dẫn setup tmux theo workflow freelancer thực tế, không phải hướng dẫn copy-paste vanilla từ Wikipedia. Sau khi đọc xong, bạn có config sẵn dùng, layout pane chuẩn, dotfiles versioning, và biết cách tránh các bẫy port-conflict thường gặp khi chạy nhiều dự án Node/Python cùng máy.

Bài viết tham khảo workflow của các solo dev đang xài Cloud VPS TND làm máy dev chính. Cấu hình thử nghiệm: VPS 4 vCPU / 8GB RAM / 80GB SSD CEPH, AlmaLinux 9, đủ thoải mái chạy 3 stack song song mà CPU vẫn dưới 40 phần trăm.

Vì sao tmux thay được 3 con VPS?

tmux là terminal multiplexer, nghĩa là một process chạy nền trên server, bên trong nó tạo ra nhiều session ảo. Mỗi session có thể có nhiều window (giống tab), mỗi window có thể chia thành nhiều pane (giống split view). Khi bạn ssh vào VPS rồi gõ tmux a -t client-a, terminal của bạn được "gắn" vào session đó. Tắt terminal, session vẫn chạy. Mở terminal khác từ iPad, attach lại, mọi thứ còn nguyên.

Với freelancer chạy 3 dự án, lợi ích cụ thể: dev server next dev của khách A vẫn chạy port 3001, FastAPI của khách B chạy port 8002, wp-cli của khách C chạy trong pane riêng, không cái nào ảnh hưởng cái nào. Mất wifi ở quán cafe, ssh drop, không sao - session tmux không chết theo. Quay về nhà, ssh lại, tmux a, tiếp tục đúng dòng code đang viết.

Chọn cấu hình VPS phù hợp cho freelancer 3 dự án

Trước khi cài tmux, chọn đúng cấu hình. Sai cấu hình thì 1 dự án Next.js build cũng đủ làm chậm 2 dự án còn lại. Bảng dưới là gợi ý theo loại stack:

Loại stack mỗi dự ánRAM tối thiểuvCPUSSDGhi chú
3 site WordPress nhẹ4 GB2 vCPU40 GBOK với caching tốt
3 app Next.js / Vue dev mode8 GB4 vCPU60 GBBuild Next ăn RAM khủng
3 backend FastAPI + Postgres mini8 GB4 vCPU80 GBPostgres mỗi dự án 1 instance
Hỗn hợp 3 stack khác nhau8-16 GB4-6 vCPU80-120 GBCấu hình thực tế phổ biến
Có thêm AI inference local16-32 GB6-8 vCPU160 GB+Cân nhắc VPS GPU riêng

Khoảng giá Cloud VPS TND nằm trong range 199k đến 3190k mỗi tháng tùy cấu hình, freelancer chọn gói tầm trung 8GB RAM là vừa đẹp cho workflow 3 dự án song song. Băng thông trong nước 200Mbps đủ pull repo lớn nhanh, push image Docker không sợ nghẽn.

Cài tmux và những plugin "must have"

tmux có sẵn trong repo của AlmaLinux, Ubuntu, Debian. Phiên bản 3.3 trở lên là đủ dùng. Cài như sau:

# AlmaLinux 9
sudo dnf install -y tmux git

# Ubuntu 22/24, Debian 12/13
sudo apt update && sudo apt install -y tmux git

# Kiểm tra version
tmux -V

Tiếp theo cài TPM (Tmux Plugin Manager). TPM giúp quản lý plugin tmux theo kiểu giống vim-plug:

git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

Config tmux thực chiến cho freelancer

Tạo file ~/.tmux.conf với nội dung sau. Đây là config đã chắt lọc từ workflow của nhiều freelancer dev, không lòe loẹt, đủ tăng tốc đáng kể:

# Đổi prefix từ Ctrl-b sang Ctrl-a (dễ bấm hơn, không đụng vim)
unbind C-b
set -g prefix C-a
bind C-a send-prefix

# Bật mouse mode cho ai lười nhớ phím
set -g mouse on

# Index window và pane bắt đầu từ 1 (số 0 nằm xa tay phải)
set -g base-index 1
setw -g pane-base-index 1

# Renumber window khi đóng bớt cho liên tục
set -g renumber-windows on

# Tăng history scroll lên 50k dòng
set -g history-limit 50000

# Split pane theo phím trực quan
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %

# Reload config nhanh bằng prefix r
bind r source-file ~/.tmux.conf ; display "Reloaded ~/.tmux.conf"

# Switch pane bằng Alt + mũi tên (không cần prefix)
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D

# Status bar màu navy nhẹ nhàng
set -g status-bg "#0B1230"
set -g status-fg "#a4b1d6"
set -g status-left-length 40
set -g status-left "#[fg=#7A5BFF,bold] #S #[default]| "
set -g status-right "#[fg=#a4b1d6] %H:%M  %d-%m "

# Plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'

# Tự save session mỗi 15 phút và restore khi tmux start lại
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15'

run '~/.tmux/plugins/tpm/tpm'

Sau khi save file, mở tmux lên rồi bấm prefix + I (in hoa) để TPM cài plugin. Lần đầu chậm khoảng 30 giây, sau đó các plugin cập nhật rất nhanh.

Tổ chức session: mỗi khách hàng 1 session

Đây là phần ai cũng làm sai lúc đầu: dồn 3 dự án vào 1 session, đặt tên window kiểu work1/work2/work3. Đến tuần thứ 2 bạn không nhớ work2 là khách nào. Quy ước nên theo:

  • 1 khách hàng = 1 session, đặt tên theo code khách: client-acme, client-zen, client-bds.
  • Trong mỗi session, 3-4 window theo concern: 1:editor, 2:server, 3:db, 4:misc.
  • Pane chia bên trong window editor: pane lớn cho nvim/code-server, pane nhỏ cho terminal phụ.

Tạo session theo template bằng script bash đặt ở ~/bin/dev-session.sh:

#!/usr/bin/env bash
# Usage: dev-session.sh client-acme /home/me/projects/acme

CLIENT="$1"
PROJECT_DIR="$2"

if [ -z "$CLIENT" ] || [ -z "$PROJECT_DIR" ]; then
  echo "Usage: dev-session.sh client-name project-dir"
  exit 1
fi

# Nếu session đã tồn tại thì attach
tmux has-session -t "$CLIENT" 2>/dev/null
if [ $? -eq 0 ]; then
  tmux attach -t "$CLIENT"
  exit 0
fi

# Tạo session mới với 4 window
tmux new-session -d -s "$CLIENT" -c "$PROJECT_DIR" -n "editor"
tmux send-keys -t "$CLIENT:editor" "nvim ." C-m

tmux new-window -t "$CLIENT" -n "server" -c "$PROJECT_DIR"
tmux split-window -t "$CLIENT:server" -h -c "$PROJECT_DIR"
tmux send-keys -t "$CLIENT:server.1" "echo 'dev server slot'" C-m
tmux send-keys -t "$CLIENT:server.2" "tail -f logs/dev.log 2>/dev/null || echo 'logs slot'" C-m

tmux new-window -t "$CLIENT" -n "db" -c "$PROJECT_DIR"
tmux send-keys -t "$CLIENT:db" "echo 'psql or mysql slot'" C-m

tmux new-window -t "$CLIENT" -n "misc" -c "$PROJECT_DIR"

tmux select-window -t "$CLIENT:editor"
tmux attach -t "$CLIENT"

Cấp quyền thực thi rồi gọi: chmod +x ~/bin/dev-session.sh && dev-session.sh client-acme ~/projects/acme. Lần sau gõ lại cùng lệnh, script tự attach vào session sẵn có. Không cần nhớ cú pháp tmux dài dòng nữa.

Tránh xung đột port giữa 3 dự án

Đây là cái bẫy lớn nhất khi chạy nhiều stack chung 1 VPS. Mặc định Next.js xài 3000, Vite xài 5173, FastAPI xài 8000. Bật 2 dự án giống nhau là một cái không start được. Quy ước nội bộ:

Loại serviceKhách AKhách BKhách C
Frontend dev server300130023003
Backend API800180028003
Postgres / MySQL543215432254323
Redis637916379263793
Ngrok / Cloudflare Tunnela.your-domain.comb.your-domain.comc.your-domain.com

Trong file .env của mỗi dự án, set cứng port theo bảng. Khi bật pane "server", chỉ cần npm run dev hoặc uvicorn main:app --port 8001 là chạy đúng slot, không sợ va chạm. Để tránh quên, viết alias trong ~/.bashrc hoặc ~/.zshrc:

alias dev-acme="cd ~/projects/acme && npm run dev"
alias api-acme="cd ~/projects/acme-api && uvicorn main:app --reload --port 8001"
alias dev-zen="cd ~/projects/zen && npm run dev"
alias api-zen="cd ~/projects/zen-api && uvicorn main:app --reload --port 8002"

Dotfiles versioning: đừng để config thất lạc

Sau vài tháng dùng, ~/.tmux.conf, ~/.bashrc, ~/.config/nvim/init.lua phình ra. Khi đổi VPS hoặc setup máy phụ, bạn lại phải nhớ cài lại từng cái. Giải pháp: dotfiles repo trên GitHub. Tạo repo private tên dotfiles, push các file config lên, ở VPS chỉ cần:

cd ~
git clone [email protected]:your-username/dotfiles.git .dotfiles
cd .dotfiles
./install.sh   # script symlink mỗi file vào $HOME

File install.sh đơn giản:

#!/usr/bin/env bash
DOTFILES="$HOME/.dotfiles"
ln -sf "$DOTFILES/tmux.conf" "$HOME/.tmux.conf"
ln -sf "$DOTFILES/bashrc" "$HOME/.bashrc"
ln -sf "$DOTFILES/zshrc" "$HOME/.zshrc"
mkdir -p "$HOME/.config/nvim"
ln -sf "$DOTFILES/nvim/init.lua" "$HOME/.config/nvim/init.lua"
echo "Dotfiles linked. Reload shell to apply."

Lần sau VPS chết hoặc bạn mua VPS thứ 2, chỉ cần clone repo, chạy install.sh là môi trường y hệt máy cũ trong 30 giây.

Persistent session bằng tmux-resurrect + continuum

Plugin tmux-resurrect lưu state các session, window, pane (kể cả working directory). tmux-continuum tự gọi resurrect mỗi 15 phút. Nếu VPS reboot vì update kernel, sau khi tmux start lại bạn vẫn thấy 3 session client-acme, client-zen, client-bds nằm sẵn, pane phân bổ đúng layout cũ. Tiết kiệm 5-10 phút setup lại mỗi sáng.

Có một số state không thể restore được, ví dụ process npm dev đang chạy. Để cứu phần này, bạn có thể bật option @resurrect-processes:

set -g @resurrect-processes 'npm pnpm yarn uvicorn python ssh "~rails server" "~bundle exec"'

Sau reboot, resurrect tự gọi lại đúng lệnh ở pane tương ứng. Cẩn thận với process có biến môi trường nhạy cảm: nên dùng systemd hoặc pm2 cho production thay vì dựa hết vào resurrect.

Kết hợp mosh để chống rớt mạng

ssh có nhược điểm: mạng yếu thì lag, mất mạng vài giây thì drop kết nối, gõ lệnh dài thấy ký tự xuất hiện trễ. Mosh (mobile shell) giải quyết: kết nối UDP, dự đoán hiển thị ký tự ngay, roaming IP khi đổi wifi. Cài 2 đầu:

# Trên VPS
sudo dnf install -y mosh           # AlmaLinux
# hoặc
sudo apt install -y mosh           # Ubuntu / Debian

# Mở range UDP 60000-61000 cho mosh
sudo firewall-cmd --add-port=60000-61000/udp --permanent
sudo firewall-cmd --reload

# Trên Mac
brew install mosh

# Kết nối: mosh tự gọi ssh để bắt tay rồi switch UDP
mosh [email protected] -- tmux a -t client-acme

Bộ đôi mosh + tmux là kinh điển cho freelancer dev di chuyển nhiều: code ở quán cafe, lên taxi đi gặp khách, mở laptop ra vẫn tiếp tục pane đang dở. Không có lý do gì để không xài.

Layout pane chuẩn cho từng kiểu task

tmux có 5 layout có sẵn: even-horizontal, even-vertical, main-horizontal, main-vertical, tiled. Mỗi loại task hợp 1 layout:

TaskLayoutPhân bổ pane
Coding chínhmain-verticalEditor chiếm 70% trái, 2 terminal phụ chồng dọc bên phải
Debug nhiều logtiled4 pane đều nhau, mỗi pane tail 1 service
Pair work qua wormholemain-horizontalEditor trên, terminal dưới chia 50:50
Quan sát monitoringeven-horizontalhtop, iotop, log nginx, log php-fpm

Chuyển layout chỉ cần prefix + space, tmux xoay tròn qua các layout. Khi đã ưng, prefix + z để zoom vào pane đang focus (full màn hình), bấm lần nữa thoát zoom. Đây là phím tắt cứu cánh khi cần focus đọc code dài mà không muốn detach pane khác.

Cô lập môi trường Python / Node giữa các dự án

tmux chỉ chia màn hình, không chia môi trường. Dự án A xài Node 18, dự án B xài Node 22, dự án C xài Python 3.11 + Postgres 16. Bạn cần thêm version manager. Khuyến nghị:

  • Node: dùng fnm hoặc volta. Mỗi project có file .nvmrc hoặc package.json với field engines.
  • Python: dùng uv hoặc pyenv + venv. Mỗi project venv riêng trong .venv/ rồi gọi source .venv/bin/activate.
  • PHP / WordPress: dùng Docker compose hoặc DDEV per project. Chỉ định version PHP trong .ddev/config.yaml.
  • Database: dùng Docker container riêng, mapping port khác nhau, không cài MySQL/Postgres native vì khó nâng cấp parallel.

Khi cd vào folder dự án, fnm/pyenv tự switch version. Pane tmux của khách A tự dùng Node 18, pane tmux của khách B tự dùng Node 22, không cần nhớ lệnh switch thủ công.

Bảo mật: SSH key, fail2ban, không root

Chạy 3 dự án khách trên 1 VPS nghĩa là rủi ro tập trung. Mất key SSH = mất luôn 3 dự án. Checklist tối thiểu:

  1. Disable password login, chỉ cho phép SSH key. Sửa /etc/ssh/sshd_config: PasswordAuthentication no.
  2. Tạo user thường thay vì login root. Dùng sudo cho lệnh đặc quyền.
  3. Cài fail2ban, bật jail sshd. Mỗi IP sai 3 lần auto ban 1 tiếng.
  4. Mở firewall chỉ port 22 (SSH) + 80/443 (web) + 60000-61000/udp (mosh) + các port custom của bạn.
  5. Backup ~/.ssh/~/.dotfiles/ hằng tuần lên cloud storage riêng.
  6. Nếu khách hàng có data nhạy cảm: tạo system user riêng, đặt project dưới /srv/clients/acme/ với permission 700.

Khi nào nên tách VPS riêng cho 1 khách?

tmux + 1 VPS là chiến lược tối ưu giai đoạn dev. Nhưng có những lúc bạn nên tách:

  • Dự án đã production, có khách thật, traffic ổn định: tách VPS production riêng, VPS dev vẫn dùng chung.
  • Khách hàng yêu cầu compliance (PCI, ISO, HIPAA): họ thường cấm shared environment.
  • 1 dự án xài AI inference local nặng (Llama 70B, Stable Diffusion XL): tách VPS GPU riêng.
  • Bạn nhận thêm khách thứ 4-5, VPS hiện tại không đủ RAM, không muốn upgrade plan chung.

Một workflow phổ biến: 1 VPS dev tổng + N VPS production nhỏ cho mỗi khách. VPS dev là sandbox bạn quẩy thoải mái, VPS production chỉ chạy code đã review, deploy qua Git hook hoặc CI.

Cloud VPS cho vibe coder

Một VPS đủ chỗ cho 3 khách hàng và 1 tmux sạch sẽ

Cloud VPS TND sẵn AlmaLinux 9, Ubuntu 22/24, Debian 12/13. SSD CEPH, snapshot 1-click, backup hằng ngày, network 200Mbps trong nước. Gói 8GB RAM / 4 vCPU thoải mái chạy 3 stack dev song song, không lo nghẽn build Next.js.

Xem 8 cấu hình Cloud VPS →

FAQ

tmux khác screen như thế nào? Có cần chuyển không?

screen là multiplexer cổ điển, ra đời 1987, vẫn còn được duy trì. tmux ra đời 2007, code clean hơn, config dễ hơn, hỗ trợ pane split tốt hơn screen. Nếu bạn đã quen screen và chỉ cần detach/attach đơn giản thì không bắt buộc đổi. Nhưng nếu muốn layout pane phức tạp, mouse mode, plugin manager, plugin resurrect, thì tmux thắng tuyệt đối.

Tôi xài VS Code Remote SSH rồi, còn cần tmux không?

VS Code Remote chạy server riêng trên VPS, không phụ thuộc tmux để giữ session. Tuy nhiên các terminal trong VS Code chạy trực tiếp trong shell, nếu bạn close VS Code thì process npm dev cũng chết theo. Workaround: chạy npm dev trong tmux session ngoài (qua ssh thường), VS Code chỉ dùng để edit code. Bạn có cả 2 thế giới: edit GUI và process bền bỉ.

Có thể chia sẻ tmux session cho khách hàng xem cùng không?

Có. Tạo user chung, cho khách ssh vào, cả hai cùng tmux attach -t demo là thấy chung 1 màn hình, gõ chung pane. Phù hợp pair programming hoặc demo live. Cẩn thận quyền: dùng user riêng cho khách, chmod 750 thư mục project, không cho khách sudo. Khi xong demo, nhớ passwd -l khóa user lại.

RAM của VPS 8GB chạy 3 Next.js cùng lúc có đủ không?

Đủ nếu chỉ dev mode bình thường (1-1.5GB mỗi dự án). Lúc build production (next build) thì có thể ăn 3-4GB cho 1 dự án lớn. Mẹo: không build song song 3 dự án cùng lúc. Set thêm 4GB swap để có vùng đệm khi build. Nếu thường xuyên build nặng, nâng VPS lên 16GB là an toàn.

Khi VPS reboot, session tmux mất không?

tmux server chết khi reboot, session in-memory mất. Nhưng nếu bạn đã cài tmux-resurrect + continuum như config trên, state cuối cùng được lưu xuống disk mỗi 15 phút. Sau reboot, gõ tmux mới và bấm prefix + Ctrl-r, resurrect sẽ tái tạo session, window, pane và cwd. Process đang chạy thì không restore tự động trừ khi bạn whitelist trong @resurrect-processes.