
Build code lên ec2
# Deploy Laravel 13 + Filament v4 lên AWS EC2 (Ubuntu 24.04)
## Yêu cầu
- EC2 instance Ubuntu 22.04/24.04
- SSH key .pem
- Domain trỏ về IP EC2
- PHP 8.3, PostgreSQL 16, Nginx
---
## 1. Kết nối EC2
```bash
chmod 400 ~/aws-vps-key.pem
ssh -i ~/aws-vps-key.pem ubuntu@YOUR_EC2_IP
```
---
## 2. Cài đặt dependencies
```bash
sudo apt update && sudo apt upgrade -y
# Nginx
sudo apt install -y nginx
# PHP 8.3
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
sudo apt install -y php8.3 php8.3-fpm php8.3-cli php8.3-common \
php8.3-pgsql php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip \
php8.3-bcmath php8.3-intl php8.3-tokenizer php8.3-gd
# PostgreSQL 16
sudo apt install -y postgresql postgresql-contrib
# Composer & Git
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo apt install -y git unzip
```
---
## 3. Cấu hình PostgreSQL
```bash
sudo -u postgres psql
```
```sql
CREATE USER blog_user WITH PASSWORD 'your_strong_password';
CREATE DATABASE blog_cms OWNER blog_user;
GRANT ALL PRIVILEGES ON DATABASE blog_cms TO blog_user;
\q
```
---
## 4. Deploy code
```bash
sudo mkdir -p /var/www/blog-cms
sudo chown ubuntu:ubuntu /var/www/blog-cms
cd /var/www/blog-cms
git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git .
```
Hoặc rsync từ máy local:
```bash
rsync -avz --exclude='.env' --exclude='vendor' \
-e "ssh -i ~/aws-vps-key.pem" \
/path/to/local/project/ \
ubuntu@YOUR_EC2_IP:/var/www/blog-cms/
```
---
## 5. Cấu hình Laravel
```bash
cd /var/www/blog-cms
composer install --no-dev --optimize-autoloader
cp .env.example .env
nano .env
```
Các giá trị cần thay:
```env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=blog_cms
DB_USERNAME=blog_user
DB_PASSWORD=your_strong_password
FILESYSTEM_DISK=public
```
```bash
php artisan key:generate
php artisan storage:link
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
```
---
## 6. Permissions (quan trọng)
Cấu trúc ownership chuẩn — không chown toàn bộ về www-data để tránh conflict với git:
```bash
# Toàn bộ code: ubuntu sở hữu (git pull, composer, artisan hoạt động)
sudo chown -R ubuntu:ubuntu /var/www/blog-cms
# Chỉ 2 thư mục PHP cần ghi: www-data
sudo chown -R www-data:www-data /var/www/blog-cms/storage
sudo chown -R www-data:www-data /var/www/blog-cms/bootstrap/cache
sudo chmod -R 775 /var/www/blog-cms/storage
sudo chmod -R 775 /var/www/blog-cms/bootstrap/cache
# Livewire file upload
sudo mkdir -p /var/www/blog-cms/storage/app/livewire-tmp
sudo chown -R www-data:www-data /var/www/blog-cms/storage/app
```
---
## 7. Nginx config
```bash
sudo nano /etc/nginx/sites-available/blog-cms
```
```nginx
server {
listen 80;
server_name your-domain.com;
root /var/www/blog-cms/public;
index index.php;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
client_max_body_size 128M;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
```
```bash
sudo ln -s /etc/nginx/sites-available/blog-cms /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl restart nginx
sudo systemctl enable nginx php8.3-fpm
```
---
## 8. PHP-FPM upload limits
```bash
sudo nano /etc/php/8.3/fpm/php.ini
```
```ini
upload_max_filesize = 64M
post_max_size = 128M
```
```bash
sudo systemctl restart php8.3-fpm
```
---
## 9. SSL với Certbot
```bash
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
```
Certbot hỏi lần lượt: email → agree terms → chọn Redirect (2). Tự động cập nhật Nginx sang HTTPS.
```bash
# Cập nhật APP_URL
nano .env # APP_URL=https://your-domain.com
php artisan config:cache
```
---
## 10. Tạo admin user
```bash
php artisan tinker --execute="
App\Models\User::create([
'name' => 'Admin',
'email' => 'admin@yourdomain.com',
'password' => bcrypt('your_password'),
'role' => 'admin',
]);
echo 'Done.';
"
```
---
## 11. Publish Filament assets
```bash
php artisan filament:assets
```
---
## Các lỗi thường gặp
### git pull bị Permission denied
```bash
# Nguyên nhân: chown www-data làm mất quyền git
sudo chown -R ubuntu:ubuntu /var/www/blog-cms/.git
git pull
# Sau đó trả lại permissions đúng (mục 6)
```
### storage/logs/laravel.log Permission denied
```bash
sudo chown -R www-data:www-data /var/www/blog-cms/storage
sudo chmod -R 775 /var/www/blog-cms/storage
```
### Livewire upload thất bại
```bash
sudo mkdir -p /var/www/blog-cms/storage/app/livewire-tmp
sudo chown -R www-data:www-data /var/www/blog-cms/storage/app
sudo chmod -R 775 /var/www/blog-cms/storage/app
```
### tempnam(): file created in system's temporary directory
```bash
# storage/app không ghi được → PHP fallback sang /tmp
sudo chown -R www-data:www-data /var/www/blog-cms/storage
php artisan storage:link
```
### Migrations lỗi relation "posts" does not exist
Pivot table post_category) có timestamp trùng với posts và chạy trước do alphabetical sort. Fix: đổi timestamp của pivot table thành số lớn hơn.
```
# Sai: 2026_05_17_064952_create_post_category_table.php
# Đúng: 2026_05_17_064954_create_post_category_table.php (sau posts)
```
### Login page không có nút Submit
CSS quá broad ẩn mất form actions. Kiểm tra AdminPanelProvider.php:
```css
/* Sai — ẩn cả nút login */
.fi-sc-actions .fi-ac { display: none !important; }
/* Đúng — chỉ ẩn trong admin panel */
.fi-main .fi-sc-actions .fi-ac { display: none !important; }
```