urapt is a self-hostable APT repository server with a companion CLI for pushing and managing Debian .deb packages. Server (urapt-server): - REST API + APT endpoint, SQLite storage (pure-Go modernc driver, no CGO) - .deb files stored content-addressed on disk, reference-counted for dedup - Server-managed RSA-4096 OpenPGP signing key (ProtonMail/go-crypto) - APT indices (Release/InRelease/Packages[.gz/.xz]) generated on demand from the DB, cached in memory, signed with the server key - Full APT model: repositories -> distributions -> components -> architectures - Bearer-token auth for REST; HTTP Basic auth for private-repo APT reads - First registrant becomes admin; repo-scoped permissions (read/write/read-write/admin) plus owner and server-admin roles - Multipart package push with control-field extraction, list/show/delete, pool serving, blob ref-count cleanup - Audit log CLI (urapt): - register/login/logout/whoami, token management - repo/distro/component/arch CRUD, member management - push/pull/ls/show/rm for packages - apt-config helper that emits apt setup commands (key, sources.list, auth.conf for private repos) Packaging & docs: - Dockerfile (multi-stage distroless), docker-compose.yml, sample config - README quick start, architecture overview, config reference, security notes - PLAN.md design blueprint, CHANGELOG.md, GPL-3.0 LICENSE - GitHub Actions CI (test, lint, cross-build for linux/darwin amd64/arm64) - Makefile release target producing static binaries + tarballs + checksums Tests cover the data-access layer, auth/permission checks, APT index generation, .deb parsing, GPG signing, the REST API, and the typed API client. Verified end-to-end on a Raspberry Pi (arm64) pushing and installing a real package.
5.7 KiB
urapt
A self-hostable APT repository server with a companion CLI for pushing and
managing Debian/Ubuntu .deb packages under your logged-in user.
urapt gives you your own apt server: run the server, log in with the CLI,
create repositories, and push .deb files. Clients configure apt against it
and install packages normally. Packages are stored as content-addressed files
on disk; everything else lives in a SQLite database. APT indices
(Release, InRelease, Packages) are generated on demand from the database
and signed with a server-managed OpenPGP key.
Components
urapt-server(cmd/urapt-server) — the REST API + APT endpoint server.urapt(cmd/urapt) — the CLI for pushing packages and managing repos.shared/— shared utilities (config, db, models, gpg, deb parsing, apt index generation, the typed API client) used by both server and CLI.
Quick start
Run the server
make build
./urapt-server --bind 0.0.0.0:8080 --base-url https://apt.example.com
Or with Docker:
docker compose up -d # see docker-compose.yml
The server creates store/database/sqlite.db and store/packages/ on first
run and generates an RSA-4096 signing key stored in the database.
Set up the CLI
./urapt register https://apt.example.com # first account becomes admin
./urapt repo create myrepo --public
./urapt distro create myrepo stable
./urapt component create myrepo stable main
./urapt arch add myrepo stable amd64
Push a package
./urapt push myrepo stable main ./hello_1.0.0_amd64.deb
Configure apt clients
./urapt apt-config myrepo stable
This prints the exact commands to install the signing key and add the repository, for example:
curl -fsSL https://apt.example.com/api/v1/server/pubkey \
| sudo gpg --dearmor -o /usr/share/keyrings/urapt-myrepo.gpg
echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/urapt-myrepo.gpg] https://apt.example.com/apt/myrepo/ stable main' \
| sudo tee /etc/apt/sources.list.d/myrepo.list
sudo apt update
sudo apt install hello
For private repositories, apt-config also prints an
/etc/apt/auth.conf.d/... snippet using your API token as the password.
Architecture
+-------------------+ +-------------------+
| urapt (CLI) | | urapt-server |
+---------+---------+ +---------+---------+
| shared/ | shared/
v v
+---------------------------------------------+
| shared/ |
| config | db | models | gpg | deb | apt | |
| crypto | api(DTOs) | apiclient | httputil |
+---------------------------------------------+
| |
+--> SQLite <---+ store/database/sqlite.db
store/packages/<sha256>.deb (files only)
- The CLI never touches the DB or filesystem; it only talks to the REST API.
- Only uploaded
.debfiles are stored on disk (store/packages/), content- addressed by SHA-256 and reference-counted for deduplication. - APT indices are generated in memory from the DB and cached (invalidated on any mutation); they are never written to disk.
Endpoints
- REST API at
/api/v1/**— auth, users, repositories, members, distributions/components/architectures, packages. Bearer-token auth. - APT endpoint at
/apt/:repo/**— servesdists/.../{Release,InRelease, Release.gpg},Packages[.gz|.xz], andpool/.../*.deb. Public repos allow anonymous reads; private repos require HTTP Basic auth (password = API token).
Permissions
Each repository has an owner with full access. The owner can grant read,
write, read-write, or admin to other users. Only users with access can
push. Server admins can manage everything.
Configuration
Server config is loaded from defaults → TOML file (--config, default
./urapt-server.toml) → environment (URAPT_*) → flags. Key options:
| Key | Default | Notes |
|---|---|---|
bind |
0.0.0.0:8080 |
listen address |
base_url |
http://localhost:8080 |
external URL for apt-config output |
store_dir |
./store |
data directory |
signing_key_bits |
4096 |
RSA signing key size |
max_package_size |
1073741824 |
1 GiB upload limit |
open_registration |
true |
allow new account registration |
Building
Requires Go 1.22+. CGO is not required (SQLite is the pure-Go modernc
driver), so binaries are static and cross-compilable.
make build # builds urapt-server and urapt
make test # go test ./...
make vet # go vet ./...
Security notes
- Passwords are bcrypt-hashed; API tokens are random 32-byte values stored only as SHA-256 hashes (revocable, with a display prefix).
- The OpenPGP private signing key is stored unencrypted in the SQLite database. This is acceptable when you control the database file; for stronger protection, restrict file permissions and back up the DB securely. Per-repo keys and key encryption-at-rest are planned.
- For internet-facing deployments, run behind a TLS-terminating reverse proxy (Caddy/nginx). Private-repo credentials must never travel over plain HTTP.
Status
See CHANGELOG.md for release history and PLAN.md for the full design and
roadmap. Future work includes per-repo signing keys, key encryption-at-rest,
OS keychain token storage, source packages, AppStream metadata, and a web UI.
License
urapt is free software released under the terms of the
GNU General Public License v3.0 or later. See LICENSE for the
full text.