The previous 5-second fixed wait was insufficient for MySQL 8.0 to fully initialize, causing migrations and seeders to fail with 'Connection refused'. Changes: - Replace 'sleep 5' with active connection polling - Try to connect every second for up to 30 seconds - Use PHP PDO to test actual database connectivity - Only proceed when database accepts connections - Show clear status when database is ready This ensures migrations and seeders run only after database is fully ready, preventing 'Connection refused' errors on fresh setup. Fixes the issue where Laravel loads but shows MySQL connection error.
Laravel Docker Development Template
A comprehensive Laravel development environment with Docker for local development and deployment configurations for Ubuntu 24.04 with Nginx Proxy Manager or Apache.
New here? Start with GETTING_STARTED.md for a step-by-step setup guide.
AI Assistant? See AI_CONTEXT.md for project context and conventions.
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ DEVELOPMENT (Docker) │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌───────────────┐ ┌─────┐ ┌─────┐ │
│ │ Nginx │──│ PHP │──│ MySQL/PgSQL/ │ │Redis│ │Mail │ │
│ │ :8080 │ │ FPM │ │ SQLite │ │:6379│ │:8025│ │
│ └─────────┘ └─────────┘ └───────────────┘ └─────┘ └─────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ PRODUCTION (Ubuntu 24.04 - No Docker) │
├─────────────────────────────────────────────────────────────────┤
│ Option A: Nginx Proxy Manager │
│ ┌───────────────┐ ┌─────────┐ ┌─────────┐ │
│ │ NPM (SSL/443) │───▶│ Nginx │───▶│ PHP-FPM │───▶ Laravel │
│ └───────────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Option B: Apache Virtual Host │
│ ┌─────────────────┐ ┌─────────┐ │
│ │ Apache + SSL │───▶│ PHP-FPM │───▶ Laravel │
│ │ (Certbot) │ └─────────┘ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Project Structure
├── docker/
│ ├── nginx/default.conf # Dev Nginx config
│ ├── php/
│ │ ├── Dockerfile # PHP-FPM image
│ │ └── local.ini # PHP dev settings
│ └── mysql/my.cnf # MySQL config
├── deploy/
│ ├── nginx/
│ │ ├── laravel-site.conf # Production Nginx config
│ │ └── nginx-proxy-manager-notes.md
│ ├── apache/
│ │ ├── laravel-site.conf # Apache virtual host
│ │ └── apache-setup.md
│ ├── production/
│ │ ├── .env.mysql.production # MySQL env template
│ │ ├── .env.pgsql.production # PostgreSQL env template
│ │ └── .env.sqlite.production # SQLite env template
│ └── scripts/
│ ├── server-setup.sh # Ubuntu server setup (DB selection)
│ ├── deploy.sh # Deployment script
│ ├── fix-permissions.sh # Permission fixer
│ ├── supervisor-worker.conf # Queue worker config
│ ├── supervisor-scheduler.conf # Scheduler config
│ └── laravel-scheduler.cron # Cron job template
├── src/
│ ├── .env.mysql # MySQL dev config
│ ├── .env.pgsql # PostgreSQL dev config
│ ├── .env.sqlite # SQLite dev config
│ └── pint.json # Code style config
├── scripts/
│ ├── post-install.sh # Flare/Telescope/Pint setup
│ └── laravel-setup.sh # Auth/API/Middleware setup
├── docs/
│ ├── error-logging.md # Error logging docs
│ ├── laravel-setup.md # Laravel setup guide
│ ├── filament-admin.md # Admin panel docs
│ ├── modules.md # Modular architecture guide
│ ├── audit-trail.md # Audit trail docs
│ ├── site-settings.md # Appearance settings
│ ├── testing.md # Pest testing guide
│ ├── queues.md # Background jobs
│ ├── ci-cd.md # GitHub Actions pipeline
│ └── backup.md # Database backup/restore
├── docker-compose.yml # Multi-DB profiles
├── Makefile
├── README.md
├── GETTING_STARTED.md # Step-by-step setup guide
└── AI_CONTEXT.md # Context for AI assistants
Database Options
This template supports three database engines via Docker Compose profiles:
| Database | Profile | Port | Use Case |
|---|---|---|---|
| MySQL 8.0 | mysql |
3306 | Production-grade, most Laravel tutorials |
| PostgreSQL 16 | pgsql |
5432 | Advanced features, JSON, full-text search |
| SQLite | sqlite |
- | Lightweight, no server, great for testing |
Quick Start (Development)
Prerequisites
- Docker & Docker Compose
One-Command Setup
# Clone the repository
git clone <repo-url> my-laravel-app
cd my-laravel-app
# Run setup script (MySQL is default)
./setup.sh # Linux/Mac
setup.bat # Windows
# Or specify database:
./setup.sh mysql # MySQL (default)
./setup.sh pgsql # PostgreSQL
./setup.sh sqlite # SQLite
That's it! The script will:
- ✅ Configure environment for your database
- ✅ Install composer dependencies
- ✅ Build and start Docker containers
- ✅ Run migrations
- ✅ Create admin user (admin@example.com / password)
Everything is pre-installed:
- ✅ Laravel 11 with Breeze authentication
- ✅ Filament admin panel with user management
- ✅ Pest testing framework
- ✅ Laravel Pint code style
- ✅ Queue workers & scheduler (optional)
Access your app:
- Laravel App: http://localhost:8080
- Admin Panel: http://localhost:8080/admin
- Mailpit: http://localhost:8025
Admin Login:
- Email: admin@example.com
- Password: password
Manual Setup (Alternative)
If you prefer manual control:
-
Clone and configure
git clone <repo-url> my-laravel-app cd my-laravel-app -
Build containers
docker-compose build -
Install Laravel
docker-compose --profile mysql run --rm app composer create-project laravel/laravel:^11.0 /tmp/new docker-compose --profile mysql run --rm app sh -c "cp -r /tmp/new/. /var/www/html/ && rm -rf /tmp/new" -
Configure environment
cp src/.env.mysql src/.env # For MySQL # OR cp src/.env.pgsql src/.env # For PostgreSQL # OR cp src/.env.sqlite src/.env # For SQLite -
Start containers
docker-compose --profile mysql up -d -
Run migrations
docker-compose exec app php artisan migrate --force -
Run setup scripts (optional)
docker-compose exec app bash scripts/laravel-setup.sh
Common Commands
| Command | Description |
|---|---|
make up DB=mysql |
Start with MySQL |
make up DB=pgsql |
Start with PostgreSQL |
make up DB=sqlite |
Start with SQLite |
make down |
Stop all containers |
make shell |
Shell into app container |
make artisan cmd='migrate' |
Run Artisan commands |
make composer cmd='require package' |
Run Composer |
make logs |
View logs |
make fresh |
Fresh migrate + seed |
make lint |
Fix code style (Pint) |
make lint-check |
Check code style |
make test |
Run tests |
make setup-tools |
Install Flare, Pint, error pages |
make setup-laravel |
Configure auth, API, middleware |
make setup-all |
Run both setup scripts |
Laravel Setup (Auth, API, Middleware)
After installing Laravel, run the interactive setup:
make setup-laravel
This configures:
| Feature | Options |
|---|---|
| Authentication | Breeze (Blade/Livewire/API) or Jetstream + Livewire |
| Admin Panel | Filament with user management |
| Site Settings | Logo, favicon, color scheme management |
| Modules | Modular architecture with make:module command |
| Audit Trail | Track all data changes with user, old/new values |
| Testing | Pest framework with module test generation |
| Queues | Redis-powered background jobs |
| CI/CD | GitHub Actions for tests + deploy |
| Backup | Database backup/restore scripts |
| API | Sanctum token authentication |
| Middleware | ForceHttps, SecurityHeaders |
| Storage | Public storage symlink |
Note: This template focuses on Blade and Livewire (no Vue/React/Inertia). Server-side rendering keeps debugging simple.
Admin Panel (Filament)
The setup includes optional Filament admin panel:
- User management - List, create, edit, delete users
- Dashboard - Stats widgets, charts
- Extensible - Add resources for any model
Access at: http://localhost:8080/admin
See docs/filament-admin.md for customization.
Site Settings (Appearance)
Manage logo, favicon, and colors from admin panel:
/admin → Settings → Appearance
Use in Blade templates:
{{-- In your <head> --}}
<x-site-head :title="$title" />
{{-- Logo --}}
<img src="{{ site_logo() }}" alt="{{ site_name() }}">
{{-- Colors available as CSS variables --}}
<div class="bg-primary">Uses --primary-color</div>
See docs/site-settings.md for configuration.
Modular Architecture
Build features as self-contained modules:
# Create a module with model and admin panel
php artisan make:module StockManagement --model=Product
# Creates:
# - app/Modules/StockManagement/
# - Routes, controllers, views
# - Filament admin resources
# - Permissions for role-based access
Each module gets:
- Landing page at
/{module-slug} - Admin section in Filament panel
- Permissions auto-registered with roles
See docs/modules.md for full documentation.
Audit Trail
Every module includes an Audit Log page showing all data changes:
- Who changed what
- Old → New values
- When and from which IP
- Filterable by user, event type, date
Configure per module in Config/module_name.php:
'audit' => [
'enabled' => true,
'strategy' => 'all', // 'all', 'include', 'exclude', 'none'
],
See docs/audit-trail.md for configuration options.
See docs/laravel-setup.md for detailed configuration.
Production Deployment
Ubuntu 24.04 Server Setup
-
Run server setup script
sudo bash deploy/scripts/server-setup.shThis installs:
- PHP 8.3 + extensions (MySQL, PostgreSQL, SQLite drivers)
- Composer
- Node.js 20
- Database server (MySQL, PostgreSQL, or SQLite - your choice)
- Redis
- Nginx or Apache (your choice)
-
Create database (based on your selection during setup)
MySQL:
sudo mysql_secure_installation sudo mysql CREATE DATABASE your_app; CREATE USER 'your_user'@'localhost' IDENTIFIED BY 'secure_password'; GRANT ALL PRIVILEGES ON your_app.* TO 'your_user'@'localhost'; FLUSH PRIVILEGES; EXIT;PostgreSQL:
sudo -u postgres psql CREATE DATABASE your_app; CREATE USER your_user WITH ENCRYPTED PASSWORD 'secure_password'; GRANT ALL PRIVILEGES ON DATABASE your_app TO your_user; \qSQLite:
touch /var/www/your-app/database/database.sqlite chmod 664 /var/www/your-app/database/database.sqlite chown www-data:www-data /var/www/your-app/database/database.sqlite
Option A: Nginx + Nginx Proxy Manager
-
Deploy your app
cd /var/www git clone <repo-url> your-app cd your-app/src composer install --no-dev --optimize-autoloader # Copy the appropriate .env file for your database: cp ../deploy/production/.env.mysql.production .env # For MySQL cp ../deploy/production/.env.pgsql.production .env # For PostgreSQL cp ../deploy/production/.env.sqlite.production .env # For SQLite # Edit .env with your settings php artisan key:generate php artisan migrate npm ci && npm run build -
Configure Nginx
sudo cp deploy/nginx/laravel-site.conf /etc/nginx/sites-available/your-app # Edit: server_name, root, log paths sudo ln -s /etc/nginx/sites-available/your-app /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx -
Configure NPM
- See
deploy/nginx/nginx-proxy-manager-notes.mdfor NPM setup
- See
-
Fix permissions
sudo bash deploy/scripts/fix-permissions.sh /var/www/your-app/src
Option B: Apache Virtual Host
-
Deploy your app (same as above)
-
Configure Apache
sudo cp deploy/apache/laravel-site.conf /etc/apache2/sites-available/your-app.conf # Edit: ServerName, DocumentRoot, paths sudo a2ensite your-app.conf sudo apache2ctl configtest sudo systemctl reload apache2 -
SSL with Certbot
sudo certbot --apache -d your-domain.com
See deploy/apache/apache-setup.md for detailed instructions.
Automated Deployments
Use the deployment script for updates:
sudo bash deploy/scripts/deploy.sh /var/www/your-app/src main
Queue Workers (Optional)
If using queues:
sudo cp deploy/scripts/supervisor-worker.conf /etc/supervisor/conf.d/laravel-worker.conf
# Edit paths in the config
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
Services
Development
| Service | Port | Description |
|---|---|---|
| Nginx | 8080 | Web server |
| MySQL | 3306 | Database |
| Redis | 6379 | Cache/Queue |
| Mailpit | 8025 | Email testing UI |
| Mailpit SMTP | 1025 | SMTP server |
Connecting to MySQL from host
mysql -h 127.0.0.1 -P 3306 -u laravel -p
# Password: secret (from .env)
Error Logging
This template uses Flare + Ignition by Spatie for error tracking.
| Environment | Tool | What You Get |
|---|---|---|
| Development | Ignition | Rich error pages, AI explanations, click-to-open in VS Code |
| Production | Flare | Remote error tracking, clean user-facing error pages |
Setup
After installing Laravel, run the post-install script:
make setup-tools
This installs:
- Flare for production error tracking
- Custom error pages (404, 500, 503)
- Optional: Laravel Telescope for debugging
Get your Flare API key at flareapp.io and add to .env:
FLARE_KEY=your_key_here
See docs/error-logging.md for full documentation.
Code Style (Laravel Pint)
This template includes Laravel Pint for code style enforcement.
# Fix code style
make lint
# Check without fixing
make lint-check
Configuration: src/pint.json (uses Laravel preset with sensible defaults).
Scheduler (Production)
Laravel's task scheduler needs to run every minute. Two options:
Option 1: Cron (Recommended)
# Add to crontab
sudo crontab -e -u www-data
# Add this line:
* * * * * cd /var/www/your-app && php artisan schedule:run >> /dev/null 2>&1
Option 2: Supervisor
sudo cp deploy/scripts/supervisor-scheduler.conf /etc/supervisor/conf.d/
# Edit paths in the config
sudo supervisorctl reread && sudo supervisorctl update
Customization
Changing PHP Version
Edit docker/php/Dockerfile:
FROM php:8.2-fpm # Change version here
Then rebuild: docker-compose build app
Adding PHP Extensions
Edit docker/php/Dockerfile and add to the install list, then rebuild.
Using PostgreSQL
- Uncomment PostgreSQL in
docker-compose.yml - Update
src/.env:DB_CONNECTION=pgsql DB_HOST=pgsql
Troubleshooting
Permission Issues
# Development
docker-compose exec app chmod -R 775 storage bootstrap/cache
# Production
sudo bash deploy/scripts/fix-permissions.sh /var/www/your-app/src
Container won't start
docker-compose logs app # Check for errors
docker-compose down -v # Reset volumes
docker-compose up -d
Database connection refused
- Ensure MySQL container is running:
docker-compose ps - Check
DB_HOST=mysqlinsrc/.env(notlocalhost)
License
MIT