Bài 34 — Deploy Laravel với Nginx, worker và scheduler: Web trả 200 chưa có nghĩa ứng dụng đã vận hành đủ. TaskFlow còn cần xử lý queue, chạy lịch, giữ file riêng tư qua các release và nạp code mới vào process sống lâu. Bài này cung cấp cấu hình mẫu và tiêu chí nghiệm thu, không tuyên bố đã cài TaskFlow lên server production.
1. Xác định các tiến trình
| Thành phần | Vai trò | Kiểm tra cần có |
|---|---|---|
| Nginx + PHP-FPM | HTTP/TLS và chạy request Laravel | Login, policy, API, upload/download |
| Worker database queue | Maintenance, notification, broadcast | Đúng queue, job được xử lý, không tăng failed jobs |
| Scheduler timer | Gọi schedule:run mỗi phút | Service exit và tác vụ đúng giờ thực sự hoàn tất |
| Reverb tùy chọn | Giữ kết nối realtime | Private auth và event đến qua WSS |
Mẫu nằm trong taskflow/deploy, dành cho Linux có systemd, Nginx và PHP 8.4 CLI/FPM. Runtime CLI và FPM phải có extension phù hợp; worker timeout cần PCNTL trên nền tảng hỗ trợ. Windows local của khóa học không chứng minh cấu hình Linux đã chạy.
2. Tách code release và dữ liệu bền vững
Dùng /srv/taskflow/releases/{release-id} cho code, current trỏ release đang phục vụ và shared cho .env, storage cùng database SQLite nếu chủ động chọn SQLite. Với SQLite, DB_DATABASE dùng đường dẫn tuyệt đối ngoài release. MySQL/PostgreSQL cần connection và kiểm thử riêng trên engine đó. Không xóa database/file khi dọn release cũ.
Tạo user taskflow và quyền cho FPM/worker đọc cấu hình, ghi storage và bootstrap/cache. Nginx cần đọc public assets, không cần đọc .env. Không chmod 777 cả project. PDF của bài 28 nằm ngoài public, download qua controller có policy; không storage:link thư mục private. APP_KEY giữ ổn định, không key:generate lại mỗi lần deploy.
3. Nginx chỉ phục vụ public
Đoạn dưới nằm trong server HTTPS đã có server_name và certificate hợp lệ; file nginx.conf.example chứa khung đầy đủ cùng redirect HTTP và vhost Reverb tùy chọn. Thay hostname, socket FPM, đường dẫn chứng chỉ theo máy đích. Không dùng certificate placeholder như cấu hình có thể chạy ngay.
# Inside the HTTPS application server block, after provisioning TLS:
root /srv/taskflow/current/public;
index index.php;
client_max_body_size 3m;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /index.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root/index.php;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_hide_header X-Powered-By;
}
location ~ \.php$ { return 404; }
location ~ /\.(?!well-known).* { deny all; }Chỉ index.php được chuyển sang FPM; PHP khác bị từ chối. $realpath_root giúp resolve release symlink. Giới hạn request 3 MB chừa multipart overhead cho PDF tối đa 2 MB, nhưng còn phải đồng bộ upload_max_filesize/post_max_size của PHP. Chạy nginx -t trên máy đích trước reload và thử file thật; đọc cấu hình không thay cho kiểm chứng TLS/quyền filesystem.
4. Worker riêng cho từng queue
# /etc/systemd/system/taskflow-worker@.service
[Unit]
Description=TaskFlow queue worker (%i)
After=network.target
[Service]
Type=simple
User=taskflow
Group=taskflow
WorkingDirectory=/srv/taskflow/current
ExecStart=/usr/bin/php8.4 artisan queue:work database --queue=%i --sleep=3 --tries=3 --timeout=60 --max-time=3600
Restart=always
RestartSec=5
KillSignal=SIGTERM
TimeoutStopSec=90
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target%i là instance name: taskflow-worker@maintenance nghe maintenance, tương tự notifications, broadcasts và default nếu cần. Tách worker giúp một queue bận không chiếm toàn bộ lượt xử lý của queue khác; vẫn cần giám sát tài nguyên chung và điều chỉnh số process theo tải.
Worker timeout 60 giây nhỏ hơn retry_after 90 giây của database queue. Job-specific timeout 15/20 giây hiện còn thấp hơn. TimeoutStopSec 90 cho process thời gian dừng; job treo hoặc bị kill vẫn có thể retry, nên xử lý phải an toàn khi chạy lại. --max-time=3600 kết thúc worker định kỳ sau công việc phù hợp; Restart=always khởi động lại cả khi process thoát bình thường, nhưng systemd stop có chủ đích không bị biến thành vòng restart.
Cài unit sau review, chạy systemd-analyze verify, daemon-reload rồi enable/start đúng instance. Không restart mọi PHP process trên host chung. Log theo journalctl -u tên-unit và theo dõi failed jobs; không queue:retry all trước khi biết nguyên nhân.
5. Scheduler mỗi phút, nghiệp vụ theo múi giờ
# taskflow-scheduler.service
[Unit]
Description=Run TaskFlow due scheduled commands
After=network.target
[Service]
Type=oneshot
User=taskflow
Group=taskflow
WorkingDirectory=/srv/taskflow/current
ExecStart=/usr/bin/php8.4 artisan schedule:run
TimeoutStartSec=120
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
# Separate file: taskflow-scheduler.timer
[Unit]
Description=Check TaskFlow schedule every minute
[Timer]
OnCalendar=*-*-* *:*:00
AccuracySec=1s
Unit=taskflow-scheduler.service
[Install]
WantedBy=timers.targetTách đoạn trên thành hai file. Timer gọi service mỗi phút; nếu service vẫn active thì không tạo instance mới chồng lên. TimeoutStartSec 120 làm service quá lâu thất bại để điều tra, không phải bảo đảm mọi tác vụ luôn xong trong hai phút. Không bật thêm cron hoặc schedule:work cho cùng lịch.
TaskFlow định nghĩa report overdue lúc 08:00 và prune token lúc 02:00 Asia/Ho_Chi_Minh; schedule:list local hiển thị UTC tương ứng 01:00/19:00. onOneServer và withoutOverlapping cần cache chia sẻ đúng cấu hình. Timer không tự replay toàn bộ tác vụ bỏ lỡ khi máy tắt. Prune xóa bản ghi token hết hạn nên phải review retention trước khi bật.
6. Reverb và các biến môi trường
Nếu bật realtime, chạy service Reverb loopback 127.0.0.1:8080 và proxy WSS qua hostname riêng. Nginx cần chuyển header Upgrade/Connection; proxy cả đường WebSocket /app và API /apps. REVERB_HOST/PORT/SCHEME là endpoint kết nối bên ngoài; REVERB_SERVER_HOST/PORT là nơi process bind. Chỉ public app key đi vào Vite; không đưa secret vào bundle. allowed origins là domain frontend cụ thể, không thay authorization.
Production đặt APP_ENV=production, APP_DEBUG=false, HTTPS APP_URL, cookie secure, database/session/cache dùng chung khi cần và mail transport thật nếu gửi email. Không dùng array cache cho lock đa process. Log mailer chỉ là demo, không phải giao thư tới người nhận.
7. Trình tự release có điểm dừng
- Xác nhận commit và CI, backup database/file/key và khả năng restore.
- Build release mới từ lockfile; test dùng dev dependencies, artifact PHP cuối cài --no-dev, giữ assets Vite đã build đúng biến public.
- Gắn shared storage/.env, kiểm tra quyền và target database.
- Review migration tương thích code cũ/mới; chỉ migrate --force trong cửa sổ được phê duyệt, không seed demo.
- Chạy config:cache, route:cache, view:cache, event:cache ở release mới; dừng nếu lỗi.
- Chuyển current có kiểm soát, reload pool FPM và restart đúng worker/Reverb để nạp code mới.
- Kiểm tra /up, login, quyền project, tạo/hoàn tất task, PDF private, queue drain, lịch và realtime nếu dùng.
Không chạy optimize:clear tùy tiện vì còn xóa key application cache mặc định. Ghi lại release, commit, thời điểm, migration và smoke results. /up mặc định chưa chứng minh database, queue, SMTP hoặc backup đều khỏe.
8. Rollback không chỉ đổi symlink
Rollback code chỉ an toàn nếu code trước đọc được schema/data hiện tại. Không tự migrate:rollback sau lỗi deploy; thao tác đó có thể mất dữ liệu hoặc làm code đang chạy không tương thích. Ưu tiên expand/contract, drain job có payload cũ và giữ release trước. Restore dữ liệu phải theo kế hoạch RPO/RTO, tính cả các ghi phát sinh sau backup.
Đã có mẫu deploy và schedule:list được kiểm tra local; Nginx/FPM/systemd, certificate, permissions, restart và rollback trên Linux chưa được chạy trong checkpoint này. Bài tập nghiệm thu là dựng staging riêng, ghi bằng chứng từng bước và diễn tập lỗi worker/rollback trước khi áp dụng cho production. Bài kế tiếp bổ sung health check và kế hoạch backup.
Tham khảo: Laravel deployment, Nginx WebSocket proxy, systemd timer reference. Điều hướng: Bài 33 · Lộ trình.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.