Run Picstome on your own server
Picstome is free and open source. You can run it on your own server and keep every feature: galleries, sharing, contracts, invoices, Stripe, camera upload and the desktop apps. There is no paid edition and no feature flag.
The only things you pay for are the server and, if you want, the installation service described at the end.
What you need
Section titled “What you need”A server running Ubuntu 22.04 or 24.04, with root access. The realistic minimum for a small studio:
| Resource | Minimum | Comfortable |
|---|---|---|
| CPU | 2 vCPU | 4 vCPU |
| RAM | 2 GB | 4 GB |
| Disk | 40 GB | 100 GB or more |
| Software | PHP 8.5, MySQL 8 / MariaDB 10.6+, Nginx, Node 22+ | same |
Photo processing is the expensive part: RAW files and large videos need CPU and RAM while they are converted. If you plan to ingest thousands of photos per session, get more than the minimum.
Before you start
Section titled “Before you start”Self-hosting means you own the server, the database and the backups. Nobody else has a copy of your photos, and nobody else can restore them if the disk fails. Read the backups section before you upload a real client gallery.
Installation
Section titled “Installation”-
Point the domain at the server. Create an
Arecord forphotos.yourdomain.compointing to the server IP. Do this first: the HTTPS step fails without it. -
Install the packages.
Terminal window apt update && apt upgrade -yapt install -y nginx mysql-server unzip git supervisor \php8.5-fpm php8.5-cli php8.5-mysql php8.5-mbstring php8.5-xml \php8.5-curl php8.5-zip php8.5-gd php8.5-intl php8.5-imagickCheck with
php -vthat you are on 8.5. If your distribution does not ship it yet, add theondrej/phpPPA first:Terminal window add-apt-repository ppa:ondrej/phpapt update -
Create the database.
Terminal window mysql -u root -pCREATE DATABASE picstome CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;CREATE USER 'picstome'@'localhost' IDENTIFIED BY 'a-long-random-password';GRANT ALL PRIVILEGES ON picstome.* TO 'picstome'@'localhost';FLUSH PRIVILEGES; -
Get the code and the dependencies.
Terminal window cd /var/wwwgit clone https://github.com/picstome/picstome.gitcd picstomecomposer install --no-dev --optimize-autoloadernpm ci && npm run build -
Configure the environment.
Terminal window cp .env.example .envphp artisan key:generateThen edit
.envand set at least:APP_NAME=PicstomeAPP_ENV=productionAPP_DEBUG=falseAPP_URL=https://photos.yourdomain.comDB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=picstomeDB_USERNAME=picstomeDB_PASSWORD=a-long-random-password -
Create the schema and the first admin.
Terminal window php artisan migrate --forcephp artisan create-admin-userphp artisan storage:link -
Nginx. Create
/etc/nginx/sites-available/picstome:server {listen 80;server_name photos.yourdomain.com;root /var/www/picstome/public;index index.php;client_max_body_size 5120M; # match the 5 GB per-file limit of the applocation / {try_files $uri $uri/ /index.php?$query_string;}location ~ \.php$ {include snippets/fastcgi-php.conf;fastcgi_pass unix:/var/run/php/php8.5-fpm.sock;fastcgi_read_timeout 3600;}location ~ /\.(?!well-known).* {deny all;}}Terminal window ln -s /etc/nginx/sites-available/picstome /etc/nginx/sites-enabled/nginx -t && systemctl reload nginx -
HTTPS.
Terminal window apt install -y certbot python3-certbot-nginxcertbot --nginx -d photos.yourdomain.com -
The background worker. Uploads, RAW conversion, gallery ZIPs and emails run in a queue. Without it, photos stay in processing forever.
Create
/etc/supervisor/conf.d/picstome-worker.conf:[program:picstome-worker]command=php /var/www/picstome/artisan queue:work --sleep=3 --tries=3 --max-time=3600autostart=trueautorestart=trueuser=www-datanumprocs=2stdout_logfile=/var/www/picstome/storage/logs/worker.logstopwaitsecs=3600Terminal window supervisorctl reread && supervisorctl update -
The scheduler. Expiry reminders, cleanup and pruning run on Laravel’s schedule. Add it to root’s crontab with
crontab -e:* * * * * cd /var/www/picstome && php artisan schedule:run >> /dev/null 2>&1 -
Permissions and caches.
Terminal window chown -R www-data:www-data /var/www/picstomechmod -R 775 storage bootstrap/cachephp artisan config:cachephp artisan route:cachephp artisan view:cache -
Log in. Open
https://photos.yourdomain.comwith the admin user you created and change the password immediately.
PHP settings that matter
Section titled “PHP settings that matter”Two INI values cause most self-hosting support requests. Edit /etc/php/8.5/fpm/php.ini and restart the service:
upload_max_filesize = 5120Mpost_max_size = 5120Mmax_execution_time = 3600memory_limit = 512Mupload_max_filesize also has to match client_max_body_size in Nginx. If one is smaller than the other, large uploads fail with a generic error.
For very large files, the queue worker is what actually processes them, so give PHP-FPM a generous max_execution_time and keep numprocs at 2 or more.
Using S3 storage
Section titled “Using S3 storage”Local disk works, but S3-compatible storage (AWS S3, Cloudflare R2, Hetzner, Backblaze B2, MinIO) is a better fit for photos: cheaper per GB, no disk limits and downloads served directly by the storage provider.
Set these in .env:
FILESYSTEM_DISK=s3AWS_ACCESS_KEY_ID=...AWS_SECRET_ACCESS_KEY=...AWS_DEFAULT_REGION=autoAWS_BUCKET=picstomeAWS_ENDPOINT=https://your-provider-endpointAWS_USE_PATH_STYLE_ENDPOINT=falseThen run php artisan storage:link again and upload a test photo. The bucket must be private: Picstome generates short-lived links for every download.
Updates
Section titled “Updates”There is no auto-update. A safe update, every time:
cd /var/www/picstomephp artisan downgit pullcomposer install --no-dev --optimize-autoloadernpm ci && npm run buildphp artisan migrate --forcephp artisan config:cache && php artisan route:cache && php artisan view:cachephp artisan queue:restartphp artisan upphp artisan queue:restart is not optional: workers keep the old code in memory until they restart.
Take a backup of the database and of storage/app before every update. Migrations are additive, but a backup is what turns a bad update into a bad afternoon.
Backups
Section titled “Backups”Three things to back up, in this order:
- The database —
mysqldump picstome > picstome.sqlon a schedule. storage/app— the files not in S3. If you use S3, back up the bucket separately..env— it holds the app key; without it, encrypted values are unreadable.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause |
|---|---|
| Photos stuck in processing | The queue worker is not running. supervisorctl status. |
| 500 on every page after an update | Stale caches. php artisan optimize:clear. |
| Large uploads fail | client_max_body_size or upload_max_filesize too low. |
| Emails not delivered | Set the MAIL_* variables; the default log driver writes to storage/logs. |
| Gallery download never becomes ready | Worker stopped or the archive disk is full. |
| Camera upload connects but nothing appears | The FTP inbox path or the account state; check the camera dialog. |
Logs live in storage/logs/laravel.log and storage/logs/worker.log.
Security checklist
Section titled “Security checklist”Before you invite a client:
-
APP_ENV=productionandAPP_DEBUG=false. - The admin password is not the default one.
- HTTPS is active and the HTTP version redirects.
- The database is not reachable from the internet.
-
php artisan aboutshows nolocalenvironment. - Backups run and you have restored one at least once.
We can install it for you
Section titled “We can install it for you”If all of this is not how you want to spend an afternoon, we install Picstome on your own server for €100. You keep the server, the data and the updates; we do the setup.
What the service includes:
- a fresh Ubuntu server configured with Nginx, PHP, MySQL, HTTPS and the queue worker;
- the app installed and migrated, with your admin user ready;
- storage configured (local disk or your S3 bucket);
- a test gallery uploaded and a shared link verified end to end;
- email delivery checked with a real send;
- a short handover with the credentials, the backup command and the update command.
What it does not include: the server itself, the domain, S3 costs or any third-party subscription. Write to [email protected] with the provider and the server size you have in mind.
Related
Section titled “Related”- Plans and storage — what changes between plans on app.picstome.com.
- Picstome Rater and Photo Stats — the desktop companions.
- Is Picstome up? — the hosted service status.

