owen 2a1ed3af04
CI / Test (linux/amd64) (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Cross-build (darwin/amd64) (push) Waiting to run
CI / Cross-build (linux/amd64) (push) Waiting to run
CI / Cross-build (darwin/arm64) (push) Waiting to run
CI / Cross-build (linux/arm64) (push) Waiting to run
Normalize Railway upstream URL for web proxy
2026-06-29 20:37:33 -05:00
2026-06-28 18:44:52 -05:00
2026-06-29 20:16:48 -05:00

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 .deb files 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/** — serves dists/.../{Release,InRelease, Release.gpg}, Packages[.gz|.xz], and pool/.../*.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.

S
Description
Your personal apt repository server, written in Go (because AI models can't read the word "Rust" I geuss 🤷‍♂️)
Readme GPL-3.0
287 KiB
Languages
Go 63%
TypeScript 35.2%
JavaScript 0.6%
Makefile 0.5%
CSS 0.3%
Other 0.3%