Deploying Filebright to production requires additional configuration and monitoring to ensure security, reliability, and performance. This guide covers essential production considerations.
Environment configuration
Security settings
Update your .env file with production-appropriate values:
APP_ENV = production
APP_DEBUG = false
APP_URL = https://your-domain.com
LOG_LEVEL = warning
LOG_CHANNEL = stack
LOG_STACK = daily
Never set APP_DEBUG=true in production. This exposes sensitive information including stack traces, environment variables, and database queries.
Application key
Generate a unique application key for encryption:
docker compose exec app php artisan key:generate
The APP_KEY is used to encrypt session data and other sensitive information. Never share this key or commit it to version control. Changing it will invalidate existing sessions and encrypted data.
Database credentials
Use strong, randomly generated passwords for database access:
DB_CONNECTION = pgsql
DB_HOST = db
DB_PORT = 5432
DB_DATABASE = filebright_prod
DB_USERNAME = filebright_user
DB_PASSWORD =< strong-random-password >
Update the corresponding variables in your environment or docker-compose.yml:
db :
environment :
POSTGRES_DB : filebright_prod
POSTGRES_USER : filebright_user
POSTGRES_PASSWORD : <strong-random-password>
Consider using environment variable substitution from a .env file at the docker-compose level to avoid hardcoding credentials.
Queue configuration
For production, use a dedicated queue driver instead of the database:
QUEUE_CONNECTION = redis
REDIS_HOST = redis
REDIS_PASSWORD =< redis-password >
REDIS_PORT = 6379
Add Redis to your docker-compose.yml:
services :
redis :
image : redis:alpine
container_name : filebright_redis
restart : unless-stopped
command : redis-server --requirepass <redis-password>
ports :
- "6379:6379"
volumes :
- filebright_redis_data:/data
networks :
- filebright_net
volumes :
filebright_redis_data :
Session and cache
Configure session and cache to use Redis for better performance:
SESSION_DRIVER = redis
CACHE_STORE = redis
SSL/HTTPS setup
Using a reverse proxy
The recommended approach is to run a reverse proxy (Nginx or Traefik) in front of Filebright to handle SSL termination.
Install Certbot
Install Certbot on your host system to obtain Let’s Encrypt certificates: sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
Obtain certificate
Generate SSL certificate for your domain: sudo certbot --nginx -d your-domain.com -d www.your-domain.com
Configure Nginx
Update your Nginx configuration to proxy to Filebright: /etc/nginx/sites-available/filebright
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Frontend
location / {
proxy_pass http://localhost:80;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
}
# Backend API
location /api {
proxy_pass http://localhost:8000;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
client_max_body_size 100M ;
}
}
# Redirect HTTP to HTTPS
server {
listen 80 ;
server_name your-domain.com;
return 301 https://$ server_name $ request_uri ;
}
Enable configuration
Enable the site and reload Nginx: sudo ln -s /etc/nginx/sites-available/filebright /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Using Traefik
Alternatively, use Traefik for automatic SSL certificate management:
services :
traefik :
image : traefik:v2.10
container_name : traefik
restart : unless-stopped
command :
- "--api.insecure=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=admin@your-domain.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports :
- "80:80"
- "443:443"
volumes :
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_certs:/letsencrypt
networks :
- filebright_net
frontend :
labels :
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`your-domain.com`)"
- "traefik.http.routers.frontend.entrypoints=websecure"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
web :
labels :
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`your-domain.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
volumes :
traefik_certs :
Database management
Backups
Implement regular database backups to prevent data loss.
Create backup script
Create a backup script at scripts/backup-db.sh: #!/bin/bash
BACKUP_DIR = "/backups"
TIMESTAMP = $( date +%Y%m%d_%H%M%S )
BACKUP_FILE = " $BACKUP_DIR /filebright_ $TIMESTAMP .sql.gz"
# Create backup directory if it doesn't exist
mkdir -p $BACKUP_DIR
# Backup database
docker compose exec -T db pg_dump -U filebright_user filebright_prod | gzip > $BACKUP_FILE
# Keep only last 30 days of backups
find $BACKUP_DIR -name "filebright_*.sql.gz" -mtime +30 -delete
echo "Backup completed: $BACKUP_FILE "
Make executable
chmod +x scripts/backup-db.sh
Schedule with cron
Add to crontab for daily backups at 2 AM: Add this line: 0 2 * * * /path/to/filebright/scripts/backup-db.sh >> /var/log/filebright-backup.log 2>&1
Restore from backup
Restore a database backup:
# Stop application to prevent writes
docker compose stop app worker
# Restore backup
gunzip < /backups/filebright_20260303_020000.sql.gz | docker compose exec -T db psql -U filebright_user filebright_prod
# Restart application
docker compose start app worker
Always test your backup and restore procedures before relying on them in production.
Database optimization
Run maintenance tasks periodically:
# Analyze and vacuum database
docker compose exec db vacuumdb -U filebright_user -d filebright_prod -z -v
# Reindex database
docker compose exec db reindexdb -U filebright_user -d filebright_prod
Queue worker monitoring
Ensure queue workers are always running and processing jobs efficiently.
Supervisor configuration
For production, run multiple queue workers with process supervision:
Update docker-compose.yml to use Supervisor:
worker :
build :
context : ./backend
dockerfile : Dockerfile
container_name : filebright_worker
restart : unless-stopped
working_dir : /var/www
env_file : ./backend/.env
command : [ "/usr/bin/supervisord" , "-c" , "/etc/supervisor/supervisord.conf" ]
volumes :
- ./backend/storage:/var/www/storage
- ./backend/supervisor/queue-worker.conf:/etc/supervisor/conf.d/queue-worker.conf
Create supervisor configuration at backend/supervisor/queue-worker.conf:
backend/supervisor/queue-worker.conf
[program:queue-worker]
process_name =%(program_name)s_%(process_num)02d
command =php /var/www/artisan queue:work -- sleep =3 -- tries =3 -- max-time =3600
autostart =true
autorestart =true
stopasgroup =true
killasgroup =true
user =www-data
numprocs =4
redirect_stderr =true
stdout_logfile =/var/www/storage/logs/worker.log
stopwaitsecs =3600
This configuration runs 4 queue worker processes, automatically restarting them if they fail or exceed 1 hour of runtime.
Monitor queue status
Check queue status regularly:
# View pending jobs
docker compose exec app php artisan queue:work --once
# Monitor queue in real-time
docker compose logs -f worker
# Check failed jobs
docker compose exec app php artisan queue:failed
Retry failed jobs
# Retry all failed jobs
docker compose exec app php artisan queue:retry all
# Retry specific job
docker compose exec app php artisan queue:retry < job-i d >
# Clear failed jobs
docker compose exec app php artisan queue:flush
Log management
Log rotation
Configure daily log rotation in .env:
LOG_CHANNEL = stack
LOG_STACK = daily
LOG_LEVEL = warning
Laravel automatically rotates logs daily and keeps 14 days by default.
Centralized logging
For production, consider centralized logging with the ELK stack (Elasticsearch, Logstash, Kibana) or a service like Papertrail:
services :
app :
logging :
driver : "syslog"
options :
syslog-address : "tcp://logs.papertrailapp.com:12345"
tag : "filebright-app"
worker :
logging :
driver : "syslog"
options :
syslog-address : "tcp://logs.papertrailapp.com:12345"
tag : "filebright-worker"
View logs
Application logs
Worker logs
Nginx access logs
Nginx error logs
docker compose exec app tail -f /var/www/storage/logs/laravel.log
Scaling considerations
Horizontal scaling
Scale services independently based on load:
# Scale queue workers
docker compose up -d --scale worker= 3
# Scale application servers
docker compose up -d --scale app= 2
When scaling the app service, you’ll need a load balancer (Nginx, HAProxy, or Traefik) to distribute traffic across instances.
Resource limits
Set resource limits to prevent containers from consuming excessive resources:
services :
app :
deploy :
resources :
limits :
cpus : '2.0'
memory : 1G
reservations :
cpus : '0.5'
memory : 512M
worker :
deploy :
resources :
limits :
cpus : '1.0'
memory : 512M
reservations :
cpus : '0.25'
memory : 256M
Database connection pooling
Configure connection pooling for better database performance:
DB_POOL_MIN = 2
DB_POOL_MAX = 10
Add PgBouncer for connection pooling:
services :
pgbouncer :
image : pgbouncer/pgbouncer:latest
container_name : filebright_pgbouncer
restart : unless-stopped
environment :
DATABASES_HOST : db
DATABASES_PORT : 5432
DATABASES_USER : filebright_user
DATABASES_PASSWORD : <db-password>
DATABASES_DBNAME : filebright_prod
PGBOUNCER_POOL_MODE : transaction
PGBOUNCER_MAX_CLIENT_CONN : 100
PGBOUNCER_DEFAULT_POOL_SIZE : 20
ports :
- "6432:6432"
networks :
- filebright_net
Update app configuration to connect through PgBouncer:
DB_HOST = pgbouncer
DB_PORT = 6432
Monitoring and alerts
Health checks
Implement health check endpoints:
# Application health
curl https://your-domain.com/api/health
# Database health
docker compose exec db pg_isready -U filebright_user
Consider these monitoring solutions:
Application Performance : New Relic, Datadog, or Laravel Telescope
Infrastructure : Prometheus + Grafana, Netdata
Uptime : UptimeRobot, Pingdom, or StatusCake
Error Tracking : Sentry, Bugsnag, or Rollbar
Sentry integration
Add error tracking with Sentry:
composer require sentry/sentry-laravel
Configure in .env:
SENTRY_LARAVEL_DSN = https://[email protected] /project-id
SENTRY_TRACES_SAMPLE_RATE = 0.2
Caching
Enable various caching mechanisms:
# Cache configuration
docker compose exec app php artisan config:cache
# Cache routes
docker compose exec app php artisan route:cache
# Cache views
docker compose exec app php artisan view:cache
# Optimize autoloader
docker compose exec app composer dump-autoload --optimize
Run these commands after every deployment or configuration change. Changes to config files won’t take effect until you clear the cache.
OPcache
Enable PHP OPcache in backend/php.ini:
opcache.enable =1
opcache.memory_consumption =256
opcache.interned_strings_buffer =16
opcache.max_accelerated_files =10000
opcache.validate_timestamps =0
opcache.revalidate_freq =0
CDN for static assets
Serve static assets (CSS, JS, images) through a CDN:
ASSET_URL = https://cdn.your-domain.com
Configure your CDN to pull from your origin server.
Security hardening
File permissions
Ensure proper file permissions:
# Application files (read-only for web server)
docker compose exec app find /var/www -type f -exec chmod 644 {} \;
docker compose exec app find /var/www -type d -exec chmod 755 {} \;
# Writable directories
docker compose exec app chmod -R 775 /var/www/storage /var/www/bootstrap/cache
docker compose exec app chown -R www-data:www-data /var/www/storage /var/www/bootstrap/cache
Disable unnecessary services
Don’t expose database ports in production:
db :
# Remove or comment out ports mapping
# ports:
# - "5432:5432"
Environment variables
Never commit .env files to version control:
.env
.env.production
.env.local
Use secure methods to manage secrets:
Docker secrets
Vault by HashiCorp
AWS Secrets Manager
Environment variables from CI/CD
Rate limiting
Configure rate limiting in backend/app/Http/Kernel.php:
'api' => [
'throttle:60,1' , // 60 requests per minute
],
Deployment checklist
Before deploying to production:
Next steps
Configuration Learn about all environment variables
Docker deployment Learn about Docker Compose setup