Self Hosted Photo Albums With Piwigo
(Updated: )
After setting up my nextcloud instance (vanwerkhoven.org), I set out to organize my photo albums online. I had been using Apple’s excellent shared photo albums before, but I prefer to have my photos on my own devices. I settled for Piwigo (piwigo.org) which was fairly easy to set-up and use, and has similar viewing experience as Apple’s version.
Update September 2021: I migrated to a new setup using pigallery2 (github.io), which is even easier. See my guide and considerations here (vanwerkhoven.org).
Requirements ¶
I was looking to have a similar experience as commercial/cloud albums, meanning:
- Can be self-hosted ~easily
- Has an app to upload images for at least iOS
- Has a nice album viewing interface
- Must support photos and videos
- Supports private albums accessible via unique token-URLs
Alternatives ¶
- Nextcloud (nextcloud.com):
- pros: has an app, already installed, supports shared folders
- con: album layout not my preference
- Piwigo (piwigo.org):
- pro: has an app, nice album layout, supports sharing via unique links
- con: not available via apt
- Zenphoto (zenphoto.org):
- pro: has an app
- con: album layout not my preference
Setting up Piwigo ¶
- Get source, unzip to
/var/www/piwigo
,chown www-data:www-data
- Set-up virtualhost
- Create virtualhost nginx
- Add subdomain to SSL certificate
sudo certbot certificates
sudo certbot certonly --http-01-port 9080 --cert-name <certname> -d <domain1>,<domain2>,<domain3>
- Choose option 1 - nginx-based verification
- Create MySQL database user (linuxize.com)
- Generate password
mkpwd -t 2 -n 30 -m 30
sudo mysql
CREATE USER 'piwigo'@'localhost' IDENTIFIED BY 'xuRroMzYn4lySHCDAh3H';
CREATE DATABASE piwigo;
GRANT ALL PRIVILEGES ON piwigo.* TO 'piwigo'@'localhost’;
SHOW GRANTS FOR 'piwigo'@'localhost’;
- Generate password
- Install piwigo via web interface
- Add extensions
- Configure piwigo
- Add ‘administrator’ users for photo uploading via app
- Get app, upload photos
Compressing videos as well ¶
While piwio nicely creates various compressions for photos, piwigo-videojs does not (github.com). Since the viewers of my albums don’t need the full resolution, I’ve hacked together a solution to compress videos as well outside piwigo’s environment based on watching changes in the directory with inotifywait (stackoverflow.com).
- Get ffmpeg with HW accel (jellyfin.org) in my case via Intel QuickSync (QSV)
- Make
inotifywait
watcher script that converts when files are moved into upload dir. Note that files initially are uploaded to aupload/buffer/
dir, and from there moved into the repository named by year. By watching only the repository, we will not trigger on moves being uploaded toupload/buffer/
.We only watch the current year as not to overflow inotifywait (debian.org), hence this requires a reboot on January first :) (xkcd.com)I decided to watch all directories of the current century, as the defualt limit of 8192 watched directories is enough for 8192/2/365 = 11 years.#!/bin/bash WATCHDIR=/var/www/photos/upload/$(date +%C)* inotifywait --quiet -e MOVED_TO --monitor --recursive "${WATCHDIR}" | while read line do # line == <dir> <event> <filen>, e.g. /var/www/photos/upload/2021/02/04/ MOVED_TO 20210204135704-a4e62c48.jpg echo "triggered " $line params=($line) thisfilepath="${params[0]}${params[2]}" mime=$(file --brief --mime-type "${thisfilepath}") # For any video, try to compress using ffmpeg. This might misfire in case of # low-quality videos which are upscaled, but that's unlikely/impossible in my use case if [[ "${mime}" =~ ^video/ ]]; then echo "video triggered " $mime # For this video, we need to: # 1. Compress it: $file to ${thisfilepath}-x264_aac.mp4 # 2. Replace it without moving: cp ${thisfilepath}-x264_aac.mp4 $file && rm ${thisfilepath}-x264_aac.mp4 # which shouldn't trigger ourself nice ffmpeg -hide_banner -nostdin -nostats -loglevel error -i "${thisfilepath}" -profile:v high -level 4.0 -pix_fmt yuv420p -c:v libx264 -preset slower -movflags use_metadata_tags -crf 28 -vf "scale='iw*min(1,sqrt(1280*720/ih/iw)):-2" -c:a aac -vbr 3 -threads 0 -y "${thisfilepath}-x264_aac.mp4" cp "${thisfilepath}-x264_aac.mp4" "${thisfilepath}" && rm "${thisfilepath}-x264_aac.mp4" echo "video conversion done" fi done
- Start script on reboot using e.g. cron (crude but works)
sudo crontab -u www-data -e @reboot /var/www/photos/videowatcher.sh
- Test
sudo su - www-data -s /bin/bash -c '/var/www/photos/videowatcher.sh' sudo killall videowatcher.sh