Docs LATEST

Production Checklist

Complete guide to deploying VelvetCMS in production.

Deployment

Follow this checklist before going live. Each step improves performance, security, or reliability.

Environment Configuration #

Application Settings #

// user/config/app.php
return [
    'env' => 'production',
    'debug' => false,
];

// user/config/logging.php
return [
    'level' => 'warning',  // or 'error' for less noise
    'daily' => true,       // rotate logs daily
    'max_files' => 14,     // keep 2 weeks
];
  • debug must be false - prevents exposing stack traces
  • level - reduce verbosity for production
  • daily - enables log rotation to prevent disk fill

Cache Configuration #

./velvet config:cache

This compiles all config files into a single cached file, reducing file reads on every request.

Clear when you change configuration:

./velvet config:clear

PHP Configuration #

OPcache Settings #

Add to your php.ini:

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.fast_shutdown=1

Key points:

  • validate_timestamps=0 - don't check file changes (deploy clears opcache)
  • memory_consumption - increase for larger apps

PHP-FPM Tuning #

For high traffic, tune your PHP-FPM pool:

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500

Adjust based on your server's memory and expected load.

Web Server #

Document Root #

Point your web server to the public/ directory:

root /var/www/velvet/public;

Never expose the project root - it contains sensitive files.

Deny Sensitive Paths #

Block access to configuration, storage, and vendor directories:

Nginx:

location ~ ^/(vendor|storage|config|database|bootstrap)/ {
    deny all;
    return 404;
}

location ~ /\. {
    deny all;
}

See Nginx Configuration and Apache Configuration for complete examples.

Caching #

Application Cache #

If Redis is available, use it:

// user/config/cache.php
return [
    'default' => 'redis',
    'drivers' => [
        'redis' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'port' => 6379,
        ],
    ],
];

Route Caching #

./velvet route:cache

Speeds up route matching. Clear after adding/changing routes.

View Caching #

Compiled views are cached automatically. Clear if templates don't update:

./velvet view:clear

Database #

Connection Settings #

For MySQL/PostgreSQL, ensure persistent connections are enabled for long-running processes:

'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'database' => env('DB_DATABASE', 'velvet'),
    'username' => env('DB_USERNAME', 'velvet'),
    'password' => env('DB_PASSWORD'),
    // ...
],

Run Migrations #

./velvet migrate

Scheduled Tasks #

Add to your system crontab:

* * * * * cd /var/www/velvet && php velvet schedule:run >> /dev/null 2>&1

This runs the scheduler every minute - individual tasks run at their configured frequencies.

WebCron Alternative #

If system cron isn't available, enable WebCron:

// user/config/app.php
'cron_enabled' => true,

Then set up an external service to hit /system/cron every minute. See WebCron for security considerations.

Security #

HTTPS #

Ensure HTTPS is configured and HTTP redirects to HTTPS.

Session Security #

// user/config/session.php
return [
    'secure' => true,        // Cookies only over HTTPS
    'same_site' => 'Lax',    // Or 'Strict'
    'httponly' => true,      // No JavaScript access
];

File Permissions #

# Code directories: readable, not writable
chmod -R 755 src/ config/ public/ vendor/

# Storage: writable by web server
chmod -R 775 storage/
chown -R www-data:www-data storage/

For additional security measures (HTTP headers, CSP, HSTS, database user separation), see Security Hardening.

Monitoring #

Log Rotation #

Configure logrotate for VelvetCMS logs:

/var/www/velvet/storage/logs/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data www-data
}

Health Check Endpoint #

Create a simple health check route:

$router->get('/health', function () {
    return Response::json([
        'status' => 'ok',
        'timestamp' => time(),
    ]);
});

Use with uptime monitoring services.

Quick Checklist #

  • debug = false
  • env = production
  • Config cached (config:cache)
  • Routes cached (route:cache)
  • OPcache enabled
  • Document root is public/
  • Sensitive paths blocked
  • HTTPS configured
  • Session cookies secured
  • Cron job installed
  • Log rotation configured
  • Database migrations run