vitrine

README.md

vitrine๐Ÿ”—

A tiny read-only webserver for putting local source trees on display.

Point it at some directories via a small config file, and it serves them: markdown renders to HTML, directories become listings, and ?fmt=raw on any URL serves the file bytes directly. No javascript required, no uploads, no auth, no dynamic anything beyond rendering.

Config๐Ÿ”—

vitrine takes exactly one config file, via the required -config flag (there is no default location and no search). The format is YAML:

exhibits:
  moonshot-1:
    path: moonshot-1
  meta/research/some-topic:
    path: ../elsewhere/some-topic
  some-repo:
    path: ../src/some-repo
    expose-git: true
  • exhibits maps URL prefixes to directories. A prefix may contain slashes; the intermediate URL levels then serve synthetic listings that reveal only the mounted subtrees.
  • path (required) is the directory to serve. Relative paths resolve against the config file's directory, which makes a config portable alongside the trees it describes. Absolute paths also work.
  • expose-git (optional, default false): see below.

A bad config (parse error, unknown key, missing path, or zero exhibits) is a startup error: vitrine refuses to run rather than serve the wrong thing.

expose-git๐Ÿ”—

By default, .git directories are invisible: hidden from listings and unreachable by direct URL.

Setting expose-git: true on an exhibit flips that: .git lists and serves like any other directory, which makes git clone http://host/exhibit/.git work over git's dumb HTTP transport.

Two caveats, read them before enabling:

  • vitrine writes into that exhibit's .git. Dumb-HTTP clone requires .git/info/refs and .git/objects/info/packs, and ordinary commits never maintain them, so vitrine runs git update-server-info on the exhibit at startup. This is a deliberate exception to vitrine's otherwise strictly read-only stance.
  • Dumb HTTP has dumb semantics. Clones reflect the refs as of the last update-server-info run, so commits made after vitrine started are invisible to clones until it next runs (currently: restart vitrine). A stale clone succeeds silently at the old tip; there is no warning. Concurrent git gc in the exhibit can also break an in-flight clone (loudly; retry works).

Deployment๐Ÿ”—

Run vitrine as your own user, under a systemd user unit. No root anywhere.

  1. Build and install the binary somewhere on your user's path:

    go build -o ~/bin/vitrine .
    
  2. Write your config, e.g. ~/fusion/.vitrine.cfg, with paths relative to that directory (see Config above).

  3. Install the unit file from this repo as a user unit:

    mkdir -p ~/.config/systemd/user
    cp vitrine.service ~/.config/systemd/user/
    systemctl --user daemon-reload
    systemctl --user enable --now vitrine
    

    Adjust ExecStart in the unit if your binary or config live elsewhere.

  4. Keep it running after logout (user units otherwise stop with your session):

    loginctl enable-linger $USER
    

Check on it with systemctl --user status vitrine and journalctl --user -u vitrine -f.

README.md ยท 3.1 KiB ยท ac8aaa4b70