pkgdepot is an Arch Linux package repository server.
Download the Linux/amd64 archive from GitHub Releases, or build the CLI from source with Go 1.27:
go build -o pkgdepot ./cmd/pkgdepotUse this host-side CLI for delegated login and repository management. Do not run delegated login inside the server container: its loopback callback and OS credential store are normally unavailable to the host browser.
Non-loopback deployments require HTTPS. Configure the identity provider before
starting the server, and ensure its discovery and signing-key endpoints are
reachable from the container. Save the following as compose.yaml, replacing
the example host and issuer URLs:
services:
pkgdepot:
image: ghcr.io/trly/pkgdepot:latest
environment:
PKGDEPOT_URL: https://packages.example.com
PKGDEPOT_OIDC_ISSUER: https://id.example.com
volumes:
- pkgdepot-data:/var/lib/pkgdepot
caddy:
image: caddy:2
depends_on:
- pkgdepot
ports:
- "80:80"
- "443:443"
command: caddy reverse-proxy --from packages.example.com --to pkgdepot:8080
volumes:
- caddy-data:/data
- caddy-config:/config
volumes:
pkgdepot-data:
caddy-data:
caddy-config:docker compose up -dThe container includes the Arch repository tools required for package mutations.
For a non-container server, install /usr/bin/repo-add and
/usr/bin/repo-remove; pkgdepot does not use substitutes from PATH.
PKGDEPOT_URL may include a path, such as https://packages.example.com/pkgdepot.
Configure the reverse proxy to remove that prefix before forwarding requests to
pkgdepot. Use the same prefix in pacman URLs. The OAuth protected-resource
metadata stays at the origin's /.well-known/oauth-protected-resource path.
pkgdepot is an OAuth 2.0 protected resource. Package and repository lists are public; every mutation requires its operation scope:
| Mutation | Required scope |
|---|---|
| Publish a package | package:publish |
| Remove a package | package:remove |
| Create a repository | repo:create |
| Remove a repository | repo:remove |
| Rename a repository | repo:rename |
The identity provider must provide OIDC discovery and signing keys, issue signed
RFC 9068 access tokens, and support the OAuth resource parameter. Delegated
login uses authorization code with S256 PKCE. It can use pkgdepot's Client ID
Metadata Document (CIMD) on an HTTPS deployment, or a pre-registered public
client specified with PKGDEPOT_OAUTH_CLIENT_ID. Pre-registered clients must
allow these loopback callbacks:
http://127.0.0.1/oauth/callback
http://[::1]/oauth/callback
The CLI selects IPv4 or IPv6 and binds an ephemeral port for each login. Do not register fixed ports; the provider matches these loopback redirect URIs with a variable port.
Authorization is controlled by the identity provider's client restrictions and resource scopes. pkgdepot publishes two CIMD clients:
| Client | CIMD client ID path | Intended group | Scopes |
|---|---|---|---|
| Publisher | /oauth/clients/cli-publisher |
pkgdepot publishers |
package:publish |
| Admin | /oauth/clients/cli-admin |
pkgdepot administrators |
All mutation scopes |
Restrict each client to its corresponding provider group. pkgdepot does not
read user roles or map role claims; a validated access token with the requested
operation scope is authorized. The token audience remains the canonical
PKGDEPOT_URL, not either CIMD client ID.
Delegated login requires an OS credential store for the cached token. For an HTTPS deployment with a provider that supports CIMD:
export PKGDEPOT_URL=https://packages.example.com
pkgdepot login --access admin --scope repo:create --scope package:publish
pkgdepot repo create stable
pkgdepot package publish stable ./example-1.0-1-x86_64.pkg.tar.zstThe CLI opens one authorization URL for the selected access profile. Pocket ID
performs authentication and displays the requested permissions. --access
selects the CIMD client, either publisher or admin; it defaults to
publisher. --scope selects the operation permissions requested from that
client and may be repeated. Without --scope, publisher login requests
package:publish, while admin login requests all scopes advertised by the
protected resource. Publisher access cannot request administrative scopes such
as package:remove; use --access admin explicitly. Run pkgdepot logout to
delete cached delegated tokens. For a provider without CIMD, set
PKGDEPOT_OAUTH_CLIENT_ID to a registered client ID before login. For the
default local HTTP URL, a pre-registered client ID is always required.
For headless or containerized automation, configure a confidential client. The client needs an ID, secret, issuer pin, and the required operation scopes:
PKGDEPOT_URL=https://packages.example.com \
PKGDEPOT_OAUTH_ISSUER=https://id.example.com \
PKGDEPOT_OAUTH_CLIENT_ID=<client-id> \
PKGDEPOT_OAUTH_CLIENT_SECRET=<client-secret> \
pkgdepot package publish stable ./example-1.0-1-x86_64.pkg.tar.zstThe provider must support client_secret_basic and grant the required operation
scope. Client credentials apply to all mutation commands and cannot use
pkgdepot login.
To use Pocket ID with client credentials:
- Create a
pkgdepotAPI whose resource is the exact publicPKGDEPOT_URL. - Add the required operation scopes, such as
package:publishandpackage:remove. - Create a confidential OIDC client and grant its API access under Client access.
- Start pkgdepot with the Pocket ID issuer.
- Configure the CLI with the confidential client credentials as shown above.
PKGDEPOT_URL=https://packages.example.com \
PKGDEPOT_OIDC_ISSUER=https://id.example.com \
pkgdepot serve--url uses PKGDEPOT_URL and defaults to http://127.0.0.1:8080.
--architecture defaults to x86_64.
# Public JSON lists
pkgdepot repo list
pkgdepot package list stable
# Protected repository lifecycle operations
pkgdepot repo create stable
pkgdepot repo rename stable production
pkgdepot repo remove production
# Protected package operations
pkgdepot package publish stable ./example-1.0-1-x86_64.pkg.tar.zst
pkgdepot package publish --signature ./example-1.0-1-x86_64.pkg.tar.zst.sig stable ./example-1.0-1-x86_64.pkg.tar.zst
pkgdepot package remove stable examplePublishing creates the repository and architecture directory if needed, so an
explicit repo create is optional. --signature stores a detached signature
alongside the package as <package filename>.sig; pkgdepot does not verify it.
repo remove recursively deletes every architecture, package, signature, and
database in that repository. package remove deletes the package, its detached
signature, and its database entry. repo rename rebuilds a copy under the new
name; packages published concurrently may not appear in that snapshot.
For a repository named stable, use the same name for the pacman section so
pacman requests stable.db:
[stable]
Server = https://packages.example.com/repos/stable/$archFor a path-prefixed resource URL, include the prefix:
[stable]
Server = https://packages.example.com/pkgdepot/repos/stable/$archsudo pacman -Syu example| Variable | Default | Description |
|---|---|---|
PKGDEPOT_ADDRESS |
:8080 |
Server bind address. |
PKGDEPOT_APP_NAME |
PKGdepot |
Name shown in the web interface. |
PKGDEPOT_DATA_ROOT |
/var/lib/pkgdepot |
Repository, staging, and lock storage root. |
PKGDEPOT_URL |
http://127.0.0.1:8080 |
Canonical public resource URL. |
PKGDEPOT_MAX_UPLOAD_SIZE |
524288000 |
Maximum complete multipart upload request size in bytes. |
PKGDEPOT_HTTP_TIMEOUT |
30s |
Read, write, and idle timeout. |
| Variable | Default | Description |
|---|---|---|
PKGDEPOT_OIDC_ISSUER |
Required | Trusted OIDC issuer URL. |
PKGDEPOT_OIDC_AUDIENCE |
PKGDEPOT_URL |
Expected access-token audience. |
PKGDEPOT_OIDC_JWT_ALGORITHMS |
RS256 |
Allowed access-token signing algorithms. |
PKGDEPOT_OIDC_JWT_CACHE_LIFETIME |
15m |
Maximum signing-key-set trust lifetime. |
| Variable | Default | Description |
|---|---|---|
PKGDEPOT_OAUTH_CLIENT_ID |
Empty | Required for client credentials and delegated clients without CIMD. HTTPS delegated clients with CIMD derive the publisher or admin CIMD URL. |
PKGDEPOT_OAUTH_CLIENT_SECRET |
Empty | Enables client-credentials authentication; omit for delegated login. |
PKGDEPOT_OAUTH_ISSUER |
Required with a client secret | Expected issuer pin before credentials are sent. |
PKGDEPOT_OIDC_* configures the server; PKGDEPOT_OAUTH_* configures the CLI.
Go 1.27 is required. Build and test without Arch Linux or pacman tools:
go test ./...
go vet ./...To seed a local instance from an existing pkgdepot repository, set the data root and run the bootstrap script with the source origin, repository name, and architecture. The destination must not already exist:
PKGDEPOT_DATA_ROOT=/tmp/pkgdepot \
./scripts/bootstrap-repository.sh \
https://packages.trly.dev stable x86_64The script downloads <repository>.db.tar.gz and every package named by that
database into repositories/<repository>/<architecture>. It expects the
source repository at /repos/<repository>/<architecture>.
Run real local package mutations only on a system that supplies
/usr/bin/repo-add and /usr/bin/repo-remove.