In the spirit of cgit, with a sourcehut-style look. One Go binary with its templates and CSS embedded. Pages need no JavaScript.
It is meant for a personal git server: you push over SSH, and everyone else can browse and clone over HTTPS. It is not a forge: there are no accounts, issues or pull requests.
- index
- activity
- about
| Name | Description | Owner | Idle |
|---|---|---|---|
| spinney | A read-only web viewer for git | you | 2 hours |
| dotfiles | Shell, editor and terminal setup | you | 3 days |
| tools | |||
| tools/backup | Nightly snapshots to object storage | tools | 1 week |
| tools/notes | Markdown notes with images | tools | 1 month |
What it does
Browse
An index of every repository, grouped by folder. Summaries with the
README, trees with syntax highlighting, rendered markdown, raw files,
blame, history, commits with diffs and .patch downloads,
refs and tarballs.
Clone
Anything public clones over HTTPS with git's smart HTTP protocol. Pushing over HTTP is never possible: spinney has no write path at all.
Push
Over SSH to a locked-down git account that runs
nothing but git. Pushing to a name that doesn't exist yet creates the
repository.
Deploy
One command from your own machine sets up spinney, HTTPS, bot protection, pushing and a hardened server, optionally with SSH on a private Tailscale network.
Feeds and activity
Atom feeds of commits and tags for every repository, and an optional activity tab with a year of commits as a GitHub-style graph.
Themes
Light and dark colour themes (GitHub, Ayu, Night Owl, Catppuccin) or your own, and Google Fonts that spinney downloads and serves itself, so visitors never contact Google.
Private repositories
ssh gitserver private NAME on takes a repository off
the web site within 15 seconds. Over SSH you push and fetch as
usual.
Mirrors
Follow repositories hosted elsewhere under [mirrors].
Visitors browse them here and are pointed to the upstream to
clone.
Try it locally
The demo needs only Go and git, and works on Linux, macOS and Windows.
# sample repositories in demo/repos go run ./demo # http://127.0.0.1:8080 go run . -config demo/spinney.toml
The demo has a C project with releases, merges and branches, a
.dotfiles repository with symlinks, markdown notes with images,
a nested repository, an empty one, and one hidden by the config.
To serve your own folder of repositories:
go build ./spinney -root ~/src -listen 127.0.0.1:8080
Deploy
From the spinney folder on your machine, with Go and SSH access to the server:
./install.sh root@git.example.com
It asks a few questions; the defaults are the most secure choices. It builds spinney for the server, uploads it and installs:
internet --> Caddy :443 (HTTPS) --> Anubis (bot check) --> spinney 127.0.0.1:8080 you --> SSH (over Tailscale) --> git account (git-shell) --> /srv/git
Before finishing it checks that a fresh SSH login and pushing still
work, and undoes the SSH changes if they don't. Later,
./install.sh … --yes re-deploys with the same answers.
Who can reach what
| No hardening | --harden | --harden --tailscale | |
|---|---|---|---|
Web site and git clone over HTTPS | Internet | Internet | Internet |
| Push over HTTP | Never | Never | Never |
| Push over SSH | Internet, push keys only | Internet, push keys only | Tailnet only, push keys only |
| Admin SSH logins | The system's own sshd settings | Keys only, listed accounts only | Tailnet only, keys only |
| Other ports | Firewall left as it is | Blocked | Blocked from the internet |
| spinney and Anubis | This machine only | This machine only | This machine only |
Day to day
The git account runs a handful of commands and nothing
else: no shell, no terminal, no port forwarding.
ssh gitserver list # all repositories, private ones marked ssh gitserver create NAME [description] # an empty repository ssh gitserver create NAME --private # one that stays off the web site ssh gitserver edit-desc NAME "New text" # set its description ssh gitserver private NAME on # take it off the web site
By default the server refuses force-pushes and deleted branches, and checks every pushed object.
Documentation
| Deploying | Putting it on a server, from a fresh VPS to a hardened setup with backups |
| Using | Day to day: cloning, pushing, pulling, new repositories, a short SSH name for the server |
| Configuration | Every setting in config/spinney.toml |
| Customising | Themes, your own colours and fonts, step by step |
| Security | How the server is protected, layer by layer |
| Development | Running and testing it on your own machine, including Windows |
spinney