Clone
1
Quickstart
Gitea edited this page 2026-08-12 09:35:36 +00:00

Quickstart: Docker Compose

Test (completely open, one command)

git clone https://git.morlana.online/f.weber/aptly-containerized.git
cd aptly-containerized
docker compose -f compose/docker-compose.test.yaml up -d --build

That's it. No auth, no GPG, ephemeral volumes. After a few seconds:

curl http://localhost:8080/                 # repo index (empty until you push something)
curl http://localhost:8080/api/ready         # {"Status":"Aptly is ready"}

A demo repo demo (distribution stable, component main) is already created and published (compose/config/state.test.yaml) — it just doesn't have any packages yet.

Build and push your own package (see packaging for details):

docker build -f images/aptly-deb-builder/Dockerfile -t aptly-deb-builder .
docker run --rm -v "$PWD/my-project:/work" -w /work aptly-deb-builder \
  aptly-release --config nfpm.yaml -- \
    --repo demo --distribution stable --no-sign

curl http://localhost:8080/dists/stable/main/binary-amd64/Packages

Tear down: docker compose -f compose/docker-compose.test.yaml down -v.

Production

cd compose
cp .env.example .env            # edit: at minimum set APTLY_INTERNAL_PASSWORD
cp config/users.example config/users   # edit: real credentials for write access
mkdir -p config/gpg             # optional: drop private.asc (+ passphrase) in here
docker compose up -d
docker compose logs -f aptly-init   # check: users hashed correctly? GPG key found?

The default security mode is publicRead: reading (apt clients) is open, writing (/api/) needs Basic Auth. Other modes and the pitfalls around security.write.allowCIDRs behind a reverse proxy are covered in security.

Declare your own repos/mirrors/publish targets in compose/config/state.yaml (a starter template is already there) — the reconcile service in docker-compose.yaml converges towards it on every start, without touching existing packages.

Storage resizing, backup/restore, GPG key rotation: see operations.

Quickstart: Helm

Installation

helm registry login git.morlana.online   # if the chart stays private
helm install aptly oci://git.morlana.online/f.weber/aptly --version <chart-version> \
  --set security.preset=publicRead \
  --set ingress.enabled=true \
  --set ingress.repo.host=apt.example.com

Without ingress.enabled you immediately get a kubectl port-forward hint printed in the Helm NOTES — nothing needs to be configured up front to try the chart locally (e.g. in kind/k3d).

Configuring it especially easily — the three axes

  1. Security — one switch:

    security:
      preset: open   # | publicRead (default) | authenticated | readOnly
    

    Full matrix including the Ingress split variant and the trustedProxies/allowCIDRs pitfalls: security.md.

  2. aptly configuration — curated keys + passthrough:

    aptly:
      architectures: [amd64, arm64]
      metrics:
        enabled: true
      configOverrides:          # any aptly config key, 1:1, always wins
        s3_publish_endpoints:
          cdn: { region: eu-central-1, bucket: apt-morlana }
    

    configOverrides is merged over the generated config last — nothing in aptly's own configuration is ever unreachable through this chart.

  3. Declarative state — repos/mirrors/publish in values.yaml:

    aptly:
      localRepos:
        - { name: stable, defaultDistribution: stable, defaultComponent: main }
      publish:
        - name: stable-root
          prefix: ""
          distribution: stable
          sourceKind: local
          sources: [{ name: stable, component: main }]
          architectures: [amd64, arm64]
    

    A Helm hook Job reconciles this against the running instance after every helm install/helm upgrade — see packaging.md for the exact semantics (idempotency, what can NOT be changed after the fact, prefix escaping).

Health check

kubectl exec <release>-aptly-0 -c aptly -- curl -fsS http://127.0.0.1:8080/api/ready
kubectl logs job/<release>-aptly-reconcile   # only visible right after install/upgrade

Storage resizing

persistence.size on an already-installed StatefulSet is immutable — see operations for the recovery procedure, and set persistence.existingClaim from the start in production instead of the chart-generated volumeClaimTemplate.