2.8 KiB
2.8 KiB
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 servespublic/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 - Templates —
html/template, embedded viaembed.FS - Images — centre-crop to square, Catmull-Rom resize to 600×600 JPEG thumbnails
- Feed — Atom (
encoding/xml) - NixOS —
flake.nix+module.nix, exportsnixosModules.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