Ở các bài trước, chúng ta đã lần lượt xây dựng và triển khai Blog CMS:
Bài 45 → Shared Hosting
Bài 46 → VPS
Bài 47 → Nginx
Bài 48 → Queue Worker & Scheduler
Đến đây ứng dụng đã có thể chạy trên production.
Nhưng:
Chạy được chưa có nghĩa là đã được cấu hình tốt cho production.
Một Laravel application thực tế cần quan tâm thêm:
Performance
Cache
Environment
Debug
Security
Database
Queue
Storage
Logs
Deployment
Configuration
Laravel 13 cung cấp sẵn nhiều công cụ để tối ưu những vấn đề này. Trong tài liệu deployment chính thức, Laravel đặc biệt khuyến nghị cache configuration, events, routes và views khi triển khai production.
1. Development và Production khác nhau
Trong quá trình học, chúng ta thường chạy:
php artisan serve
với:
APP_ENV=local
APP_DEBUG=true
Điều này phù hợp cho development.
Production nên sử dụng:
APP_ENV=production
APP_DEBUG=false
Mô hình:
Development
APP_ENV=local
APP_DEBUG=true
│
▼
Debug nhiều
Hot reload
Test
Development
Production:
Production
APP_ENV=production
APP_DEBUG=false
│
▼
Security
Performance
Caching
Monitoring
2. File .env
Laravel sử dụng .env để chứa các giá trị phụ thuộc môi trường.
Ví dụ:
APP_NAME="Blog CMS"
APP_ENV=production
APP_KEY=base64:...
APP_DEBUG=false
APP_URL=https://example.com
Database:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=blog_user
DB_PASSWORD=********
Mail:
MAIL_MAILER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=...
MAIL_PASSWORD=...
MAIL_ENCRYPTION=tls
Queue:
QUEUE_CONNECTION=database
Cache:
CACHE_STORE=database
Các giá trị này có thể thay đổi giữa:
Local
Staging
Production
Laravel cũng khuyến cáo không commit .env vào source control vì file này có thể chứa credentials và thông tin nhạy cảm.
3. .env không phải file để đưa lên Git
Không nên:
git add .env
Thay vào đó:
.env
nên được ignore.
Thông thường project có:
.env
.env.example
Trong đó:
.env
Chứa cấu hình thực tế:
DB_PASSWORD=secret-password
.env.example
Chỉ chứa cấu trúc mẫu:
DB_PASSWORD=
Nhờ vậy người khác có thể biết application cần những biến môi trường nào mà không biết password production.
4. APP_ENV
Ví dụ:
APP_ENV=production
Laravel có thể kiểm tra environment:
use Illuminate\Support\Facades\App;
if (App::environment('production')) {
// Production
}
Hoặc:
if (App::environment(['local', 'staging'])) {
// Local hoặc staging
}
Trong production Blog CMS:
APP_ENV=production
là lựa chọn phù hợp.
5. APP_DEBUG
Đây là một trong những biến quan trọng nhất:
APP_DEBUG=false
Development:
APP_DEBUG=true
Production:
APP_DEBUG=false
Laravel documentation cảnh báo APP_DEBUG=true trên production có thể làm lộ thông tin nhạy cảm cho người dùng.
6. Điều gì xảy ra khi APP_DEBUG=true?
Giả sử code có lỗi:
$post->category->name;
nhưng:
$post->category
là null.
Development có thể hiển thị rất nhiều thông tin:
Exception
File
Line
Stack Trace
Environment
Configuration
SQL
Request
Điều này cực kỳ hữu ích khi debug.
Nhưng production:
APP_DEBUG=true
có thể biến thông tin debug thành dữ liệu mà attacker có thể khai thác.
Do đó:
APP_DEBUG=false
7. Production Error Page
Production nên hiển thị một thông báo thân thiện:
Something went wrong.
Please try again later.
thay vì:
SQLSTATE...
/var/www/blog/vendor/...
DB_PASSWORD...
Stack trace...
Nguyên tắc:
Development
↓
Developer cần thông tin
Production
↓
User cần thông báo an toàn
8. APP_KEY
Laravel application cần:
APP_KEY=base64:...
Không được tùy tiện thay đổi APP_KEY trên production đang chạy.
Nếu thay đổi key, những dữ liệu được mã hóa bằng key cũ có thể không còn giải mã được.
Ví dụ:
php artisan key:generate
Chỉ nên thực hiện khi tạo application hoặc khi bạn hiểu rõ tác động.
Không nên mỗi lần deploy lại chạy:
php artisan key:generate
9. APP_URL
Production nên đặt URL thật:
APP_URL=https://example.com
Không nên để:
APP_URL=http://127.0.0.1:8000
nếu application đang chạy trên Internet.
APP_URL có thể được sử dụng trong nhiều tình huống tạo URL, command và các thành phần khác của application.
10. Cache là gì?
Cache là kỹ thuật lưu lại dữ liệu hoặc kết quả đã được xử lý để lần sau lấy nhanh hơn.
Ví dụ:
Không Cache
Request
↓
Database
↓
Query
↓
Process
↓
Response
Có Cache:
Request
↓
Cache
│
├── Có → Response nhanh
│
└── Không
↓
Database
↓
Cache
↓
Response
11. Laravel Cache
Laravel cung cấp API thống nhất cho nhiều cache backend.
Ví dụ:
use Illuminate\Support\Facades\Cache;
Lưu:
Cache::put('site_name', 'Blog CMS', 3600);
Lấy:
$name = Cache::get('site_name');
Hoặc:
$name = Cache::get('site_name', 'Default');
Xóa:
Cache::forget('site_name');
12. Cache::remember()
Đây là một pattern rất hữu ích.
Ví dụ:
$categories = Cache::remember(
'blog.categories',
3600,
function () {
return Category::active()
->withCount('posts')
->orderBy('name')
->get();
}
);
Luồng:
Request
│
▼
Cache?
│
├── Có
│ ↓
│ Return
│
└── Không
↓
Database
↓
Cache
↓
Return
Thay vì query database liên tục, dữ liệu có thể được sử dụng từ cache trong thời gian đã cấu hình.
13. Cache cho Blog CMS
Trong Blog CMS, chúng ta có:
Categories
Tags
Settings
Statistics
Popular Posts
Homepage Data
Một số dữ liệu không thay đổi liên tục có thể phù hợp với cache.
Ví dụ:
$categories = Cache::remember(
'categories.active',
3600,
fn () => Category::active()
->withCount('posts')
->orderBy('name')
->get()
);
14. Không nên cache mọi thứ
Cache không phải:
Càng nhiều càng tốt.
Ví dụ:
User profile
Admin permissions
Realtime stock price
Current order status
có thể cần dữ liệu mới.
Nếu cache quá lâu:
Database
↓
Data mới
Cache
↓
Data cũ
Người dùng có thể nhìn thấy dữ liệu stale.
Do đó cần cân nhắc:
Data thay đổi thường xuyên
→ Cache ngắn hoặc không cache
Data ít thay đổi
→ Cache lâu hơn
15. Clear Cache
Trong development hoặc khi troubleshooting:
php artisan optimize:clear
Laravel 13 cung cấp optimize:clear để xóa các cache được tạo bởi optimize và các key trong default cache store.
Có thể sử dụng riêng:
php artisan config:clear
hoặc:
php artisan route:clear
hoặc:
php artisan view:clear
Tùy trường hợp.
16. Production Optimization
Laravel 13 có command:
php artisan optimize
Đây là command rất quan trọng khi deploy production.
Laravel sẽ cache các thành phần quan trọng như:
Configuration
Events
Routes
Views
Laravel documentation khuyến nghị chạy php artisan optimize trong deployment process.
17. config:cache
Chạy:
php artisan config:cache
Laravel gom configuration vào cache.
Điều này giúp giảm việc phải đọc nhiều file configuration khi application boot.
18. Lưu ý cực kỳ quan trọng về env()
Sau khi:
php artisan config:cache
không nên viết:
$name = env('APP_NAME');
trực tiếp trong application code.
Không nên:
class BlogController
{
public function index()
{
$debug = env('APP_DEBUG');
}
}
Thay vào đó:
$debug = config('app.debug');
Tư duy đúng:
.env
↓
config/*.php
↓
config(...)
Ví dụ trong:
config/app.php
có:
'debug' => (bool) env('APP_DEBUG', false),
Application sử dụng:
config('app.debug');
Laravel documentation lưu ý rằng sau khi config:cache, .env không còn được load trong request và env() bên ngoài configuration files có thể trả về null.
19. Cache Routes
Laravel có:
php artisan route:cache
Command này tạo route cache.
Đặc biệt có lợi với application có nhiều routes.
Blog CMS của chúng ta có thể có:
Web Routes
Admin Routes
Blog Routes
API Routes
Auth Routes
Khi số lượng route tăng lên, route caching giúp giảm thời gian đăng ký routes khi application boot.
20. Cache Views
Chạy:
php artisan view:cache
Laravel sẽ precompile Blade views.
Ví dụ:
resources/views/
↓
Blade
↓
Compiled Views
Nhờ vậy production không phải compile từng Blade view lần đầu khi request.
Laravel khuyến nghị cache views trong deployment process.
21. Cache Events
Laravel cũng hỗ trợ:
php artisan event:cache
Command này cache event → listener mappings.
Ví dụ Blog CMS:
Registered
↓
SendWelcomeEmail
PostPublished
↓
SendNotification
PostUpdated
↓
ClearPostCache
Khi application lớn, caching event discovery có thể giúp quá trình boot hiệu quả hơn.
22. Production Optimize đầy đủ
Có thể chạy:
php artisan optimize
Thay vì phải chạy riêng:
php artisan config:cache
php artisan event:cache
php artisan route:cache
php artisan view:cache
Laravel 13 cung cấp optimize như command tổng hợp cho deployment.
23. Autoloader Optimization
Khi deploy production:
composer install \
--no-dev \
--optimize-autoloader
Trong một dòng:
composer install --no-dev --optimize-autoloader
Ý nghĩa:
--no-dev
Không cài các package development không cần thiết.
Ví dụ:
PHPUnit
Debugbar
Development tools
--optimize-autoloader giúp Composer tối ưu class autoloading.
24. Không chạy npm run dev trên production
Development:
npm run dev
Production:
npm run build
Ví dụ:
npm install
npm run build
Sau đó:
public/build
chứa production assets.
25. Laravel Vite
Nếu Blog CMS sử dụng Vite:
resources/css
resources/js
thì production nên build:
npm run build
Thay vì để development server chạy trên production.
Mô hình:
Development
↓
npm run dev
Production
↓
npm run build
26. Database Optimization
Một trong những bottleneck lớn nhất của web application thường là database.
Ví dụ:
Post::all();
có thể lấy quá nhiều dữ liệu.
Không nên:
$posts = Post::all();
nếu database có:
1,000,000 posts
Thay vào đó:
$posts = Post::paginate(10);
27. Pagination
Blog CMS của chúng ta đã sử dụng:
->paginate(10)
Ví dụ:
$posts = Post::published()
->latest('published_at')
->paginate(10);
Thay vì lấy toàn bộ:
Post::all();
Database chỉ phải xử lý lượng dữ liệu phù hợp với page hiện tại.
28. Eager Loading
Một lỗi rất phổ biến:
$posts = Post::all();
foreach ($posts as $post) {
echo $post->user->name;
echo $post->category->name;
}
Có thể tạo ra vấn đề N+1 Query.
Thay vào đó:
$posts = Post::with([
'user',
'category'
])->get();
Laravel sẽ eager load relationship.
29. Blog CMS và N+1
Controller của chúng ta đã sử dụng:
Post::published()
->with(['user', 'category'])
->latest('published_at')
->paginate(10);
Đây là cách tốt hơn:
Posts
│
├── User
└── Category
thay vì để từng Post tự query User và Category.
30. Chỉ lấy những cột cần thiết
Không phải lúc nào cũng cần:
Post::all();
với toàn bộ column.
Ví dụ:
Post::query()
->select([
'id',
'title',
'slug',
'excerpt'
])
->latest()
->paginate(10);
Nếu page chỉ hiển thị:
Title
Excerpt
thì không nhất thiết phải lấy toàn bộ content lớn.
31. Database Index
Các column thường được:
WHERE
ORDER BY
JOIN
có thể cần index phù hợp.
Ví dụ:
posts.slug
posts.user_id
posts.category_id
posts.status
posts.published_at
Migration:
$table->index('status');
$table->index('published_at');
Foreign key thường đã có index phù hợp tùy schema và cách khai báo, nhưng cần hiểu execution plan và workload thực tế thay vì index mọi column.
32. Không index mọi column
Sai lầm:
Index tất cả
Index giúp query:
Nhanh hơn
nhưng cũng có cost:
INSERT
UPDATE
DELETE
phải duy trì index.
Do đó:
Query thường xuyên
↓
Phân tích
↓
Index phù hợp
Không phải:
Column nào cũng index
33. Cache Database Query
Không nên cache mọi query.
Ví dụ categories:
$categories = Cache::remember(
'categories.active',
3600,
fn () => Category::active()
->withCount('posts')
->orderBy('name')
->get()
);
Khi category thay đổi:
Cache::forget('categories.active');
Như vậy cache có thể được invalidated đúng thời điểm.
34. Cache Invalidation
Một trong những vấn đề khó của cache là:
Cache cũ
Ví dụ:
10:00
Category = Laravel
cache:
Laravel
11:00 admin đổi:
Laravel → Laravel 13
nhưng cache vẫn:
Laravel
Nếu không clear/invalidate:
Database = Laravel 13
Cache = Laravel
Vì vậy khi update dữ liệu quan trọng:
Cache::forget('categories.active');
hoặc sử dụng strategy phù hợp.
35. Storage
Production cần kiểm tra:
php artisan storage:link
Laravel sử dụng:
storage/app/public
cho public files và symbolic link:
public/storage
để browser có thể truy cập.
Blog CMS:
Post Image
↓
storage/app/public/posts
↓
public/storage
↓
Browser
36. Permissions
Laravel cần quyền ghi cho:
storage/
bootstrap/cache/
Ví dụ trên Ubuntu + Nginx/PHP-FPM:
sudo chown -R www-data:www-data /var/www/blog/storage
sudo chown -R www-data:www-data /var/www/blog/bootstrap/cache
Tùy server setup, user chạy PHP-FPM có thể khác www-data.
Không nên dùng:
chmod -R 777
chỉ để “cho chạy được”.
37. Vì sao chmod 777 nguy hiểm?
chmod -R 777 /var/www/blog
nghĩa là:
Owner → read/write/execute
Group → read/write/execute
Others → read/write/execute
Đây là quyền quá rộng.
Thay vào đó:
Owner
Group
Web Server
nên được cấu hình đúng.
Nguyên tắc:
Cấp quyền tối thiểu cần thiết.
38. Security — .env
Không bao giờ public:
.env
Nginx phải trỏ:
root /var/www/blog/public;
chứ không:
root /var/www/blog;
Laravel deployment documentation nhấn mạnh rằng web server phải hướng request tới public/index.php, không phải project root, để tránh expose sensitive files.
39. Security — APP_DEBUG
Production:
APP_DEBUG=false
Không:
APP_DEBUG=true
Đây là một trong những cấu hình bảo mật cơ bản nhất của Laravel production.
40. Security — APP_ENV
Production:
APP_ENV=production
Giúp application biết mình đang chạy trong environment nào.
41. Security — Secret Keys
Các thông tin như:
APP_KEY
DB_PASSWORD
MAIL_PASSWORD
AWS_SECRET
API_KEY
không nên hard-code vào source:
$password = '123456';
Không nên:
Git
↓
Source
↓
Secret
Mà:
Environment
↓
.env
↓
config
↓
Application
42. Security — Password
Laravel không nên lưu password dạng plain text.
Không:
password = 123456
Laravel sử dụng hashing.
Ví dụ:
use Illuminate\Support\Facades\Hash;
$hash = Hash::make($password);
Kiểm tra:
Hash::check($password, $hash);
43. Security — Validation
Không tin dữ liệu từ browser.
Ví dụ:
$request->validate([
'title' => ['required', 'string', 'max:255'],
'content' => ['required', 'string'],
]);
Client-side validation:
JavaScript
chỉ giúp UX.
Server-side validation:
Laravel
mới là lớp bảo vệ thực sự.
44. Security — Mass Assignment
Model:
protected $fillable = [
'name',
'slug',
'description',
'is_active',
];
Không nên cho phép user tùy tiện gửi:
role=admin
nếu role không thuộc dữ liệu họ được phép thay đổi.
Ví dụ:
User::create($request->validated());
cần kết hợp:
Validation
+
Fillable
+
Authorization
45. Security — Authorization
Authentication:
Bạn là ai?
Authorization:
Bạn được phép làm gì?
Ví dụ:
User
└── Xem bài viết
Admin
├── Tạo category
├── Sửa category
├── Xóa category
└── Quản lý user
Không nên chỉ dựa vào:
ẩn button
mà phải bảo vệ ở server bằng:
Middleware
Policy
Gate
Authorization
46. Security — CSRF
Các form web thay đổi dữ liệu cần CSRF protection.
Ví dụ Blade:
<form method="POST" action="{{ route('posts.store') }}">
@csrf
...
</form>
Laravel có cơ chế CSRF protection cho web requests.
Không nên bỏ:
@csrf
chỉ vì form vẫn submit được trong một số trường hợp.
47. Security — SQL Injection
Không nên nối chuỗi SQL trực tiếp:
DB::select(
"SELECT * FROM posts WHERE title = '$title'"
);
Thay vào đó sử dụng Query Builder/Eloquent:
Post::where('title', $title)->get();
Laravel sẽ sử dụng parameter binding phù hợp.
48. Security — XSS
Nếu nội dung user nhập:
<script>...</script>
không nên tùy tiện render raw HTML.
Blade mặc định:
{{ $post->title }}
sẽ escape output.
Cẩn thận với:
{!! $post->content !!}
Nếu content cho phép HTML, cần có chiến lược sanitization phù hợp.
49. Security — File Upload
Blog CMS của chúng ta có upload image.
Không nên chỉ kiểm tra:
filename.jpg
Mà phải validation:
'image' => [
'nullable',
'image',
'max:2048',
]
Có thể giới hạn MIME/types theo yêu cầu application.
Ngoài server validation, frontend có thể báo:
File > 2MB
để cải thiện UX.
Nhưng validation Laravel vẫn bắt buộc.
50. Security — Storage
Không nên lưu file upload tùy tiện vào:
project root
Nên sử dụng Laravel filesystem:
$image->store('posts', 'public');
Sau đó:
php artisan storage:link
Laravel filesystem cung cấp abstraction cho local, public và các storage backend khác.
51. Security — HTTPS
Production nên sử dụng:
HTTPS
Không nên:
HTTP
để đăng nhập.
Mô hình:
Browser
│
HTTPS
▼
Nginx
▼
Laravel
HTTPS bảo vệ dữ liệu trên đường truyền.
52. Security — HTTP Headers
Có thể cấu hình một số security headers tại Nginx.
Ví dụ:
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
Laravel 13 deployment configuration mẫu cũng sử dụng các header này.
Không nên copy một danh sách security headers một cách máy móc.
Mỗi header cần hiểu rõ tác dụng và khả năng ảnh hưởng tới application.
53. Rate Limiting
Các endpoint nhạy cảm như:
Login
Register
Password Reset
API
nên có rate limiting phù hợp.
Ví dụ:
User
↓
Login attempts
↓
Rate Limit
↓
Too many requests
↓
Block / Throttle
Điều này giúp giảm abuse và brute-force attempts.
54. Logs
Production không nên bật debug để “xem lỗi”.
Hãy sử dụng logs.
Ví dụ:
Log::error('Payment failed', [
'order_id' => $order->id,
]);
Log thường nằm trong:
storage/logs/
Có thể kiểm tra:
tail -f storage/logs/laravel.log
hoặc:
tail -f storage/logs/*.log
55. Health Check
Laravel 13 có health route:
/up
Mặc định route này trả:
200
nếu application boot thành công.
Nếu application gặp lỗi boot:
500
Laravel cung cấp route này để uptime monitor, load balancer hoặc hệ thống orchestration sử dụng.
Ví dụ:
https://example.com/up
56. Health Check trong Blog CMS
Có thể dùng:
Monitoring
│
▼
https://example.com/up
│
├── 200 → OK
│
└── 500 → Problem
Đây là một cách đơn giản để kiểm tra application còn hoạt động hay không.
57. Production Deployment Flow
Từ Bài 45 đến Bài 49, quy trình deployment của chúng ta có thể là:
Developer
│
▼
Git
│
▼
VPS
│
▼
composer install --no-dev --optimize-autoloader
│
▼
npm run build
│
▼
php artisan migrate --force
│
▼
php artisan optimize
│
▼
php artisan reload
│
▼
Nginx
│
▼
Laravel 13
Laravel 13 deployment documentation cũng khuyến nghị tối ưu application và reload các long-running services sau deployment để chúng sử dụng code mới.
58. Một deployment script đơn giản
Có thể hình dung quy trình:
git pull origin main
composer install --no-dev --optimize-autoloader
npm install
npm run build
php artisan migrate --force
php artisan storage:link
php artisan optimize
php artisan reload
Tùy kiến trúc Queue/Worker, có thể cần đảm bảo process monitor như Supervisor khởi động lại worker sau khi reload.
59. Không chạy migration production tùy tiện
Development:
php artisan migrate
Production:
php artisan migrate --force
Flag:
--force
cho phép migration chạy trong production mà không yêu cầu interactive confirmation.
Nhưng:
Trước khi migration production, phải hiểu migration sẽ thay đổi database như thế nào.
Đặc biệt với database lớn:
ALTER TABLE
DROP COLUMN
Index
Data migration
có thể ảnh hưởng production.
60. Backup Database
Một production application phải nghĩ đến:
Nếu database hỏng thì sao?
Không nên chỉ có:
Database
mà cần:
Database
│
▼
Backup
│
├── Daily
├── Weekly
└── Retention
Ví dụ MySQL có thể backup bằng:
mysqldump
Điều quan trọng không chỉ là:
Backup
mà còn:
Restore được hay không?
Một backup chưa từng thử restore chưa thể xem là chiến lược backup hoàn chỉnh.
61. Storage Backup
Database không phải dữ liệu duy nhất.
Blog CMS còn có:
Post Images
User Avatars
Uploaded Files
Nếu các file này nằm trong:
storage/app/public
thì cũng cần có chiến lược backup.
Production backup:
Database
+
Uploaded Files
+
Environment/Secrets strategy
62. Không backup vendor và node_modules như dữ liệu chính
Thông thường source repository có:
composer.json
composer.lock
package.json
package-lock.json
Có thể cài lại:
composer install
npm install
Do đó production backup nên tập trung vào:
Database
Uploaded Files
Application Source
Configuration/Secrets
và chiến lược khôi phục phù hợp.
63. Performance Checklist
Một Laravel production cơ bản:
[✓] PHP production configuration
[✓] OPcache
[✓] Composer optimized autoload
[✓] Config cache
[✓] Route cache
[✓] Event cache
[✓] View cache
[✓] Database indexes
[✓] Pagination
[✓] Eager loading
[✓] Appropriate cache
[✓] Queue
[✓] Scheduler
[✓] Nginx
[✓] PHP-FPM
Không phải tất cả đều phải tối ưu cực đại ngay từ đầu.
Nguyên tắc:
Đo → tìm bottleneck → tối ưu.
64. Đừng tối ưu mù quáng
Ví dụ application chậm.
Không nên ngay lập tức:
Redis
Horizon
Octane
Multiple servers
Load Balancer
Microservices
trong khi vấn đề thực sự là:
N+1 Query
hoặc:
SELECT *
hoặc:
Không có index
Quy trình tốt hơn:
Problem
↓
Measure
↓
Identify bottleneck
↓
Optimize
↓
Measure again
65. Production Stack của Blog CMS
Sau 49 bài, Blog CMS đã đi từ:
PHP
đến:
Laravel 13
và cuối cùng:
INTERNET
│
▼
HTTPS
│
▼
Nginx
│
┌───────────┴───────────┐
│ │
PHP-FPM Static Files
│
▼
Laravel 13
│
┌─────────┼─────────┐
│ │ │
▼ ▼ ▼
MySQL Cache Storage
│
│
▼
Database
Queue:
Laravel → Queue → Worker → Supervisor
Scheduler:
Cron → schedule:run → Laravel Scheduler
Đây không còn là một project PHP đơn giản.
Đây đã là một Laravel application có kiến trúc production cơ bản.
66. Production .env mẫu
Ví dụ:
APP_NAME="Blog CMS"
APP_ENV=production
APP_KEY=base64:YOUR_REAL_APP_KEY
APP_DEBUG=false
APP_URL=https://example.com
LOG_CHANNEL=stack
LOG_LEVEL=error
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=blog_user
DB_PASSWORD=YOUR_DATABASE_PASSWORD
QUEUE_CONNECTION=database
CACHE_STORE=database
Không copy nguyên mẫu này vào production.
Các giá trị:
APP_KEY
DB_PASSWORD
MAIL_PASSWORD
API_KEY
phải sử dụng secret thật của server.
67. Production Command Checklist
Sau khi deploy code:
composer install --no-dev --optimize-autoloader
Build frontend:
npm run build
Migration:
php artisan migrate --force
Storage:
php artisan storage:link
Optimization:
php artisan optimize
Reload:
php artisan reload
Nếu sử dụng Supervisor cho queue worker, kiểm tra:
sudo supervisorctl status
Kiểm tra Nginx:
sudo nginx -t
Kiểm tra application:
https://example.com/up
68. Khi nào dùng optimize:clear?
Nếu production có vấn đề liên quan đến cache configuration:
php artisan optimize:clear
Sau đó kiểm tra lại .env và configuration.
Sau khi sửa xong, có thể chạy:
php artisan optimize
Tư duy:
Clear
↓
Fix
↓
Optimize
Không nên chạy optimize:clear liên tục trên production mà không hiểu lý do.
69. Những lỗi production người mới thường gặp
Lỗi 1
APP_DEBUG=true
Production.
→ Có nguy cơ lộ thông tin.
Lỗi 2
Nginx:
root /var/www/blog;
→ Sai.
Đúng:
root /var/www/blog/public;
Lỗi 3
Không chạy:
php artisan optimize
→ Có thể bỏ qua các optimization cache production.
Lỗi 4
Deploy code mới nhưng Worker vẫn chạy code cũ.
→ Reload/restart long-running services.
Lỗi 5
Không có backup database.
→ Khi database hỏng, mất dữ liệu.
Lỗi 6
Upload file nhưng không:
php artisan storage:link
→ Image không truy cập được.
Lỗi 7
Dùng:
chmod -R 777
→ Cấp quyền quá rộng.
Lỗi 8
Query:
Model::all();
trên bảng cực lớn.
→ Có thể gây tốn RAM và chậm.
70. Production Security Checklist
[ ] APP_DEBUG=false
[ ] APP_ENV=production
[ ] HTTPS
[ ] .env không commit Git
[ ] APP_KEY được bảo vệ
[ ] Database password được bảo vệ
[ ] Không expose project root
[ ] Nginx root → public/
[ ] Validation server-side
[ ] Authorization
[ ] CSRF
[ ] Password hashing
[ ] File upload validation
[ ] Rate limiting
[ ] Security headers phù hợp
[ ] Logs
[ ] Database backup
[ ] Uploaded files backup
[ ] Queue Worker monitoring
71. Production Performance Checklist
[ ] Composer optimized autoload
[ ] Config cache
[ ] Event cache
[ ] Route cache
[ ] View cache
[ ] Database indexes
[ ] Pagination
[ ] Eager loading
[ ] Query optimization
[ ] Cache dữ liệu phù hợp
[ ] Vite production build
[ ] Queue cho tác vụ nặng
[ ] Scheduler cho tác vụ định kỳ
72. Bài tập thực hành
Bài tập 1 — Production Environment
Đổi:
APP_ENV=production
APP_DEBUG=false
Sau đó kiểm tra:
App::environment();
Bài tập 2 — Optimize
Chạy:
php artisan optimize
Sau đó kiểm tra website.
Bài tập 3 — Clear Cache
Chạy:
php artisan optimize:clear
Sau đó:
php artisan optimize
Quan sát sự khác nhau.
Bài tập 4 — Route Cache
Chạy:
php artisan route:cache
Sau đó:
php artisan route:list
Bài tập 5 — View Cache
Chạy:
php artisan view:cache
Kiểm tra Blog CMS.
Bài tập 6 — Cache Category
Viết:
Cache::remember(...)
để cache danh sách category.
Sau đó khi category thay đổi:
Cache::forget(...)
Bài tập 7 — Health Check
Mở:
/up
và kiểm tra HTTP status.
Bài tập 8 — Security
Kiểm tra production:
APP_DEBUG=false
và thử truy cập:
/.env
Kết quả phải là:
Không được phép truy cập
73. Tổng kết
Sau bài này, chúng ta đã hoàn thành phần quan trọng nhất của deployment Laravel 13.
Các nguyên tắc cần nhớ:
ENV
↓
Configuration
↓
Cache
↓
Optimization
↓
Security
↓
Monitoring
Production không đơn giản chỉ là:
Upload source code
Mà là:
Application
+
Web Server
+
PHP-FPM
+
Database
+
Cache
+
Queue
+
Scheduler
+
Security
+
Monitoring
+
Backup
📌 74. Những command cần nhớ
Optimize
php artisan optimize
Clear optimization cache
php artisan optimize:clear
Configuration
php artisan config:cache
Routes
php artisan route:cache
Views
php artisan view:cache
Events
php artisan event:cache
Storage
php artisan storage:link
Migration production
php artisan migrate --force
Reload long-running services
php artisan reload
Laravel 13 documentation xác nhận reload được dùng để terminate các long-running services như queue workers, Reverb hoặc Octane sau deployment để process monitor có thể khởi động lại chúng với code mới.
🎯 75. Tư duy Production
Một developer Laravel không chỉ cần biết:
Controller
Model
Migration
Blade
Route
mà khi đưa application ra Internet còn phải hiểu:
Code
↓
Security
↓
Performance
↓
Deployment
↓
Monitoring
↓
Backup
Đó chính là sự khác biệt giữa:
"Làm được một Laravel project"
và:
"Biết triển khai một Laravel application"
🏁 KẾT THÚC PHẦN TRIỂN KHAI
Sau:
Bài 45 — Deploy Shared Hosting
Bài 46 — Deploy VPS
Bài 47 — Nginx
Bài 48 — Queue Worker & Scheduler
Bài 49 — Production Tips
chúng ta đã hoàn thành toàn bộ phần:
TRIỂN KHAI LARAVEL 13
Kiến trúc cuối cùng:
INTERNET
│
HTTPS
│
▼
NGINX
│
▼
PHP-FPM
│
▼
┌─────────────┐
│ Laravel 13 │
└──────┬──────┘
│
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
MySQL Cache Storage
│
│
▼
Database
Laravel
│
▼
Queue
│
▼
Worker
│
▼
Supervisor
Cron
│
▼
Laravel Scheduler
Và chỉ còn một bài cuối cùng:
🎓 BÀI 50 — TỔNG KẾT DỰ ÁN BLOG CMS
Chúng ta sẽ tổng hợp toàn bộ những gì đã học:
PHP
↓
Laravel 13
↓
MVC
↓
Database
↓
Eloquent
↓
Relationship
↓
Authentication
↓
Authorization
↓
CRUD
↓
Upload
↓
Search
↓
Pagination
↓
Soft Delete
↓
Events
↓
Queue
↓
Mail
↓
Notification
↓
Cache
↓
Storage
↓
Logging
↓
REST API
↓
Sanctum
↓
Nginx
↓
VPS
↓
Production
và ráp lại thành Blog CMS hoàn chỉnh.
x1




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