Files
2026-07-02 00:53:17 +02:00

2.8 KiB
Raw Permalink Blame History

photogallery

Personal static photo gallery with Atom feed and upload API. Single-user. No database, no framework — just a Go binary that watches a directory and regenerates a static site.

Architecture

content/          # images + .toml sidecars (source of truth)
public/           # generated output (served by nginx / --serve flag)
templates/        # embedded HTML templates
static/           # embedded CSS

The binary does three things at once:

  • Watches content/ via fsnotify and rebuilds on any change
  • Serves a multipart upload API at POST /upload
  • In dev mode (--serve), also serves public/ as static files

In production nginx sits in front: serves public/ directly, proxies /upload to localhost, htpasswd on the upload endpoint.

Stack

  • Go — stdlib + BurntSushi/toml, fsnotify/fsnotify, golang.org/x/image
  • Templateshtml/template, embedded via embed.FS
  • Images — centre-crop to square, Catmull-Rom resize to 600×600 JPEG thumbnails
  • Feed — Atom (encoding/xml)
  • NixOSflake.nix + module.nix, exports nixosModules.default

Sidecar format

caption = "Tempelhof at sunrise"
date    = "2026-06-14"

Missing sidecar → filename as caption, today as date.

Design

  • Gruvbox dark hard colour scheme
  • Vollkorn (serif) for headings and captions
  • Manjari for Malayalam text (bio line)
  • 3-column square grid → 2-column on mobile
  • Single photo page with sidebar

Running locally

nix develop
go mod tidy
go run . --serve
# gallery: http://localhost:8080
# upload:  http://localhost:8080/upload

NixOS module usage

inputs.photogallery.url = "github:youruser/photogallery";
# in modules:
inputs.photogallery.nixosModules.default
# in configuration.nix:
services.photogallery = {
  enable  = true;
  baseURL = "https://photos.yourdomain.tld";
  nginx   = {
    enable       = true;
    domain       = "photos.yourdomain.tld";
    htpasswdFile = "/etc/nginx/.htpasswd-gallery";
  };
};

Bootstrap (first nix build)

go mod tidy        # generates go.sum — commit it
nix build          # fails, prints correct vendorHash
# paste hash into flake.nix
nix build          # succeeds

Key files

File Purpose
main.go Flags, wires generator + watcher + server
generator.go Scans content dir, renders HTML + Atom feed, generates thumbs
server.go Upload API + optional static file serving
watcher.go fsnotify watcher with 500ms debounce
assets.go //go:embed for templates and static
module.nix NixOS module (systemd service, tmpfiles, nginx vhost)
flake.nix buildGoModule package + devShell + nixosModules

What's not done yet

  • ActivityPub federation (planned later — start with RSS/Atom)
  • Multi-image upload
  • Delete/edit via UI
  • Any auth beyond nginx htpasswd