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:
- Lightroom Classic — edit and export RAWs to web-sized JPEGs, same as always.
- 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.
- I run the Sigal build locally on my machine, then push the output to a GitLab repo.
- 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).


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


Other photos

