Building a Self-Hosted Photo Gallery: Sigal + GitLab + Cloudflare Pages


I got back from Croatia with a few hundred keepers — travel shots, my first real astrophotography session, some wildlife stuff I got lucky with — and nowhere good to put them. Lightroom’s web export is fine but ugly and a pain to update. SaaS galleries mean a monthly fee for the privilege of someone else hosting my own photos. So I built my own pipeline instead, and it ended up simpler than I expected once I stopped overthinking it.

The Pipeline

Nothing fancy here, which is kind of the point:

  1. Lightroom Classic — edit and export RAWs to web-sized JPEGs, same as always.
  2. Sigal — a Python static site generator made specifically for photo galleries. Point it at a folder of images, it spits out thumbnails, albums, and a full static site.
  3. I run the Sigal build locally on my machine, then push the output to a GitLab repo.
  4. Cloudflare Pages is connected to that repo and auto-deploys on every push. No CI step, no build server — I build, I push, Cloudflare grabs it and it’s live on photos.olehsheremeta.com a minute later.

That’s it. No backend, no database, nothing running that I have to babysit. The only “infrastructure” is a folder of static files and a CNAME record. Building locally instead of in CI also means I get to actually look at the output before it goes anywhere — if a thumbnail looks wrong or an album’s out of order, I catch it on my own machine instead of debugging it after it’s already live.

Problems Along the Way

Some Sigal themes don’t show all the photos in the gallery preview. A few albums looked like they were missing images when really the theme was just silently dropping some thumbnails from the grid view — the photos were there, the theme just wasn’t rendering all of them. Took some digging through theme templates to figure out it wasn’t a build issue on my end, it was the theme itself being selective about what it displayed.

JPEG made the output too big, so I switched to WebP. With a few hundred images plus Sigal’s generated thumbnails, JPEG file sizes added up fast enough to make the repo and the deploy noticeably heavier than I wanted. WebP gave me roughly the same visual quality at a meaningfully smaller size, so I switched the export format and the size problem mostly went away.

Neither issue was a big deal once I knew what I was looking at.

Why This Stack

Static over dynamic because a photo gallery doesn’t need a backend — it needs to load fast and not break. Sigal because it’s free, it’s just files, and I can restyle it later without being locked into anyone’s platform. Cloudflare Pages because free hosting that auto-deploys off a git push is hard to beat for something this low-stakes.

The Photos

Astrophotography

It was my first time trying astrophotography, but thanks to my brand new f/1.8 35mm lens, it turned out pretty well. For the setup, I just placed the camera on the ground pointing straight up so it wouldn’t move, and used an IR remote (a neat, dirt-cheap accessory from AliExpress) to trigger the shutter. I opened the aperture to its max of f/1.8, set a 15–20” shutter speed, and dialed in a high ISO between 1600 and 3200 (making sure to disable auto ISO).

Astrophotography 1

Astrophotography 2

Tortoise and blackbird

While strolling around town, I crossed paths with some of the local Croatian wildlife and managed to capture these moments.

Tortoise

Blackbird

Other photos

Astrophotography 2

Astrophotography 2