NTM Solutions

Thứ Tư, 23 tháng 9, 2026

🚀LARAVEL 13 — BÀI 47 — NGINX TRONG LARAVEL 13

Bài 46, chúng ta đã đưa Laravel 13 lên VPS.

Nhưng một Laravel project trên VPS chưa thể tự nhiên hoạt động như một website production chỉ bằng việc upload source code.

Chúng ta cần một Web Server.

Một mô hình phổ biến là:

Internet
   │
   ▼
 Nginx
   │
   ▼
PHP-FPM
   │
   ▼
Laravel 13
   │
   ├── MySQL
   ├── Storage
   └── Cache

Trong bài này chúng ta sẽ học cách cấu hình Nginx cho Laravel 13.


1. Nginx là gì?

Nginx là một web server và reverse proxy rất phổ biến.

Nó có thể:

  • nhận HTTP/HTTPS request;

  • phục vụ file tĩnh;

  • xử lý domain;

  • chuyển request PHP cho PHP-FPM;

  • reverse proxy;

  • load balancing;

  • cache;

  • giới hạn request;

  • cấu hình HTTPS;

  • chạy nhiều website trên cùng một VPS.

Trong Laravel deployment, Nginx thường đứng phía trước PHP-FPM.

Ví dụ:

Browser
   │
   │ HTTPS
   ▼
 Nginx
   │
   │ FastCGI
   ▼
PHP-FPM
   │
   ▼
Laravel

2. Tại sao Laravel cần Nginx?

Laravel không phải là web server production.

Khi development, chúng ta thường chạy:

php artisan serve

Sau đó truy cập:

http://127.0.0.1:8000

Đây là môi trường phát triển.

Production thường sử dụng:

Nginx
+
PHP-FPM
+
Laravel

Nginx nhận request:

GET /

sau đó đưa request đến Laravel.


3. Nginx và PHP-FPM

Đây là phần rất quan trọng.

Nginx không trực tiếp chạy PHP.

PHP được xử lý bởi:

PHP-FPM

PHP-FPM là:

PHP FastCGI Process Manager

Có thể hình dung:

                 ┌──────────────┐
                 │    Browser   │
                 └──────┬───────┘
                        │
                        ▼
                 ┌──────────────┐
                 │    Nginx     │
                 └──────┬───────┘
                        │
                FastCGI │
                        ▼
                 ┌──────────────┐
                 │   PHP-FPM    │
                 └──────┬───────┘
                        │
                        ▼
                 ┌──────────────┐
                 │  Laravel 13  │
                 └──────────────┘

Nginx đảm nhiệm phần web server.

PHP-FPM đảm nhiệm việc chạy PHP.

Laravel xử lý application logic.


4. Laravel 13 yêu cầu PHP phiên bản nào?

Laravel 13 yêu cầu:

PHP >= 8.3

Vì vậy server của chúng ta trong khóa học sử dụng:

Ubuntu
Nginx
PHP 8.3
PHP-FPM
MySQL
Composer
Laravel 13

Laravel cũng yêu cầu một số PHP extension như:

Ctype
cURL
DOM
Fileinfo
Filter
Hash
Mbstring
OpenSSL
PCRE
PDO
Session
Tokenizer
XML

Đây là các yêu cầu chính thức của Laravel 13.


5. Kiểm tra Nginx

Trên VPS:

nginx -v

Ví dụ:

nginx version: nginx/1.24.0

Kiểm tra trạng thái:

sudo systemctl status nginx

Nếu đang chạy:

Active: active (running)

Khởi động:

sudo systemctl start nginx

Cho Nginx tự khởi động cùng server:

sudo systemctl enable nginx

Restart:

sudo systemctl restart nginx

Reload:

sudo systemctl reload nginx

6. Kiểm tra PHP-FPM

Ví dụ PHP 8.3:

sudo systemctl status php8.3-fpm

Nếu chưa chạy:

sudo systemctl start php8.3-fpm

Enable:

sudo systemctl enable php8.3-fpm

Restart:

sudo systemctl restart php8.3-fpm

7. Nginx configuration nằm ở đâu?

Trên Ubuntu, các file thường nằm trong:

/etc/nginx/

Cấu trúc phổ biến:

/etc/nginx/
├── nginx.conf
├── sites-available/
│   └── default
└── sites-enabled/
    └── default

Trong đó:

sites-available

chứa configuration của website.

sites-enabled

chứa các website đang được enable.


