Đừng tìm cách xóa ‘public’ trên URL Laravel

695

Một câu hỏi mà mình thấy rất nhiều bạn thắc mắc đó là “Làm thế nào để xóa /public trên URL của Laravel?“. Thực ra hồi mới làm Laravel, mình cũng có câu hỏi y như vậy, thậm chí mình còn từng nghĩ “Sao Laravel nó ngu quá, thêm cái public để làm khó developer à”, nhưng sau khi tìm hiểu nguyên nhân sâu xa phía sau cái ‘/public’ đó, mình mới thấy mình thật ngu ngốc. Hóa ra, cái ‘/public’ đó vốn là một tính năng quan trọng, có điều mình đang dùng sai cách. Cụ thể như thế nào, mời các bạn hãy theo dõi bài viết sau đây.

I. Tại sao ‘public’ lại xuất hiện trên URL

Trước tiên, chúng ta sẽ đi tìm hiểu ý nghĩa của thư mục public trong cấu trúc thư mục Laravel.

Public có nghĩa là “công khai”, đúng như cái tên của nó, đây là thư mục chứa các file được công khai truy cập từ phía người dùng nếu bạn không có can thiệp gì thêm (như chmod, hay đặt password).

Trong thư mục này, ngoài chứa các file như ảnh, css, js, robot.txt,… thì còn chứa một file vô cùng quan trọng đó là file index.php – Đây là file đầu tiên tiếp nhận request trong chu trình xử lý của Laravel. Request từ đây được truyền lần lượt tới route, tới middleware rồi mới tới controller để xử lý.

Do file index.php nằm trong thư mục public, nên khi bạn trỏ tên miền vào thư mục root của Laravel, bạn phải đi vào http://domain.com/public thì mới dự án mới chạy được – Đây chính là lý do khiến nhiều bạn muốn xóa ‘/public’ khỏi URL để nhìn cho đỡ ngứa mắt.

II. Tại sao file index.php lại nằm trong thư mục public, sao không nằm ở thư mục root cho ‘dễ thở’

Câu trả lời là “để bảo mật và hạn chế lỗi“.

GIẢI THÍCH

Giả sử file index.php được đặt tại thư mục root thay vì đặt trong thư mục ‘public’, và domain của bạn là domain.com được trỏ tới thư mục root của dự án. Vậy thì khi mình truy cập vào domain.com/.env thì sao? Có phải nó sẽ hiển thị hết nội dung của file .env – nơi chứa các thông tin cấu hình (có cả cấu hình về database) của dự án. Rồi khi mình truy cập trực tiếp vào một file .php thì sao, ví dụ domain.com/routes/web.php – chẳng phải nó cũng sẽ bị lỗi, vì lẽ ra request phải đi qua public/index.php trước rồi mới được truyền tới route.

Nhưng khi file index.php được đặt trong thư mục public, và domain của bạn cũng được trỏ vào thư mục public thì mình lại chẳng có cơ hội để thực hiện các hành động truy cập trực tiếp vào file .env hay file .php như tình huống trên. Bởi mọi request lúc này đã bị giới hạn trong thư mục public – giúp dự án bảo mật hơn và hạn chế các lỗi phát sinh.

Bạn đừng quên rằng Laravel là opensource. Vì thế, ngoài bạn ra, có rất nhiều người khác biết rõ cấu trúc dự án của bạn thế nào. Dể hạn chế việc “người ngoài” cố tình phá hoại trang web, thì chúng ta nên trỏ domain vào thư mục public để chặn hoàn toàn việc truy cập vào các thư mục khác của dự án.

III. Cách xóa ‘public’ khỏi URL theo cách chính xác nhất

Cách xóa khôn ngoan nhất đó chính là trỏ tên miền vào vào thư mục public, thay vì trỏ vào thư mục root của dự án Laravel.

Theo như phần docs deploy của Laravel 7.x, với nginx bạn sẽ cấu hình như sau:

server {
    listen 80;
    server_name example.com;
    root /path/to/laravel-project/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm 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; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

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

Hãy để ý dòng số 4, bạn sẽ thấy Laravel chỉ rõ đâu mới là thư mục mà domain example.com được trỏ vào.

IV. Lời kết

Nếu như bạn làm đúng, thì trên URL sẽ không xuất hiện /public (trừ khi bạn có một cái route là /public thì chịu). Vì thế đừng tìm các trick để xóa nó, thay vào đó, hãy làm đúng.

Chúc các bạn thành công. Hihi.