small local package repositories, one binary, no daemon

↓ Download for Linux x86-64, static, no dependencies · ARM, macOS, Windows and checksums

what it is

tinyrepo is a command line tool written in Go that builds small local repositories for Debian and its derivatives, and for Arch Linux / Manjaro. Pick the format with type in config.toml; the commands are the same for both.

It names the packages it wants, resolves their dependencies against the real upstream index, downloads only what that closure needs, and publishes the result over HTTP. No database, no daemon, no runtime dependencies.

quick start

$ ./tinyrepo -gc > config.toml   # example config for Debian (-ga for Arch)
$ nano config.toml               # set the mirror, the path and the packages

$ ./tinyrepo -di -ci -dp         # download indexes, build the repo, download packages
$ ./tinyrepo -ws                 # publish it over HTTP

flags

flagwhat it does
-didownload the package indexes from the mirror
-ciresolve the requested packages and build the repository
-dpdownload the packages themselves
-wsserve the repository over HTTP, until Ctrl+C
-clremove packages that config.toml does not ask for
-vpcheck that every requested package exists on the mirror
-gc / -gaprint an example config.toml for Debian / Arch
-eclist the exit codes
-pwhash a password for the web config panel, printed to stdout
-spask for a password and write it into config.toml
-gs / -grprint a systemd unit / an OpenRC service (Alpine)
-helpshow the help

on demand

By default the repository is closed: it holds exactly the packages config.toml asks for. Turn on onDemand and the published index becomes the whole upstream archive, while the disk only ever fills with what somebody actually installed — the first request for a package streams it from the mirror to the client and to disk at the same time, and its dependencies are warmed in the background.

checking the package list

-vp answers the question a typo raises: does the mirror really have this name? It reads the index -di already cached, so it costs nothing, and it exits 18 if anything is missing — straight into a CI job. The same check is a button in the web panel.

$ ./tinyrepo -di -vp
  MISSING nanoo                  nothing on the mirror answers to this name
  ok      astrometry-data-2mass  in the index

finding packages to add

The panel's available tab is the mirror's whole catalog — ~64,000 packages for a Debian suite — searchable by name or description and paged, with a button on each row that adds the name to [destination].packages. The index is parsed once and kept until it changes, so the page stays quick. Its downloaded tab answers the other question: what is on disk here.

web config panel

-ws can also publish /admin: a form that edits config.toml, buttons that run the four actions with the log of whichever is running, and the package check above. Off by default and behind a login — the password is hashed with PBKDF2-SHA256, sessions are HttpOnly and SameSite=Strict, every write carries a CSRF token, and the panel ships no JavaScript at all.

$ ./tinyrepo -sp                 # asks for a password, writes it into config.toml
$ ./tinyrepo -pw                 # ...or just prints the hash, to place by hand

-sp rewrites the one passwordHash line and leaves every comment exactly as it was. It refuses a field that is commented out — the sample configs ship it that way — and says which line to uncomment.

the package list in the panel

/admin/packages lists every package file actually in the repository — name, version, architecture, size and date — paged, filterable, and each name links to the file. On demand the repository fills with packages nobody declared, so one switch shows just those: exactly what -cl would remove. A button on each row adopts a name into [destination].packages or drops it again — which changes what the next run does, not what is on disk now.

pointing a client at it

Debian — add it to sources.list:

deb [trusted=yes] http://<host>/ tinyrepo main

Arch / Manjaro — add it to /etc/pacman.conf:

[tinyrepo]
SigLevel = Optional TrustAll
Server = http://<host>/

Neither generated repository is signed, so each one has to be trusted explicitly. Publish it on a network you control, or behind TLS: over plain HTTP these lines tell the package manager to install whatever answers. Individual pacman packages keep their upstream signature.

running it as a service

Both files are filled in from where the binary and its config.toml actually are, so there is nothing left to edit. The systemd unit is sandboxed — ProtectSystem=strict, an empty capability set, and ReadWritePaths naming only the repository directory.

$ ./tinyrepo -gs | sudo tee /etc/systemd/system/tinyrepo.service
$ ./tinyrepo -gr > /etc/init.d/tinyrepo   # alpine

get it

$ git clone https://github.com/osniel/tinyrepo
$ cd tinyrepo
$ go build -ldflags="-s -w" -o tinyrepo ./cmd/tinyrepo