Skip to main content
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:
backend/.env
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:
backend/.env
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:
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:
backend/.env
QUEUE_CONNECTION=redis

REDIS_HOST=redis
REDIS_PASSWORD=<redis-password>
REDIS_PORT=6379
Add Redis to your docker-compose.yml:
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:
backend/.env
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.
1

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
2

Obtain certificate

Generate SSL certificate for your domain:
sudo certbot --nginx -d your-domain.com -d www.your-domain.com
3

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;
}
4

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:
docker-compose.yml
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.
1

Create backup script

Create a backup script at scripts/backup-db.sh:
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"
2

Make executable

chmod +x scripts/backup-db.sh
3

Schedule with cron

Add to crontab for daily backups at 2 AM:
crontab -e
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:
docker-compose.yml
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-id>

# Clear failed jobs
docker compose exec app php artisan queue:flush

Log management

Log rotation

Configure daily log rotation in .env:
backend/.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:
docker-compose.yml
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

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:
docker-compose.yml
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:
backend/.env
DB_POOL_MIN=2
DB_POOL_MAX=10
Add PgBouncer for connection pooling:
docker-compose.yml
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:
backend/.env
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

Monitoring tools

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:
backend/.env
SENTRY_LARAVEL_DSN=https://[email protected]/project-id
SENTRY_TRACES_SAMPLE_RATE=0.2

Performance optimization

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:
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:
backend/.env
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:
docker-compose.yml
db:
  # Remove or comment out ports mapping
  # ports:
  #   - "5432:5432"

Environment variables

Never commit .env files to version control:
.gitignore
.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:
  • APP_ENV=production and APP_DEBUG=false
  • Strong, unique APP_KEY generated
  • Secure database credentials
  • SSL/HTTPS configured and enforced
  • Database backups scheduled
  • Queue workers monitored with Supervisor
  • Log rotation configured
  • Resource limits set on containers
  • Health checks implemented
  • Monitoring and alerting configured
  • All caches enabled (config, routes, views)
  • File permissions set correctly
  • Rate limiting enabled
  • .env not committed to version control
  • Error tracking (Sentry) configured
  • CDN configured for static assets

Next steps

Configuration

Learn about all environment variables

Docker deployment

Learn about Docker Compose setup

Build docs developers (and LLMs) love