curl and openssl extensions
(both are standard), and Apache .htaccess support.fsn1). Set visibility to private — visitors get
access only through short-lived presigned URLs.No bucket CORS rule is needed: uploads are proxied through the webhost
(same-origin) and gallery images load via <img> presigned GET URLs, which
browsers don't subject to CORS. Keep the bucket private.
Uploads stream through PHP one image per request, so the total gallery size is
irrelevant — but each single image must fit the host's limits. Ensure
upload_max_filesize and post_max_size are at least as large as your biggest
original (e.g. 200M for RAW files); on shared hosting set these in .user.ini
or php.ini:
upload_max_filesize = 200M
post_max_size = 200M
max_execution_time is lifted per upload request in code, but if your host caps
it at the web-server level (e.g. Apache/FPM request timeout), raise that too for
large files.
cp config/config.sample.php config/config.php
cp config/credentials.sample.php config/credentials.php
Edit config/config.php:
| Key | Meaning |
|---|---|
site.name |
Fallback site title |
site.base_url |
Public base URL, used for gallery share links |
site.timezone |
Timezone for expiry checks, e.g. Europe/Berlin |
s3.endpoint |
https://<location>.your-objectstorage.com |
s3.region |
The location, e.g. fsn1 |
s3.bucket |
Bucket name |
s3.access_key / s3.secret_key |
S3 credentials |
s3.url_ttl |
Lifetime of presigned view URLs in seconds |
uploads.thumb_size |
Longest edge of grid thumbnails (browser-generated) |
The default admin login is admin / changeme — change it in the admin
Settings page immediately after the first login.
Upload the contents of this folder into your account's document root
(usually public_html/, htdocs/ or www/) via FTP/SFTP. The site's home
page, index.php, sits directly in the document root — there is no separate
web-root subfolder to configure.
The application internals (app/, config/, data/, docs/) live inside
the document root but are blocked from the web by the root .htaccess (plus a
deny-all .htaccess inside each of app/, config/, data/ as a fallback).
Verify after deploying — each of these must return 403 Forbidden, never their contents:
https://your-domain.com/config/config.phphttps://your-domain.com/config/credentials.phphttps://your-domain.com/data/site.jsonIf they don't, your host ignores .htaccess — move app/, config/ and
data/ above the document root and adjust the paths, or contact support.
The PHP process must be able to write to:
data/ (and data/galleries/) — flat-file contentmedia/ — hero + showreel imagesconfig/ — only for the online password changeOn typical shared hosting (suEXEC/FPM running as your user) this already
works; otherwise chmod 755 the directories (or 775/777 as a last resort).
/admin/, log in, change the password (Settings)./showreel.php, scroll behavior, and
that navigation hides when scrolling down.your-objectstorage.com, not from your domain,php -S localhost:8080 router.php
router.php reproduces the .htaccess protection for the PHP built-in server
(which does not read .htaccess); it is only used locally.
Everything except real S3 traffic works without credentials; gallery pages render presigned URLs that simply won't resolve until real keys are configured.