This guide covers detailed production environment configuration for NutriFit. Follow these instructions to ensure optimal performance, security, and reliability.
Environment File Configuration
Creating Production .env
Start with the example environment file:
Then customize for production:
Complete Production .env
Minimal Production .env
# Application
APP_NAME = "NutriFit"
APP_ENV = production
APP_KEY = base64:YOUR_GENERATED_KEY_HERE
APP_DEBUG = false
APP_URL = https://yourdomain.com
APP_LOCALE = es
APP_FALLBACK_LOCALE = es
# Security
BCRYPT_ROUNDS = 12
# Logging
LOG_CHANNEL = stack
LOG_STACK = daily
LOG_LEVEL = error
LOG_DEPRECATIONS_CHANNEL = null
# Database (MySQL)
DB_CONNECTION = mysql
DB_HOST = 127.0.0.1
DB_PORT = 3306
DB_DATABASE = nutrifit
DB_USERNAME = nutrifit_user
DB_PASSWORD = your_secure_database_password
# Session
SESSION_DRIVER = database
SESSION_LIFETIME = 120
SESSION_ENCRYPT = false
SESSION_PATH = /
SESSION_DOMAIN = .yourdomain.com
# Cache
CACHE_STORE = database
# Or use Redis for better performance:
# CACHE_STORE=redis
# Queue
QUEUE_CONNECTION = database
# Or use Redis for better performance:
# QUEUE_CONNECTION=redis
# Mail (Production SMTP)
MAIL_MAILER = smtp
MAIL_HOST = smtp.yourdomain.com
MAIL_PORT = 587
MAIL_USERNAME = noreply@yourdomain.com
MAIL_PASSWORD = your_mail_password
MAIL_ENCRYPTION = tls
MAIL_FROM_ADDRESS = "noreply@yourdomain.com"
MAIL_FROM_NAME = "${ APP_NAME }"
# Redis (Optional but recommended)
# REDIS_CLIENT=phpredis
# REDIS_HOST=127.0.0.1
# REDIS_PASSWORD=null
# REDIS_PORT=6379
# Admin credentials
ADMIN_PASSWORD = your_secure_admin_password
Always use strong, unique passwords for database and admin accounts. Never reuse development passwords in production.
Database Setup
MySQL Configuration
Create Database
Create a dedicated database for NutriFit: CREATE DATABASE nutrifit CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Create Database User
Create a dedicated user with appropriate permissions: CREATE USER ' nutrifit_user '@ 'localhost' IDENTIFIED BY 'secure_password' ;
GRANT ALL PRIVILEGES ON nutrifit. * TO 'nutrifit_user' @ 'localhost' ;
FLUSH PRIVILEGES;
Replace secure_password with a strong password generated by a password manager.
Run Migrations
Execute database migrations: php artisan migrate --force
The --force flag is required for production environments.
Seed Initial Data
Create admin user and initial data: Default admin credentials:
Email: nutrifit2026@gmail.com
Password: Set via ADMIN_PASSWORD in .env
Database Optimization
MySQL Settings
Connection Pooling
Indexes
Optimize MySQL for NutriFit workload: # /etc/mysql/my.cnf or /etc/my.cnf
[mysqld]
max_connections = 150
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
query_cache_size = 0
query_cache_type = 0
Restart MySQL after changes: sudo systemctl restart mysql
Laravel uses persistent connections by default for MySQL. No additional configuration needed. For high-traffic scenarios, consider using ProxySQL or PgBouncer (for PostgreSQL).
NutriFit migrations include optimized indexes. Verify they exist: SHOW INDEX FROM appointments;
SHOW INDEX FROM attentions;
SHOW INDEX FROM users;
Key indexes:
appointments.nutritionist_id
appointments.patient_id
appointments.status
appointments.scheduled_date
Mail Server Configuration
SMTP Providers
Professional transactional email service: MAIL_MAILER = smtp
MAIL_HOST = smtp.postmarkapp.com
MAIL_PORT = 587
MAIL_USERNAME = your_postmark_token
MAIL_PASSWORD = your_postmark_token
MAIL_ENCRYPTION = tls
MAIL_FROM_ADDRESS = "noreply@yourdomain.com"
Benefits:
High deliverability rates
Detailed analytics
Bounce/spam handling
Free tier available
Cost-effective for high volume: MAIL_MAILER = ses
AWS_ACCESS_KEY_ID = your_key_id
AWS_SECRET_ACCESS_KEY = your_secret_key
AWS_DEFAULT_REGION = us-east-1
MAIL_FROM_ADDRESS = "noreply@yourdomain.com"
Benefits:
Very low cost ($0.10 per 1,000 emails)
Scalable
Integrated with AWS ecosystem
Developer-friendly email service: MAIL_MAILER = mailgun
MAILGUN_DOMAIN = yourdomain.com
MAILGUN_SECRET = your_api_key
MAIL_FROM_ADDRESS = "noreply@yourdomain.com"
Requires package: composer require symfony/mailgun-mailer
Use your own mail server: MAIL_MAILER = smtp
MAIL_HOST = mail.yourdomain.com
MAIL_PORT = 587
MAIL_USERNAME = noreply@yourdomain.com
MAIL_PASSWORD = your_password
MAIL_ENCRYPTION = tls
Ensure proper SPF, DKIM, and DMARC records are configured to prevent emails from being marked as spam.
Email Testing
Verify email delivery:
Then run:
Mail :: raw ( 'Test email from NutriFit' , function ( $message ) {
$message -> to ( 'your-email@example.com' )
-> subject ( 'NutriFit Email Test' );
});
Check your inbox and spam folder for the test email.
Cache Configuration
Database Cache (Default)
NutriFit uses database caching by default:
Ensure cache table exists:
php artisan cache:table
php artisan migrate
Redis Cache (Recommended)
For better performance, use Redis:
Install Redis
# Ubuntu/Debian
sudo apt install redis-server
# Start Redis
sudo systemctl start redis
sudo systemctl enable redis
Install PHP Redis Extension
sudo apt install php8.2-redis
sudo systemctl restart php8.2-fpm
Configure Laravel
Update .env: CACHE_STORE = redis
SESSION_DRIVER = redis
QUEUE_CONNECTION = redis
REDIS_CLIENT = phpredis
REDIS_HOST = 127.0.0.1
REDIS_PASSWORD = null
REDIS_PORT = 6379
Test Redis Connection
Cache :: put ( 'test' , 'value' , 60 );
Cache :: get ( 'test' ); // Should return 'value'
Cache Optimization
Clear and recache for optimal performance:
# Clear all caches
php artisan optimize:clear
# Rebuild caches
php artisan config:cache
php artisan route:cache
php artisan view:cache
Run these commands after every deployment to ensure caches are up to date.
Security Configuration
Application Security
Protect sensitive configuration: # Set restrictive permissions
chmod 600 .env
# Ensure proper ownership
chown www-data:www-data .env
Never commit .env to version control: # .gitignore already includes
.env
.env.backup
.env.production
Set correct filesystem permissions: # Storage and cache directories
chmod -R 755 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache
# Application files (read-only)
chmod -R 644 app/ config/ routes/
chmod -R 755 artisan
Force HTTPS for all requests. Add to .env: APP_URL = https://yourdomain.com
Configure in app/Http/Middleware/TrustProxies.php if behind proxy: protected $proxies = '*' ;
protected $headers = Request :: HEADER_X_FORWARDED_ALL ;
NutriFit includes rate limiting. Configure in config/fortify.php: 'limiters' => [
'login' => 'login' ,
'two-factor' => 'two-factor' ,
],
Default: 5 login attempts per minute per IP.
CORS Configuration
If you plan to add API access:
php artisan config:publish cors
Edit config/cors.php:
'allowed_origins' => [ 'https://yourdomain.com' ],
'allowed_methods' => [ '*' ],
'allowed_headers' => [ '*' ],
Session Configuration
Database Sessions (Default)
SESSION_DRIVER = database
SESSION_LIFETIME = 120
Ensure session table exists:
php artisan session:table
php artisan migrate
Redis Sessions (Recommended)
For better performance:
SESSION_DRIVER = redis
SESSION_CONNECTION = default
Session Security
Configure session cookie settings in .env:
SESSION_DOMAIN = .yourdomain.com
SESSION_SECURE_COOKIE = true
SESSION_HTTP_ONLY = true
SESSION_SAME_SITE = lax
Logging Configuration
Production Logging
Configure appropriate log level:
LOG_CHANNEL = stack
LOG_STACK = daily
LOG_LEVEL = error
This creates daily log files in storage/logs/.
Log Rotation
Configure automatic log rotation:
// config/logging.php
'daily' => [
'driver' => 'daily' ,
'path' => storage_path ( 'logs/laravel.log' ),
'level' => env ( 'LOG_LEVEL' , 'error' ),
'days' => 14 , // Keep logs for 14 days
],
External Logging Services
For production monitoring, consider:
Sentry Error tracking and performance monitoring composer require sentry/sentry-laravel
php artisan sentry:publish
Papertrail Cloud-based log management Configure syslog in config/logging.php
OPcache Configuration
Enable OPcache for PHP (should be enabled by default):
; /etc/php/8.2/fpm/php.ini
opcache.enable =1
opcache.memory_consumption =256
opcache.interned_strings_buffer =16
opcache.max_accelerated_files =10000
opcache.revalidate_freq =2
Restart PHP-FPM:
sudo systemctl restart php8.2-fpm
PHP-FPM Tuning
Optimize PHP-FPM pool:
; /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
Laravel Optimizations
Run all optimization commands:
# Install production dependencies only
composer install --optimize-autoloader --no-dev
# Cache everything
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Build optimized assets
npm run build
Health Checks
Verify your production configuration:
# Check environment
php artisan env
# Test database connection
php artisan db:show
# Verify queue is working
php artisan queue:work --once
# Check scheduled tasks
php artisan schedule:list
Troubleshooting
500 Internal Server Error
Check Laravel logs: storage/logs/laravel.log
Verify file permissions
Clear all caches: php artisan optimize:clear
Check web server error logs
Verify SMTP credentials
Check queue worker is running
Review failed jobs: php artisan queue:failed
Test mail configuration with tinker
Database Connection Failed
Verify MySQL is running: sudo systemctl status mysql
Check credentials in .env
Test connection: mysql -u nutrifit_user -p nutrifit
Verify MySQL grants are correct
Next Steps
Deployment Platforms Choose your hosting platform
Queue Workers Configure background job processing
Checklist Pre-deployment verification
Monitoring Set up application monitoring