8. Tạo configuration cho Laravel

Giả sử project của chúng ta nằm tại:

/var/www/blog

Laravel có:

/var/www/blog/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── resources/
├── routes/
├── storage/
├── vendor/
└── artisan

Điểm quan trọng:

Nginx phải trỏ vào thư mục public.

Không được trỏ vào:

/var/www/blog

mà phải là:

/var/www/blog/public

Laravel chính thức cũng yêu cầu web server hướng request đến public/index.php, thay vì project root, nhằm tránh expose các file nhạy cảm như .env.


9. Tạo Server Block

Tạo file:

sudo nano /etc/nginx/sites-available/blog

Nội dung:

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    root /var/www/blog/public;

    index index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico {
        access_log off;
        log_not_found off;
    }

    location = /robots.txt {
        access_log off;
        log_not_found off;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;

        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;

        include fastcgi_params;

        fastcgi_buffer_size 32k;
        fastcgi_buffers 8 32k;
        fastcgi_busy_buffers_size 64k;

        fastcgi_hide_header X-Powered-By;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Đây là cấu hình dựa trên cấu hình Nginx production được Laravel 13 documentation cung cấp, với đường dẫn project và PHP-FPM socket cần thay đổi theo server thực tế.


10. Giải thích server

server {
}

Một server block đại diện cho một website hoặc virtual host.

Ví dụ:

example.com

có thể có một server block.

Website khác:

abc.com

có thể có server block khác.

Do đó một VPS có thể chạy:

VPS
│
├── example.com
│
├── abc.com
│
└── xyz.com

11. listen

listen 80;

Port:

80

dành cho HTTP.

IPv6:

listen [::]:80;

Khi dùng HTTPS sau này:

listen 443 ssl;

12. server_name

Ví dụ:

server_name example.com www.example.com;

Nginx sẽ biết request dành cho website nào.

Ví dụ browser truy cập:

https://example.com

Nginx tìm server block có:

server_name example.com;

13. root

Đây là một trong những dòng quan trọng nhất:

root /var/www/blog/public;

Không phải:

root /var/www/blog;

Mà:

root /var/www/blog/public;

Vì Laravel có cấu trúc:

blog/
├── app/
├── config/
├── resources/
├── routes/
├── storage/
├── vendor/
└── public/
    ├── index.php
    ├── build/
    ├── favicon.ico
    └── ...

Browser chỉ nên truy cập phần:

public/

14. Tại sao không trỏ vào project root?

Giả sử chúng ta cấu hình:

root /var/www/blog;

Khi đó có nguy cơ expose các file như:

.env
composer.json
composer.lock
artisan
config/
storage/

Đặc biệt .env chứa những thông tin như:

DB_PASSWORD
MAIL_PASSWORD
AWS_SECRET
APP_KEY

Đây là vấn đề bảo mật nghiêm trọng.

Do đó:

❌ /var/www/blog

phải chuyển thành:

✅ /var/www/blog/public

15. index

index index.php;

Khi request đến:

/

Nginx biết entry point chính là:

index.php

Laravel sử dụng:

public/index.php

làm entry point của ứng dụng.


16. location /

Phần quan trọng:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Đây là phần giúp Laravel routing hoạt động.

Ví dụ:

/blog

hoặc:

/blog/laravel-13

không nhất thiết phải là file vật lý.

Nginx sẽ thử:

$uri

Nếu không tồn tại:

$uri/

Nếu vẫn không tồn tại:

/index.php

và giữ query string.

Laravel sau đó nhận request và xử lý:

Route::get('/blog', ...);

hoặc:

Route::get('/blog/{post}', ...);

17. Hiểu try_files bằng ví dụ

Giả sử browser gọi:

/images/logo.png

Nếu file tồn tại:

public/images/logo.png

Nginx phục vụ trực tiếp.

Không cần PHP.

Nhưng nếu gọi:

/blog

không có file:

public/blog

Nginx chuyển request về:

public/index.php

Sau đó Laravel xử lý route.


18. Request Laravel thực tế

Ví dụ:

GET /blog

Luồng xử lý:

Browser
   │
   ▼
Nginx
   │
   ├── public/blog tồn tại?
   │        │
   │        └── Không
   │
   ▼
public/index.php
   │
   ▼
PHP-FPM
   │
   ▼
Laravel Router
   │
   ▼
BlogController
   │
   ▼
Blade
   │
   ▼
HTML

19. location ~ ^/index\.php

Đây là phần chuyển PHP request cho PHP-FPM:

location ~ ^/index\.php(/|$) {

Laravel 13 documentation sử dụng chính pattern này trong cấu hình Nginx production.


20. fastcgi_pass

Ví dụ:

fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;

Nginx nói:

Hãy chuyển PHP request cho PHP-FPM 8.3.

Socket có thể khác tùy server.

Kiểm tra:

ls /var/run/php/

Có thể thấy:

php8.3-fpm.sock

Khi đó:

fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;

Nếu server sử dụng PHP phiên bản khác thì đường dẫn phải thay đổi tương ứng.


21. SCRIPT_FILENAME

fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;

Dòng này cho PHP-FPM biết file PHP thực tế cần chạy.

Laravel configuration chính thức cũng sử dụng:

$realpath_root$fastcgi_script_name

trong server block mẫu.


22. include fastcgi_params

include fastcgi_params;

Nó đưa các FastCGI parameters cần thiết vào request.

Không nên tùy tiện bỏ dòng này khỏi cấu hình.


23. Chặn file ẩn

Cấu hình:

location ~ /\.(?!well-known).* {
    deny all;
}

Mục đích là chặn truy cập đến các file hoặc thư mục bắt đầu bằng:

.

Ví dụ:

.env
.git
.gitignore

Trong đó .env đặc biệt quan trọng.

Laravel 13 documentation cũng đưa rule này vào cấu hình Nginx mẫu.


24. favicon.icorobots.txt

Có thể sử dụng:

location = /favicon.ico {
    access_log off;
    log_not_found off;
}

location = /robots.txt {
    access_log off;
    log_not_found off;
}

Hai file này thường được browser hoặc crawler truy cập thường xuyên.

Không cần ghi log những request không đáng kể này.


25. Enable website

Sau khi tạo:

/etc/nginx/sites-available/blog

tạo symbolic link:

sudo ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/blog

Có thể xóa site mặc định:

sudo rm /etc/nginx/sites-enabled/default

26. Kiểm tra configuration

Đừng restart Nginx ngay.

Trước tiên:

sudo nginx -t

Nếu đúng:

syntax is ok
test is successful

Sau đó:

sudo systemctl reload nginx

Đây là thói quen rất quan trọng.

Luôn:

Sửa config
    ↓
nginx -t
    ↓
OK?
    ↓
reload nginx

Không nên:

Sửa config
    ↓
restart ngay

nếu chưa kiểm tra syntax.


27. Cấu hình domain

Giả sử domain:

example.com

DNS cần trỏ:

example.com → IP VPS

Ví dụ:

A
example.com
123.123.123.123

Và:

A
www
123.123.123.123

Sau đó Nginx:

server_name example.com www.example.com;

28. Một VPS chạy nhiều website

Nginx cho phép:

VPS
│
├── example.com
│      └── /var/www/example
│
├── blog.com
│      └── /var/www/blog
│
└── shop.com
       └── /var/www/shop

Mỗi website có một server block.

Ví dụ:

/etc/nginx/sites-available/
├── example
├── blog
└── shop

và:

/etc/nginx/sites-enabled/
├── example
├── blog
└── shop

Đây là một trong những lý do Nginx rất phù hợp với VPS.


29. HTTPS

Website production nên sử dụng:

HTTPS

thay vì:

HTTP

Mô hình:

Browser
   │
 HTTPS :443
   ▼
 Nginx
   │
   ▼
PHP-FPM
   │
   ▼
Laravel

Thông thường có thể sử dụng Let's Encrypt + Certbot để cấp SSL certificate.

Sau khi cấu hình SSL:

http://example.com

có thể redirect sang:

https://example.com

30. Nginx và Laravel Storage

Trong Blog CMS của chúng ta có upload:

Post Image

Laravel public disk mặc định lưu tại:

storage/app/public

Để browser truy cập được, tạo symbolic link:

php artisan storage:link

Khi đó:

storage/app/public
        │
        │ symbolic link
        ▼
public/storage

Laravel documentation cũng sử dụng storage:link cho public disk.

Ví dụ database lưu:

posts/abc.jpg

thì URL có thể là:

Storage::url($post->image)

hoặc:

asset('storage/' . $post->image)

31. Nginx và file upload

Blog CMS của chúng ta có upload image.

Nginx cũng có giới hạn kích thước request.

Ví dụ:

client_max_body_size 10M;

Nếu website cho phép upload file lớn hơn mặc định, có thể cấu hình:

server {
    ...

    client_max_body_size 10M;
}

Sau đó:

sudo nginx -t

và:

sudo systemctl reload nginx

Tuy nhiên còn phải kiểm tra giới hạn của PHP:

upload_max_filesize
post_max_size

Ví dụ:

upload_max_filesize = 10M
post_max_size = 12M

Không nên chỉ sửa Nginx mà quên PHP.


32. Lỗi 413 Request Entity Too Large

Nếu upload file quá lớn, Nginx có thể trả:

413 Request Entity Too Large

Nguyên nhân thường liên quan:

client_max_body_size

Ví dụ:

client_max_body_size 2M;

nhưng người dùng upload:

5MB

Nginx có thể chặn request trước khi Laravel nhận được.


33. Nginx log

Log thường nằm trong:

/var/log/nginx/

Ví dụ:

access.log
error.log

Xem error log:

sudo tail -f /var/log/nginx/error.log

Xem access log:

sudo tail -f /var/log/nginx/access.log

Khi website gặp lỗi:

502
403
404
413

hãy kiểm tra log.


34. Lỗi 502 Bad Gateway

Một lỗi rất phổ biến:

502 Bad Gateway

Nếu:

Nginx
   │
   X
PHP-FPM

thì Nginx không thể giao tiếp với PHP-FPM.

Kiểm tra:

sudo systemctl status php8.3-fpm

Kiểm tra socket:

ls /var/run/php/

Ví dụ socket thực tế là:

php8.3-fpm.sock

nhưng Nginx lại cấu hình:

fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;

thì sẽ lỗi.


35. Lỗi 403 Forbidden

Nếu gặp:

403 Forbidden

có thể kiểm tra:

  • quyền thư mục;

  • owner;

  • Nginx configuration;

  • public/;

  • file permissions.

Laravel cần web server có quyền ghi vào:

storage/

và:

bootstrap/cache/

Laravel deployment documentation cũng yêu cầu các thư mục này phải writable bởi web server process.


36. Lỗi 404

Nếu:

/blog

trả:

404

hãy kiểm tra:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Nếu thiếu:

/index.php

Laravel routing có thể không hoạt động đúng.

Sau đó kiểm tra route:

php artisan route:list

37. Lỗi CSS/JS không tải

Nếu Laravel chạy nhưng:

CSS
JS
Image

không hiển thị, kiểm tra:

public/build

Nếu dùng Vite, trên server cần build:

npm install
npm run build

Sau đó kiểm tra:

public/build/

Laravel không tự động biến source frontend thành production assets chỉ vì Nginx được cấu hình.


38. Nginx không thay thế Laravel

Một hiểu nhầm phổ biến:

Nginx = Laravel

Không đúng.

Nginx chỉ là web server.

Kiến trúc:

Nginx
  ↓
PHP-FPM
  ↓
Laravel
  ↓
Application
  ↓
Database

Mỗi thành phần có nhiệm vụ riêng.


39. Nginx + Laravel + MySQL

Một server Laravel production hoàn chỉnh có thể nhìn như sau:

                    INTERNET
                        │
                        ▼
                   ┌─────────┐
                   │  Nginx  │
                   └────┬────┘
                        │
                        ▼
                  ┌───────────┐
                  │ PHP-FPM   │
                  └─────┬─────┘
                        │
                        ▼
                 ┌─────────────┐
                 │ Laravel 13  │
                 └──────┬──────┘
                        │
            ┌───────────┼───────────┐
            ▼           ▼           ▼
         MySQL       Storage      Cache

Đây chính là kiến trúc cơ bản mà chúng ta đang xây dựng cho Blog CMS.


40. Production Nginx configuration

Một configuration tương đối hoàn chỉnh:

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    root /var/www/blog/public;

    index index.php;

    charset utf-8;

    client_max_body_size 10M;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico {
        access_log off;
        log_not_found off;
    }

    location = /robots.txt {
        access_log off;
        log_not_found off;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;

        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;

        include fastcgi_params;

        fastcgi_buffer_size 32k;
        fastcgi_buffers 8 32k;
        fastcgi_busy_buffers_size 64k;

        fastcgi_hide_header X-Powered-By;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Laravel 13's official deployment example also includes security headers such as X-Frame-Options and X-Content-Type-Options, the Laravel try_files rule, PHP-FPM configuration and hidden-file protection.


41. Sau khi sửa Nginx phải làm gì?

Quy trình:

sudo nginx -t

Nếu:

syntax is ok
test is successful

thì:

sudo systemctl reload nginx

Kiểm tra:

sudo systemctl status nginx

Sau đó mở:

https://example.com

42. Checklist Laravel 13 + Nginx

Trước khi xem deployment là hoàn thành:

[ ] PHP >= 8.3

[ ] PHP-FPM đang chạy

[ ] Nginx đang chạy

[ ] root trỏ tới /public

[ ] server_name đúng domain

[ ] try_files đúng

[ ] fastcgi_pass đúng PHP-FPM socket

[ ] SCRIPT_FILENAME đúng

[ ] .env không public

[ ] storage/ có quyền ghi

[ ] bootstrap/cache có quyền ghi

[ ] php artisan storage:link

[ ] npm run build

[ ] nginx -t thành công

[ ] nginx reload

[ ] HTTPS hoạt động

[ ] APP_DEBUG=false

43. Bài tập thực hành

Bài tập 1

Kiểm tra Nginx:

nginx -v

Bài tập 2

Kiểm tra PHP-FPM:

sudo systemctl status php8.3-fpm

Bài tập 3

Tìm PHP-FPM socket:

ls /var/run/php/

Bài tập 4

Tạo server block:

/etc/nginx/sites-available/blog

và cấu hình Laravel:

/var/www/blog/public

Bài tập 5

Kiểm tra:

sudo nginx -t

Bài tập 6

Reload:

sudo systemctl reload nginx

Bài tập 7

Mở Blog CMS và kiểm tra:

/
├── Login
├── Register
├── Blog
├── Category
├── Post
└── Admin

Bài tập 8

Upload một hình ảnh vào Blog CMS.

Kiểm tra:

storage/app/public

và:

public/storage

44. Tổng kết

Sau bài này chúng ta đã hiểu được:

Nginx

là gì.

PHP-FPM

là gì.

Và quan trọng nhất:

Nginx
   ↓
PHP-FPM
   ↓
Laravel 13

Chúng ta đã biết:

  • cài và kiểm tra Nginx;

  • kiểm tra PHP-FPM;

  • tạo Server Block;

  • cấu hình server_name;

  • cấu hình root;

  • trỏ Nginx vào public/;

  • cấu hình try_files;

  • cấu hình PHP-FPM;

  • bảo vệ file ẩn;

  • cấu hình upload;

  • cấu hình domain;

  • chạy nhiều website trên một VPS;

  • đọc Nginx log;

  • xử lý lỗi 403;

  • xử lý lỗi 404;

  • xử lý lỗi 502;

  • xử lý lỗi 413;

  • kết hợp Nginx với Laravel Storage;

  • kiểm tra configuration bằng nginx -t;

  • reload Nginx.

Kiến trúc chúng ta đang hướng tới:

                    DOMAIN
                       │
                       ▼
                 ┌──────────┐
                 │  Nginx   │
                 └────┬─────┘
                      │
                      ▼
                ┌───────────┐
                │ PHP-FPM   │
                └─────┬─────┘
                      │
                      ▼
               ┌─────────────┐
               │ Laravel 13  │
               └──────┬──────┘
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
        MySQL       Storage      Cache

Đây là nền tảng rất quan trọng trước khi chúng ta đi tiếp vào Queue Worker và Scheduler.


📌 Ghi nhớ

Có 5 điều đặc biệt quan trọng:

1. Nginx không chạy PHP trực tiếp

Nginx → PHP-FPM → Laravel

2. Laravel phải trỏ vào public

root /var/www/blog/public;

3. Laravel route cần try_files

try_files $uri $uri/ /index.php?$query_string;

4. PHP-FPM socket phải chính xác

fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;

5. Luôn kiểm tra configuration trước khi reload

sudo nginx -t
sudo systemctl reload nginx

Bài tiếp theo: Bài 48 — Queue Worker & Scheduler

Chúng ta sẽ đưa những phần chạy nền của Blog CMS lên production:

Laravel Queue
      │
      ▼
Queue Worker
      │
      ├── Send Mail
      ├── Notification
      ├── Job
      └── Background Task

Scheduler
      │
      ├── Cron
      ├── Daily Task
      ├── Cleanup
      └── Scheduled Job

Đây là bước biến một Laravel project từ website đơn giản thành một ứng dụng production thực tế.

Không có nhận xét nào:

Đăng nhận xét

Facebook Youtube RSS