[ 'name' => 'Jane Doe Photography', // Base URL of the public site, no trailing slash. Used for links in // shared gallery URLs. Example: 'https://www.example.com' 'base_url' => 'https://www.example.com', // IANA timezone used for gallery expiry checks. 'timezone' => 'Europe/Berlin', ], // ---- Hetzner Object Storage (S3-compatible) --------------------------- // Create the bucket in the Hetzner console, keep it PRIVATE. // Endpoint depends on the location, e.g. fsn1/nbg1/hel1. 's3' => [ 'endpoint' => 'https://fsn1.your-objectstorage.com', 'region' => 'fsn1', 'bucket' => 'my-photo-galleries', 'access_key' => 'CHANGE_ME', 'secret_key' => 'CHANGE_ME', // Bucket addressing. true → https://// // (path-style, recommended for Hetzner). false → virtual-hosted-style // https://./, which needs the bucket to // resolve as a TLS subdomain of the endpoint. 'path_style' => true, // Key prefix under which gallery objects are stored: // //originals/... and .../thumbs/... Set to '' to store // galleries at the bucket root. 'prefix' => 'galleries', // Lifetime of presigned GET URLs (seconds). Gallery pages embed these; // after expiry the browser must reload the page for fresh URLs. 'url_ttl' => 3600, ], // ---- Uploads ---------------------------------------------------------- 'uploads' => [ // Longest edge of the client-side generated grid thumbnails (px). // Originals are never touched. 'thumb_size' => 600, // JPEG quality for thumbnails (0.0 - 1.0, used by the browser canvas). 'thumb_quality' => 0.8, // JPEG quality for downscaled originals (0.0 - 1.0). Only applies to // galleries that set a resolution cap; "Original" galleries are never // re-encoded. 'resize_quality' => 0.9, // How many images the browser uploads at once. Each one holds a PHP // worker on the webhost for its whole S3 round trip, so keep this // below the host's per-site process limit. 1 restores serial uploads. 'concurrency' => 3, ], // ---- Download-all archives -------------------------------------------- // A gallery with downloads enabled gets one ZIP built into S3 and rebuilt // whenever its images change. The build is split into slices so that no // request ever approaches the host's max_execution_time, which on shared // hosting is typically 60 s and cannot be raised. 'archive' => [ // Seconds of work per request. Must stay comfortably below // max_execution_time: a slice stops starting new photos at this point, // but the one already running still has to finish. 'step_seconds' => 25, // How long a gallery must go unchanged before its archive is rebuilt. // Guests uploading over an hour should trigger one rebuild, not thirty. 'settle_seconds' => 300, // Bytes buffered before they are sent as one multipart part. S3 rejects // parts under 5 MB (the final part excepted), so do not lower this. 'part_min_bytes' => 5 * 1024 * 1024, // A build with no progress for this long is assumed dead: its multipart // upload is aborted (S3 bills for the parts) and it restarts. 'abandon_hours' => 24, // Safety net on the self-dispatching background worker chain. A normal // build is a few dozen links long. 'max_chain' => 500, ], ];