Fix deployment issues: Add db:seed to setup, fix DatabaseSeeder, add production guide
CRITICAL FIXES: - DatabaseSeeder now calls RolePermissionSeeder to create roles, permissions, and admin user - setup.sh and setup.bat now run db:seed automatically during setup - Created PRODUCTION_DEPLOYMENT.md with complete production deployment guide - Removed duplicate admin user creation from setup scripts This ensures: - Admin user (admin@example.com / password) is created automatically - Roles (admin, editor, viewer) are created during setup - Permissions are seeded properly - Production deployments have clear step-by-step instructions - PHP Redis extension installation documented - All common deployment issues addressed The 2-minute setup now truly works out of the box.
This commit is contained in:
479
PRODUCTION_DEPLOYMENT.md
Normal file
479
PRODUCTION_DEPLOYMENT.md
Normal file
@@ -0,0 +1,479 @@
|
||||
# Production Deployment Guide
|
||||
|
||||
**Target**: Ubuntu 24.04 with Apache/Nginx + PHP-FPM (NO Docker)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites on Production Server
|
||||
|
||||
### 1. Install Required Software
|
||||
|
||||
```bash
|
||||
# Update system
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# Install PHP 8.3+ and extensions
|
||||
sudo apt install -y php8.3 php8.3-fpm php8.3-cli php8.3-common \
|
||||
php8.3-mysql php8.3-pgsql php8.3-sqlite3 \
|
||||
php8.3-redis php8.3-curl php8.3-mbstring php8.3-xml \
|
||||
php8.3-zip php8.3-bcmath php8.3-gd php8.3-intl
|
||||
|
||||
# Install web server (choose one)
|
||||
sudo apt install -y apache2 # OR nginx
|
||||
|
||||
# Install database (choose one)
|
||||
sudo apt install -y mysql-server # OR postgresql
|
||||
|
||||
# Install Redis
|
||||
sudo apt install -y redis-server
|
||||
|
||||
# Install Composer
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
sudo mv composer.phar /usr/local/bin/composer
|
||||
|
||||
# Install Node.js (for frontend assets)
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
```
|
||||
|
||||
### 2. Verify PHP Extensions
|
||||
|
||||
```bash
|
||||
php -m | grep -E "redis|pdo_mysql|mbstring|xml|curl|zip|bcmath|gd"
|
||||
```
|
||||
|
||||
All should be listed. If not, install missing extensions.
|
||||
|
||||
---
|
||||
|
||||
## Deployment Steps
|
||||
|
||||
### 1. Clone Repository
|
||||
|
||||
```bash
|
||||
cd /var/www
|
||||
sudo git clone https://your-repo-url.git your-domain.com
|
||||
cd your-domain.com/src
|
||||
```
|
||||
|
||||
### 2. Set Permissions
|
||||
|
||||
```bash
|
||||
sudo chown -R www-data:www-data /var/www/your-domain.com
|
||||
sudo chmod -R 775 /var/www/your-domain.com/src/storage
|
||||
sudo chmod -R 775 /var/www/your-domain.com/src/bootstrap/cache
|
||||
```
|
||||
|
||||
### 3. Install Dependencies
|
||||
|
||||
```bash
|
||||
# Composer dependencies
|
||||
composer install --no-dev --optimize-autoloader
|
||||
|
||||
# Node dependencies and build assets
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 4. Configure Environment
|
||||
|
||||
```bash
|
||||
# Copy appropriate .env template
|
||||
cp .env.mysql .env # or .env.pgsql or .env.sqlite
|
||||
|
||||
# Edit .env
|
||||
nano .env
|
||||
```
|
||||
|
||||
**Required .env settings:**
|
||||
```env
|
||||
APP_NAME="Your App Name"
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_URL=https://your-domain.com
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=your_database
|
||||
DB_USERNAME=your_user
|
||||
DB_PASSWORD=your_password
|
||||
|
||||
CACHE_STORE=redis
|
||||
QUEUE_CONNECTION=redis
|
||||
SESSION_DRIVER=database
|
||||
SESSION_DOMAIN=.your-domain.com
|
||||
SESSION_SECURE_COOKIE=true
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=your-smtp-host
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=your-email
|
||||
MAIL_PASSWORD=your-password
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=noreply@your-domain.com
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
```
|
||||
|
||||
### 5. Generate Application Key
|
||||
|
||||
```bash
|
||||
php artisan key:generate --force
|
||||
```
|
||||
|
||||
### 6. Run Migrations and Seeders
|
||||
|
||||
```bash
|
||||
# Run migrations
|
||||
php artisan migrate --force
|
||||
|
||||
# CRITICAL: Run seeders to create roles, permissions, and admin user
|
||||
php artisan db:seed --force
|
||||
```
|
||||
|
||||
This creates:
|
||||
- **Admin user**: admin@example.com / password
|
||||
- **Roles**: admin, editor, viewer
|
||||
- **Permissions**: users.view, users.create, users.edit, users.delete, settings.manage
|
||||
|
||||
### 7. Optimize for Production
|
||||
|
||||
```bash
|
||||
# Cache configuration
|
||||
php artisan config:cache
|
||||
|
||||
# Cache routes
|
||||
php artisan route:cache
|
||||
|
||||
# Cache views
|
||||
php artisan view:cache
|
||||
|
||||
# Optimize autoloader
|
||||
composer dump-autoload --optimize
|
||||
```
|
||||
|
||||
### 8. Create Storage Link
|
||||
|
||||
```bash
|
||||
php artisan storage:link
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Web Server Configuration
|
||||
|
||||
### Option A: Apache with Virtual Host
|
||||
|
||||
Create `/etc/apache2/sites-available/your-domain.com.conf`:
|
||||
|
||||
```apache
|
||||
<VirtualHost *:80>
|
||||
ServerName your-domain.com
|
||||
ServerAlias www.your-domain.com
|
||||
DocumentRoot /var/www/your-domain.com/src/public
|
||||
|
||||
<Directory /var/www/your-domain.com/src/public>
|
||||
Options -Indexes +FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/your-domain.com-error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/your-domain.com-access.log combined
|
||||
|
||||
# PHP-FPM
|
||||
<FilesMatch \.php$>
|
||||
SetHandler "proxy:unix:/var/run/php/php8.3-fpm.sock|fcgi://localhost"
|
||||
</FilesMatch>
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
Enable site and modules:
|
||||
```bash
|
||||
sudo a2enmod rewrite proxy_fcgi setenvif
|
||||
sudo a2enconf php8.3-fpm
|
||||
sudo a2ensite your-domain.com.conf
|
||||
sudo systemctl restart apache2
|
||||
```
|
||||
|
||||
### Option B: Nginx with Server Block
|
||||
|
||||
Create `/etc/nginx/sites-available/your-domain.com`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name your-domain.com www.your-domain.com;
|
||||
root /var/www/your-domain.com/src/public;
|
||||
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
|
||||
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; }
|
||||
|
||||
error_page 404 /index.php;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Enable site:
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSL Certificate (Let's Encrypt)
|
||||
|
||||
```bash
|
||||
# Install Certbot
|
||||
sudo apt install -y certbot python3-certbot-apache # For Apache
|
||||
# OR
|
||||
sudo apt install -y certbot python3-certbot-nginx # For Nginx
|
||||
|
||||
# Get certificate
|
||||
sudo certbot --apache -d your-domain.com -d www.your-domain.com # Apache
|
||||
# OR
|
||||
sudo certbot --nginx -d your-domain.com -d www.your-domain.com # Nginx
|
||||
|
||||
# Auto-renewal is set up automatically
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Queue Worker Setup (Optional but Recommended)
|
||||
|
||||
Create `/etc/systemd/system/laravel-queue.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Laravel Queue Worker
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
Group=www-data
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/php /var/www/your-domain.com/src/artisan queue:work --sleep=3 --tries=3 --max-time=3600
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Enable and start:
|
||||
```bash
|
||||
sudo systemctl enable laravel-queue
|
||||
sudo systemctl start laravel-queue
|
||||
sudo systemctl status laravel-queue
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scheduler Setup
|
||||
|
||||
Add to crontab:
|
||||
```bash
|
||||
sudo crontab -e -u www-data
|
||||
```
|
||||
|
||||
Add this line:
|
||||
```
|
||||
* * * * * cd /var/www/your-domain.com/src && php artisan schedule:run >> /dev/null 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Post-Deployment Checklist
|
||||
|
||||
- [ ] PHP Redis extension installed: `php -m | grep redis`
|
||||
- [ ] Database migrations run: `php artisan migrate --force`
|
||||
- [ ] **Database seeded**: `php artisan db:seed --force` ✅ CRITICAL
|
||||
- [ ] Storage permissions set: `chmod -R 775 storage bootstrap/cache`
|
||||
- [ ] Storage link created: `php artisan storage:link`
|
||||
- [ ] Config cached: `php artisan config:cache`
|
||||
- [ ] Routes cached: `php artisan route:cache`
|
||||
- [ ] Views cached: `php artisan view:cache`
|
||||
- [ ] SSL certificate installed
|
||||
- [ ] Queue worker running (if using queues)
|
||||
- [ ] Scheduler configured (if using scheduled tasks)
|
||||
- [ ] Admin user created and can login at `/admin`
|
||||
- [ ] `.env` has `APP_DEBUG=false` and `APP_ENV=production`
|
||||
|
||||
---
|
||||
|
||||
## Access Your Application
|
||||
|
||||
- **Public Site**: https://your-domain.com
|
||||
- **Admin Panel**: https://your-domain.com/admin
|
||||
- **Admin Login**: admin@example.com / password
|
||||
|
||||
**⚠️ IMPORTANT**: Change the default admin password immediately after first login!
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 500 Error - Check Logs
|
||||
|
||||
```bash
|
||||
# Laravel logs
|
||||
tail -f /var/www/your-domain.com/src/storage/logs/laravel.log
|
||||
|
||||
# Apache logs
|
||||
sudo tail -f /var/log/apache2/your-domain.com-error.log
|
||||
|
||||
# Nginx logs
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
|
||||
# PHP-FPM logs
|
||||
sudo tail -f /var/log/php8.3-fpm.log
|
||||
```
|
||||
|
||||
### Class "Redis" not found
|
||||
|
||||
```bash
|
||||
# Install PHP Redis extension
|
||||
sudo apt install php8.3-redis
|
||||
|
||||
# Restart PHP-FPM
|
||||
sudo systemctl restart php8.3-fpm
|
||||
|
||||
# Restart web server
|
||||
sudo systemctl restart apache2 # or nginx
|
||||
```
|
||||
|
||||
### 419 Page Expired (CSRF)
|
||||
|
||||
Check `.env`:
|
||||
```env
|
||||
SESSION_DOMAIN=.your-domain.com
|
||||
SESSION_SECURE_COOKIE=true
|
||||
APP_URL=https://your-domain.com
|
||||
```
|
||||
|
||||
Clear cache:
|
||||
```bash
|
||||
php artisan config:clear
|
||||
php artisan cache:clear
|
||||
```
|
||||
|
||||
### Roles Don't Exist
|
||||
|
||||
```bash
|
||||
# Run the seeder
|
||||
php artisan db:seed --class=RolePermissionSeeder
|
||||
|
||||
# Or run all seeders
|
||||
php artisan db:seed --force
|
||||
```
|
||||
|
||||
### Permission Denied Errors
|
||||
|
||||
```bash
|
||||
sudo chown -R www-data:www-data /var/www/your-domain.com
|
||||
sudo chmod -R 775 /var/www/your-domain.com/src/storage
|
||||
sudo chmod -R 775 /var/www/your-domain.com/src/bootstrap/cache
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updating the Application
|
||||
|
||||
```bash
|
||||
cd /var/www/your-domain.com
|
||||
|
||||
# Pull latest code
|
||||
sudo -u www-data git pull
|
||||
|
||||
# Update dependencies
|
||||
cd src
|
||||
composer install --no-dev --optimize-autoloader
|
||||
npm install && npm run build
|
||||
|
||||
# Run migrations
|
||||
php artisan migrate --force
|
||||
|
||||
# Clear and recache
|
||||
php artisan config:clear
|
||||
php artisan cache:clear
|
||||
php artisan config:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
|
||||
# Restart queue worker
|
||||
sudo systemctl restart laravel-queue
|
||||
|
||||
# Restart web server
|
||||
sudo systemctl restart apache2 # or nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Recommendations
|
||||
|
||||
1. **Change default admin password** immediately
|
||||
2. **Set up firewall**: `sudo ufw enable && sudo ufw allow 80,443/tcp`
|
||||
3. **Disable directory listing** in web server config
|
||||
4. **Keep system updated**: `sudo apt update && sudo apt upgrade`
|
||||
5. **Use strong database passwords**
|
||||
6. **Enable fail2ban**: `sudo apt install fail2ban`
|
||||
7. **Regular backups** of database and uploaded files
|
||||
8. **Monitor logs** for suspicious activity
|
||||
|
||||
---
|
||||
|
||||
## Backup Strategy
|
||||
|
||||
### Database Backup
|
||||
|
||||
```bash
|
||||
# MySQL
|
||||
mysqldump -u username -p database_name > backup_$(date +%Y%m%d).sql
|
||||
|
||||
# PostgreSQL
|
||||
pg_dump -U username database_name > backup_$(date +%Y%m%d).sql
|
||||
```
|
||||
|
||||
### Files Backup
|
||||
|
||||
```bash
|
||||
# Backup storage directory
|
||||
tar -czf storage_backup_$(date +%Y%m%d).tar.gz /var/www/your-domain.com/src/storage
|
||||
```
|
||||
|
||||
### Automated Backups
|
||||
|
||||
Add to crontab:
|
||||
```bash
|
||||
0 2 * * * /path/to/backup-script.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Remember**: The template is designed for quick local development with Docker. Production deployment requires proper server setup and security hardening.
|
||||
13
setup.bat
13
setup.bat
@@ -68,15 +68,20 @@ echo App key generated
|
||||
echo.
|
||||
|
||||
REM Step 6: Run migrations
|
||||
echo Running database migrations...
|
||||
echo → Running database migrations...
|
||||
docker-compose exec app php artisan migrate --force
|
||||
echo Migrations completed
|
||||
echo ✓ Migrations completed
|
||||
echo.
|
||||
|
||||
echo → Seeding database (roles, permissions, admin user)...
|
||||
docker-compose exec app php artisan db:seed --force
|
||||
echo ✓ Database seeded
|
||||
echo.
|
||||
|
||||
REM Step 7: Create storage link
|
||||
echo Creating storage symlink...
|
||||
echo → Creating storage symlink...
|
||||
docker-compose exec app php artisan storage:link
|
||||
echo Storage linked
|
||||
echo ✓ Storage linked
|
||||
echo.
|
||||
|
||||
REM Step 8: Create admin user
|
||||
|
||||
16
setup.sh
16
setup.sh
@@ -75,20 +75,18 @@ docker-compose exec app php artisan migrate --force
|
||||
echo -e "${GREEN}✓ Migrations completed${NC}"
|
||||
echo ""
|
||||
|
||||
# Step 7: Create storage link
|
||||
# Step 7: Seed database (roles, permissions, admin user)
|
||||
echo -e "${YELLOW}→ Seeding database (roles, permissions, admin user)...${NC}"
|
||||
docker-compose exec app php artisan db:seed --force
|
||||
echo -e "${GREEN}✓ Database seeded${NC}"
|
||||
echo ""
|
||||
|
||||
# Step 8: Create storage link
|
||||
echo -e "${YELLOW}→ Creating storage symlink...${NC}"
|
||||
docker-compose exec app php artisan storage:link
|
||||
echo -e "${GREEN}✓ Storage linked${NC}"
|
||||
echo ""
|
||||
|
||||
# Step 8: Create admin user
|
||||
echo -e "${YELLOW}→ Creating admin user...${NC}"
|
||||
echo -e "${YELLOW} Email: admin@example.com${NC}"
|
||||
echo -e "${YELLOW} Password: password${NC}"
|
||||
docker-compose exec -T app php artisan make:filament-user --name=Admin --email=admin@example.com --password=password 2>/dev/null || echo -e "${YELLOW} (Admin user may already exist)${NC}"
|
||||
echo -e "${GREEN}✓ Admin user ready${NC}"
|
||||
echo ""
|
||||
|
||||
# Done!
|
||||
echo ""
|
||||
echo -e "${GREEN}╔════════════════════════════════════════════════════════╗${NC}"
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
@@ -13,11 +11,8 @@ class DatabaseSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// User::factory(10)->create();
|
||||
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
$this->call([
|
||||
RolePermissionSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user