4 min read

Continuous Photo Deployment

How to keep photos alive
Continuous Photo Deployment

After pressing the shutter button, photos nowadays first end up on an SD card and then on a hard drive (either at home or in the cloud). Most of them are left there until they are eventually deleted or forgotten, without ever having received any special attention from a human being. There are many reasons for this unfortunate state of affairs:

  • There are too many photos and each photo gets buried in the masses
  • Deeply nested folder structures that only reveal the date of creation diminish any desire to engage with the photos
  • Access to the photos is limited to very few people
  • Viewing photos is fraught with hurdles, such as having to boot up a PC and connect an external hard drive

All these reasons also once applied to my photo collection, consisting of over 77,000 individual snapshots. I was dissatisfied with this situation. My solution consisted of several components. If you combine them, you can even build a kind of continuous deployment for a public photo gallery. But more about that later.

1. External HDD → NAS

missing
My TrueNAS system

My first step was to move my photos from my external hard drive to a NAS. Having the photos on the NAS is like having an external hard drive that you take a snapshot of once at night, that you connect to any device on your home network at the same time, and that stays connected all the time.

2. Nextcloud

missing
My nextcloud photo folders

By integrating the photos into Nextcloud, I took another hurdle. From now on, I was able to share the photos with anyone I wanted. Just create a link and send it. However, viewing and discovering old photos remained cumbersome, as you still had to fight your way through the entire folder structure.

2. Photoprism

missing
Photoprism gallery

In addition to Nextcloud, I use Photoprism on the same data to get a web-based gallery view of my photos. The software indexes my photos, creates previews, calculates and estimates geo-data, and runs a classification model on the photos to assign tags and recognize people. When using the Photoprism gallery, it now doesn't matter which folder a photo is in. You can scroll through your feed lost in thought and get inspired by old photos, but also just search directly for a person or a tag to find old photos specifically again. In addition, albums can be created that can even survive a complete deletion of the Photoprism database, as they are stored in sidecar files on the hard drive.

3. Photostream

missing
This is how my photo-stream looks like

The photo feed, originally developed by maxvoltar, is a theme for the static site generator Jekyll written in Ruby.

Since the Jekyll version took an incredibly long time to generate the page for many photos and there were many problems with the exif data I used for sorting, I switched to Hugo. Someone already created a theme for this as well, which I forked and customized to my needs. → Github: photo-stream
I have also published my Hugo files → Github: photo-stream-hugosite. It can be deployed with the docker-compose.yml:

version: "3"
services:
  app:
    image: klakegg/hugo:ext-alpine
    command: server
    user: "33:33"
    volumes:
      - "/data/photo-stream/photo-stream-hugosite:/src"
    restart: unless-stopped
    networks:
      - traefik
    environment:
      - HUGO_ENV=production
      - GITHUB_USERNAME=
      - INSTAGRAM_USERNAME=
      - MASTODON_SERVER=
      - MASTODON_USERNAME=
      - ALLOW_ORDER_SORT_CHANGE=1
      - ALLOW_IMAGE_SHARING=1
    entrypoint: "hugo-official server --bind=0.0.0.0 --baseURL=https://photos.example.com/ --appendPort=false --disableFastRender"
    labels:
      - traefik.enable=true
      - traefik.http.routers.photo-stream.entrypoints=websecure
      - traefik.http.routers.photo-stream.rule=Host(`photos.example.com`)
      - traefik.http.routers.photo-stream.tls.certresolver=myresolver

networks:
  traefik:
    external: true

4. Continuous Photo Deployment

To avoid having to manually add new photos to the Hugo page and then trigger the rebuild, I wrote a microservice that automates the whole thing. I use an album at Photoprism as source for the photos. The microservice wades through the album file from Photoprism, downloads the new photos every time a change is made, deletes photos that are no longer in the album, and then triggers a rebuild of the Hugo page. → Github: photoprism-album-sync

Updating the Photostream page thus needs only one action on my part: adding or removing photos from the Photoprism album.

https://photos.valentinriess.com