Configuration
Laravel Shaka can be configured via the config/laravel-shaka.php file.
Publishing configuration
Publish the configuration file:
php artisan vendor:publish --tag="shaka-config"
Configuration options
Packager binary
Configure the path to the Shaka Packager binary:
'packager' => [
'binaries' => env('PACKAGER_PATH', '/usr/local/bin/packager'),
],
Environment variable:
PACKAGER_PATH=/usr/local/bin/packager
Multiple binary paths: The system will search for the first available binary:
'packager' => [
'binaries' => [
'/usr/local/bin/packager',
'/usr/bin/packager',
'/opt/shaka-packager/packager',
],
],
Timeout
Set the maximum execution time for packaging operations:
'timeout' => 60 * 60 * 4, // 4 hours in seconds
Environment variable:
PACKAGER_TIMEOUT=14400
Considerations:
- Longer videos require more time
- 4K content takes significantly longer than 1080p
- Multiple quality variants multiply processing time
- Consider your server's PHP
max_execution_timesetting
Logging
Enable logging to track packaging operations:
'log_channel' => env('PACKAGER_LOG_CHANNEL', false),
Environment variables:
# Disable logging (default)
PACKAGER_LOG_CHANNEL=false
# Use default log channel
PACKAGER_LOG_CHANNEL=stack
# Use custom channel
PACKAGER_LOG_CHANNEL=packager
Custom log channel:
Define a custom channel in config/logging.php:
'channels' => [
'packager' => [
'driver' => 'daily',
'path' => storage_path('logs/packager.log'),
'level' => 'debug',
'days' => 14,
],
],
Temporary files
Configure where temporary files are stored:
'temporary_files_root' => env('PACKAGER_TEMPORARY_FILES_ROOT', storage_path('app/packager/temp')),
Environment variable:
PACKAGER_TEMPORARY_FILES_ROOT=/tmp/packager
Considerations:
- Remote files (S3, etc.) are copied here before processing
- Ensure sufficient disk space
- Clean up regularly with
cleanupTemporaryFiles() - Use
/dev/shmfor faster processing (RAM disk)
Encrypted files
Configure location for encrypted temporary files:
'temporary_files_encrypted' => env('PACKAGER_TEMPORARY_ENCRYPTED', '/dev/shm'),
Environment variable:
PACKAGER_TEMPORARY_ENCRYPTED=/dev/shm
Storage space guards
Fail fast with a clear exception instead of a job dying mid-packaging when a
storage-constrained root (e.g. a size-limited tmpfs) runs low on space. All
three checks are disabled by default (0), so upgrading does not change
behavior for existing installs - set them explicitly to opt in.
'temporary_files_min_free' => env('PACKAGER_TEMPORARY_MIN_FREE', 0),
'temporary_files_size_multiplier' => env('PACKAGER_TEMPORARY_SIZE_MULTIPLIER', 1.5),
'cache_files_min_free' => env('PACKAGER_CACHE_MIN_FREE', 0),
Environment variables:
PACKAGER_TEMPORARY_MIN_FREE=1073741824 # 1 GiB floor on temporary_files_root
PACKAGER_TEMPORARY_SIZE_MULTIPLIER=1.5 # safety factor applied to the job's input size
PACKAGER_CACHE_MIN_FREE=10485760 # 10 MiB floor on cache_files_root
How the checks work:
temporary_files_min_free- a static floor checked againsttemporary_files_rootbefore a job starts.temporary_files_size_multiplier- before packaging starts, the combined size of the job's source input files (MediaCollection::totalSize()) is multiplied by this and checked too, on top of the static floor. Packager repackages/segments already-encoded input rather than re-encoding it, so output size tracks input size closely - this catches jobs whose own footprint won't fit, not just a generically-nearly-full root.cache_files_min_free- a separate floor forcache_files_root(manifests/encryption keys). Kept independent fromtemporary_files_min_freebecause this root is often a much smaller mount than the main temporary root (see the tmpfs example below) - a multi-GB floor meant for the main root would permanently break a small cache mount.
Both failure modes throw Foxws\Shaka\Exceptions\InsufficientStorageException, catchable separately from other packaging failures (e.g. in a queued job's failed() method).
Tuning the multiplier: 1.5 is a starting point, not a measurement. After a real job runs, compare du -sh on its temporary directory against the combined size of its source input files, and adjust PACKAGER_TEMPORARY_SIZE_MULTIPLIER from there - especially if you generate separate HLS and DASH segment sets rather than sharing CMAF segments across both, which pushes real usage closer to 2x than 1.5x.
Example: temporary_files_root on a Podman tmpfs
If you run Horizon/queue workers in Podman and want packaging scratch space
to live in RAM instead of hitting your NVMe (segments are written once,
uploaded, then deleted - nothing here needs to survive a restart), mount
the root as a tmpfs in your .container quadlet instead of a regular
volume:
# horizon.container (podman quadlet)
[Container]
...
# Was: Volume=app-cache:/cache:rw,z
Tmpfs=/cache:rw,size=12g,mode=1777
Then point the package at it and set a floor sized to fit comfortably inside that tmpfs, leaving headroom for concurrent jobs:
PACKAGER_TEMPORARY_FILES_ROOT=/cache/temp/packager
PACKAGER_TEMPORARY_MIN_FREE=1073741824 # 1 GiB
PACKAGER_TEMPORARY_SIZE_MULTIPLIER=1.5
cache_files_root (manifests/keys) typically points at /dev/shm, a
separate tmpfs the container runtime mounts automatically. Keep its floor
small relative to that mount's actual size (often just tens of MB via a
container's ShmSize):
PACKAGER_CACHE_FILES_ROOT=/dev/shm
PACKAGER_CACHE_MIN_FREE=10485760 # 10 MiB
A tmpfs
size=is a quota, not a reservation - it does not protect you from concurrent jobs collectively exceeding it. Pair this with a concurrency limit on your queue (e.g. Horizon'smaxProcesses) sized soworkers x largest expected job footprintstays comfortably under the tmpfs size, and treattemporary_files_min_freeas a fail-fast safety net for the jobs that slip past that limit, not as the primary defense.
Complete configuration example
<?php
return [
/*
|--------------------------------------------------------------------------
| Shaka Packager Binary
|--------------------------------------------------------------------------
|
| Path to the Shaka Packager binary. Can be a string or array of paths.
| The system will use the first available binary.
|
*/
'packager' => [
'binaries' => env('PACKAGER_PATH', '/usr/local/bin/packager'),
],
/*
|--------------------------------------------------------------------------
| Timeout
|--------------------------------------------------------------------------
|
| Maximum execution time in seconds for packaging operations.
| Adjust based on your content size and quality requirements.
|
*/
'timeout' => env('PACKAGER_TIMEOUT', 60 * 60 * 4), // 4 hours
/*
|--------------------------------------------------------------------------
| Logging
|--------------------------------------------------------------------------
|
| Log channel for packaging operations. Set to false to disable logging.
| Use your default log channel or define a custom one.
|
*/
'log_channel' => env('PACKAGER_LOG_CHANNEL', false),
/*
|--------------------------------------------------------------------------
| Temporary Files
|--------------------------------------------------------------------------
|
| Root directory for temporary files during packaging operations.
| Remote files are downloaded here before processing.
|
*/
'temporary_files_root' => env('PACKAGER_TEMPORARY_FILES_ROOT', storage_path('app/packager/temp')),
/*
|--------------------------------------------------------------------------
| Encrypted Temporary Files
|--------------------------------------------------------------------------
|
| Directory for encrypted temporary files. Using /dev/shm (RAM disk)
| provides better performance for encryption operations.
|
*/
'temporary_files_encrypted' => env('PACKAGER_TEMPORARY_ENCRYPTED', '/dev/shm'),
/*
|--------------------------------------------------------------------------
| Storage Space Guards
|--------------------------------------------------------------------------
|
| Fail fast with a clear exception instead of a job dying mid-packaging
| when a storage-constrained root runs low on space. Set to 0 to
| disable a given check.
|
*/
'temporary_files_min_free' => env('PACKAGER_TEMPORARY_MIN_FREE', 0),
'temporary_files_size_multiplier' => env('PACKAGER_TEMPORARY_SIZE_MULTIPLIER', 1.5),
'cache_files_min_free' => env('PACKAGER_CACHE_MIN_FREE', 0),
];
Environment configuration
Example .env configuration:
# Shaka Packager Configuration
PACKAGER_PATH=/usr/local/bin/packager
PACKAGER_TIMEOUT=14400
PACKAGER_LOG_CHANNEL=packager
PACKAGER_TEMPORARY_FILES_ROOT=/tmp/packager
PACKAGER_TEMPORARY_ENCRYPTED=/dev/shm
PACKAGER_TEMPORARY_MIN_FREE=1073741824
PACKAGER_TEMPORARY_SIZE_MULTIPLIER=1.5
PACKAGER_CACHE_MIN_FREE=10485760
Verification
After configuration, verify your setup:
php artisan shaka:info
This command checks:
- Binary path is valid and executable
- Can retrieve version information
- Timeout is configured
- Logger is properly set up
Runtime configuration
You can also configure the packager at runtime:
use Foxws\Shaka\Support\Packager\Packager;
use Foxws\Shaka\Support\Packager\ShakaPackager;
// Create with custom configuration
$driver = new ShakaPackager(
binaryPath: '/custom/path/packager',
logger: Log::channel('custom'),
timeout: 7200
);
$packager = new Packager($driver, Log::channel('custom'));
Or using the static create method:
$packager = Packager::create(
logger: Log::channel('packager'),
configuration: [
'packager' => ['binaries' => '/custom/path/packager'],
'timeout' => 7200,
]
);
Driver configuration
Modify driver settings after instantiation:
$driver = app(ShakaPackager::class);
// Change timeout
$driver->setTimeout(7200);
// Change logger
$driver->setLogger(Log::channel('debug'));
Troubleshooting
Binary not found
If you see "Executable not found" errors:
- Verify the binary exists:
which packager - Check permissions:
ls -l /usr/local/bin/packager - Ensure it's executable:
chmod +x /usr/local/bin/packager - Update config with correct path
Timeout errors
If operations timeout:
- Increase timeout in config
- Check server PHP
max_execution_time - Consider queueing long operations
- Optimize video settings (resolution, bitrate)
Permission errors
If you see permission errors:
- Check temporary directory permissions
- Ensure web server user can write
- Verify binary is executable
- Check SELinux/AppArmor policies
Logging issues
If logging doesn't work:
- Verify log channel exists in
config/logging.php - Check log directory permissions
- Ensure channel is properly configured
- Test with a simple log entry
See the Troubleshooting guide for more issues and solutions.