operations/deploy-docs-site.md

Deploy Docs Site (PM2 + Nginx)

Hướng dẫn deploy documents.<domain> — static HTML được build từ docs/**/*.md qua scripts/build.mjs, chạy 24/7 bằng PM2, nginx làm reverse proxy + TLS.

Xem ../scripts/README.md cho chi tiết build pipeline.


Prerequisites trên VPS

# Node 20 LTS
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Yarn classic (project dùng Yarn 1)
sudo npm i -g yarn pm2

# Nginx + certbot (nếu chưa có)
sudo apt install -y nginx certbot python3-certbot-nginx

PM2 đã được dùng cho booking-api + booking-web ở dự án này, em không cần cài lại nếu VPS đang chạy 2 app đó.


Lần đầu: clone + build + start

# 1. Clone repo docs (repo riêng với booking-api/web)
cd /var/www
git clone git@github.com:novagoo/booking-docs.git
cd booking-docs

# 2. Cài deps + build ra dist/
yarn install --frozen-lockfile
yarn build

# 3. Khởi PM2
pm2 start ecosystem.config.cjs
pm2 save                       # persist process list qua reboot

# 4. Lần đầu dùng PM2 trên máy — sinh systemd unit để auto-start on boot
pm2 startup systemd
# Copy-paste dòng `sudo env PATH=... pm2 startup ...` PM2 in ra rồi chạy

# 5. Verify
pm2 status                     # thấy `booking-docs` online
curl -I http://127.0.0.1:4010/ # 200 OK

Nginx reverse proxy

Tạo /etc/nginx/sites-available/booking-docs:

server {
  listen 80;
  server_name documents.salon.no;

  # Certbot sẽ tự thêm block TLS bên dưới khi chạy lệnh dưới cùng
  location / {
    proxy_pass http://127.0.0.1:4010;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }

  # Gzip — các file HTML/CSS/JS static nén rất tốt
  gzip on;
  gzip_types text/plain text/css application/javascript application/json image/svg+xml;
  gzip_min_length 1024;
}
sudo ln -s /etc/nginx/sites-available/booking-docs /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

# TLS
sudo certbot --nginx -d documents.salon.no

Alternative: Nginx serve dist/ trực tiếp (không PM2)

Nếu VPS quá chật RAM (không muốn tốn thêm Node process), có thể bỏ PM2 hoàn toàn — nginx serve thẳng file dist/. Trade-off: mất khả năng pm2 logs booking-docs, mỗi lần deploy phải yarn build trên VPS (hoặc rsync dist/ từ local).

server {
  listen 80;
  server_name documents.salon.no;

  root /var/www/booking-docs/dist;
  index index.html;

  # Clean URLs: /flows/payment-flow → /flows/payment-flow.html
  location / {
    try_files $uri $uri/ $uri.html =404;
  }

  location ~* \.(css|js|woff2?|svg|png|jpg|ico)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
  }
}

Deploy update (sau khi docs có thay đổi)

ssh vps
cd /var/www/booking-docs
git pull
yarn install --frozen-lockfile     # skip nếu package.json không đổi
yarn build
pm2 restart booking-docs           # pick up new dist/ + restart Node

Hoặc script gọn 1 dòng trên local (không cần ssh thủ công):

ssh deploy@vps 'cd /var/www/booking-docs && git pull && yarn install --frozen-lockfile && yarn build && pm2 restart booking-docs'

Useful PM2 commands

pm2 status                        # danh sách process
pm2 logs booking-docs             # tail logs (Ctrl+C để thoát)
pm2 logs booking-docs --lines 200 # 200 dòng gần nhất
pm2 restart booking-docs          # restart
pm2 reload booking-docs           # zero-downtime reload (không cần thiết cho static)
pm2 stop booking-docs             # stop (giữ trong list)
pm2 delete booking-docs           # xóa khỏi list

pm2 monit                         # dashboard live CPU/memory
pm2 describe booking-docs         # config + log paths
pm2 flush booking-docs            # xóa log cũ

Log rotation

pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7

Tránh log file phình to khi chạy nhiều tháng.


Troubleshooting

Triệu chứng Nguyên nhân thường gặp Fix
pm2 statuserrored Port 4010 đang bị app khác dùng lsof -i :4010 → đổi DOCS_PORT trong ecosystem.config.cjs rồi pm2 restart
502 Bad Gateway từ nginx PM2 process chết / port mismatch pm2 logs booking-docs --lines 100 xem stacktrace
Đổi docs xong vẫn thấy bản cũ Browser cache (production bật max-age=86400 cho CSS/JS) Hard refresh (Cmd+Shift+R) hoặc bump query string trong template
Sidebar mất section mới thêm Build chưa chạy / dist/ chưa rsync yarn build lại rồi pm2 restart booking-docs
Page 404 khi click anchor .md Link chưa được rewrite (có thể do syntax edge case trong marked) Check regex trong rewriteMarkdownLinks của scripts/build.mjs
Node version quá cũ Builder dùng ES2022+ + replaceAll Yêu cầu Node ≥ 20 (xem package.json engines)