
Ein leichtgewichtiger Caching-Proxy für Paketregistries.
Ein Caching-Proxy für Paketregistrierungen. Beschleunigt Paketdownloads durch lokales Caching von Artefakten, reduziert die Bandbreitennutzung und verbessert die Zuverlässigkeit.
Die meisten Supply-Chain-Angriffe setzen auf Geschwindigkeit: Eine bösartige Version wird veröffentlicht und innerhalb von Minuten von automatisierten Pipelines konsumiert, bevor es jemand bemerkt. Die Cooldown-Funktion fügt neu veröffentlichten Versionen eine Quarantänezeit hinzu. Wenn sie aktiviert ist, entfernt der Proxy Versionen aus Metadaten-Antworten, bis sie ein konfigurierbares Alter überschritten haben.```yaml cooldown: default: "3d" # hide versions published less than 3 days ago ecosystems: npm: "7d" # npm gets a longer window cargo: "0" # disable for cargo packages: "pkg:npm/lodash": "0" # exempt trusted packages
Ein 3-Tage-Cooldown bedeutet, dass wenn `lodash` Version `4.18.0` veröffentlicht, deine Builds weiterhin `4.17.21` verwenden, bis 3 Tage vergangen sind. Sollte sich das neue Release als kompromittiert erweisen, warst du nie exponiert.
Auflösungsreihenfolge: Paket-Override, dann Ökosystem-Override, dann globaler Standard. So kannst du einen konservativen Standard festlegen und Ausnahmen für Pakete schaffen, bei denen du schnellere Updates benötigst. Siehe [docs/configuration.md](https://github.com/git-pkgs/proxy/blob/main/docs/configuration.md) für die vollständige Konfigurationsreferenz.
## Artifact Scanning
Cooldown betrachtet nur den Veröffentlichungszeitstempel einer Version — es werden niemals die tatsächlichen Bytes inspiziert. Artifact Scanning schließt diese Lücke: Wenn aktiviert, wird jedes Artefakt in den Speicher überführt und von einem oder mehreren externen Diensten (trivy, ClamAV, Wiz oder allem anderen, das einen kleinen HTTP/JSON-Vertrag spricht) gescannt, bevor es in den Cache übernommen und an Clients ausgeliefert wird.```yaml
scanning:
enabled: true
signing_key: ${PROXY_SCANNING_SIGNING_KEY}
scanners:
- name: clamav
url: http://clamav-adapter:8080/scan
mode: block # a block verdict deletes the artifact and returns 403
- name: trivy
url: http://trivy-adapter:8081/scan
mode: monitor # findings are logged, never gate caching
ecosystems: [npm, pypi]
Der Proxy lädt niemals Artefakt-Bytes zu einem Scanner hoch. Jeder Scanner wird mit Paket-Metadaten plus einer kurzlebigen signierten URL benachrichtigt; der Scanner lädt die Bytes selbst aus dem eigenen Speicher des Proxys. Scanner laufen gleichzeitig, und der erste block-Modus-Scanner, der ein Urteil „nicht erlaubt" meldet, gewinnt sofort und bricht die übrigen ab. Siehe docs/configuration.md für die vollständige Konfigurationsreferenz und den HTTP-Vertrag des Scanners.
| Registry | Sprache/Plattform | Cooldown | Abgeschlossen |
|---|---|---|---|
| npm | JavaScript | Ja | ✓ |
| Cargo | Rust | Ja | ✓ |
| RubyGems | Ruby | Ja | ✓ |
| Go proxy | Go | ✓ | |
| Hex | Elixir | Ja* | ✓ |
| pub.dev | Dart | Ja | ✓ |
| PyPI | Python | Ja | ✓ |
| Maven | Java | ✓ | |
| Gradle Build Cache | Java/Kotlin | ✓ | |
| NuGet | .NET | Ja | ✓ |
| Composer | PHP | Ja | ✓ |
| Conan | C/C++ | ✓ | |
| Conda | Python/R | Ja | ✓ |
| CRAN | R | ✓ | |
| Julia | Julia | ✓ | |
| Swift | Swift | ✓ | |
| Container | Docker/OCI | ✓ | |
| Homebrew | macOS/Linux | ✓ | |
| Debian | Debian/Ubuntu | ✓ | |
| RPM | RHEL/Fedora | ✓ | |
| Alpine | Alpine Linux | ✓ | |
| Arch | Arch Linux | ✗ |
Cooldown erfordert Veröffentlichungszeitstempel in den Metadaten. Registries ohne ein „Ja" in der Cooldown-Spalte stellen entweder keine Zeitstempel bereit oder wurden noch nicht angebunden.
* Hex-Cooldown erfordert das Deaktivieren der Registry-Signaturverifikation (HEX_NO_VERIFY_REPO_ORIGIN=1), da der Proxy die Protobuf-Nutzlast neu kodiert.
brew install git-pkgs/git-pkgs/proxy
Oder lade ein Binary von der [Releases-Seite](https://github.com/git-pkgs/proxy/releases) herunter.
### Helm
Installiere das Chart von GHCR und lege die öffentliche URL fest, die Paketmanager-Clients
verwenden werden, um den Proxy zu erreichen:```bash
helm install proxy oci://ghcr.io/git-pkgs/charts/proxy \
--set config.data.base_url=https://proxy.example.com
Das Standard-Chart stellt ein Replikat bereit, das auf einem 10 GiB persistenten Volume basiert und SQLite sowie Dateisystem-Artefaktspeicherung unter /data verwendet. Siehe
deploy/charts/proxy/values.yaml für Ingress-,
externe Datenbank- und Objektspeicher-Konfigurationsoptionen.
go build -o proxy ./cmd/proxy
./proxy
./proxy -listen :3000 -base-url https://proxy.example.com
Der Proxy läuft jetzt. Konfigurieren Sie Ihre Paketmanager so, dass sie ihn verwenden.
## OpenAPI (Swagger)
Dieses Repository verwendet swaggo, um eine OpenAPI-Spezifikation aus annotierten Handlern zu generieren.
Generieren Sie die Spezifikation:```bash
go install github.com/swaggo/swag/cmd/swag@latest
go generate ./internal/server
Generierte Dateien werden in docs/swagger/ geschrieben.
Wenn der Proxy läuft, rufe die Live-Spezifikation ab von:
http://localhost:8080/openapi.jsonOder ersetze http://localhost:8080 durch deine konfigurierte Basis-URL. Dieser Link wird auch im Dashboard angezeigt.
Erstelle oder bearbeite ~/.npmrc:```
registry=http://localhost:8080/npm/
Oder pro Projekt in `.npmrc` festlegen:```
registry=http://localhost:8080/npm/
Oder verwenden Sie die Umgebungsvariable:```bash npm_config_registry=http://localhost:8080/npm/ npm install
### Cargo
Erstellen oder bearbeiten Sie `~/.cargo/config.toml`:```toml
[source.crates-io]
replace-with = "proxy"
[source.proxy]
registry = "sparse+http://localhost:8080/cargo/"
Oder pro Projekt in .cargo/config.toml im Projektstammverzeichnis festlegen.
Legen Sie die Gem-Quelle in Ihrer Gemfile fest:```ruby
source "http://localhost:8080/gem"
Oder global konfigurieren:```bash
gem sources --add http://localhost:8080/gem/
bundle config mirror.https://rubygems.org http://localhost:8080/gem
Setzen Sie die Umgebungsvariable GOPROXY:```bash export GOPROXY=http://localhost:8080/go,direct
Oder in deinem Shell-Profil für Persistenz.
### Homebrew
Richte Homebrews JSON-API und Artefakt-Domain auf den Proxy aus:```bash
export HOMEBREW_API_DOMAIN=http://localhost:8080/homebrew
export HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080
Die Artefakt-Domain proxyt Manifeste und Bottle-Blobs unter /v2/homebrew/core/. Das GHCR-Routing ist auf dieses Repository beschränkt. Quellarchive, Cask-Anwendungsdownloads, benutzerdefinierte Tap-Artefakte und Legacy-Flat-File-Bottle-Mirrors verwenden die normalen Fallback-URLs von Homebrew. Lassen Sie den Fallback aktiviert, indem Sie HOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK nicht setzen.
Aktivieren Sie cache_metadata oder setzen Sie PROXY_CACHE_METADATA=true, um Homebrew-JSON-API-Antworten für den Offline-Fallback beizubehalten. Bottle-Blobs und ihre OCI-Manifeste werden ohne diese Einstellung zwischengespeichert.
Die Upstreams sind standardmäßig https://formulae.brew.sh/api für die JSON-API und https://ghcr.io für Artefakte. Um diesen Proxy an einen anderen Proxy anzuketten, konfigurieren Sie dessen Homebrew-Endpunkte als Upstreams:```yaml
upstream:
homebrew_api: "https://upstream-proxy.example.com/homebrew"
homebrew_artifact: "https://upstream-proxy.example.com"
Die entsprechenden Umgebungsvariablen sind `PROXY_UPSTREAM_HOMEBREW_API` und `PROXY_UPSTREAM_HOMEBREW_ARTIFACT`.
### Hex (Elixir)
Konfigurieren Sie in `~/.hex/hex.config`:```erlang
{default_url, <<"http://localhost:8080/hex">>}.
Oder setzen Sie die Umgebungsvariable:```bash export HEX_MIRROR=http://localhost:8080/hex
### pub.dev (Dart/Flutter)
Legen Sie die Umgebungsvariable PUB_HOSTED_URL fest:```bash
export PUB_HOSTED_URL=http://localhost:8080/pub
Konfigurieren Sie pip für die Verwendung des Proxys:```bash pip install --index-url http://localhost:8080/pypi/simple/ package_name
Oder in `~/.pip/pip.conf` festlegen:```ini
[global]
index-url = http://localhost:8080/pypi/simple/
Fügen Sie Folgendes zu Ihrer ~/.m2/settings.xml hinzu:```xml
proxy
central
http://localhost:8080/maven/
Der `/maven/`-Endpunkt verwendet Maven Central als primäres Upstream und fällt auf das Gradle Plugin Portal zurück für Gradle-Plugin-Marker-Metadaten und zugehörige Artefakte, wenn das primäre Upstream „not found“ zurückgibt.
Für die Gradle-Plugin-Auflösung über denselben Proxy-Endpunkt:```kotlin
pluginManagement {
repositories {
maven(url = "http://localhost:8080/maven/")
}
}
Konfigurieren in settings.gradle(.kts):```kotlin
buildCache {
local {
enabled = false
}
remote {
url = uri("http://localhost:8080/gradle/")
push = true
}
}
### NuGet
In `nuget.config` konfigurieren:```xml
<configuration>
<packageSources>
<clear />
<add key="proxy" value="http://localhost:8080/nuget/v3/index.json" />
</packageSources>
</configuration>
Oder verwenden Sie die CLI:```bash dotnet nuget add source http://localhost:8080/nuget/v3/index.json -n proxy
### Composer (PHP)
In `composer.json` konfigurieren:```json
{
"repositories": [
{
"type": "composer",
"url": "http://localhost:8080/composer"
}
]
}
Oder global festlegen:```bash composer config -g repositories.proxy composer http://localhost:8080/composer
### Conan (C/C++)
Fügen Sie den Proxy als Remote hinzu:```bash
conan remote add proxy http://localhost:8080/conan
conan remote disable conancenter
Oder konfigurieren Sie in ~/.conan2/remotes.json.
Konfigurieren Sie in ~/.condarc:```yaml
channels:
Oder per Befehl festlegen:```bash
conda config --add channels http://localhost:8080/conda/main
Legen Sie das Repository in R fest:```r options(repos = c(CRAN = "http://localhost:8080/cran"))
Oder in `~/.Rprofile` für Persistenz:```r
local({
r <- getOption("repos")
r["CRAN"] <- "http://localhost:8080/cran"
options(repos = r)
})
Legen Sie den Pkg-Server fest, bevor Sie Julia starten:```bash export JULIA_PKG_SERVER=http://localhost:8080/julia
Oder innerhalb einer laufenden Sitzung:```julia
ENV["JULIA_PKG_SERVER"] = "http://localhost:8080/julia"
using Pkg; Pkg.update()
Konfigurieren Sie den Proxy als Standard-Registry für das aktuelle Swift-Paket:```bash swift package-registry set --allow-insecure-http http://localhost:8080/swift
Registry-Abhängigkeiten verwenden ihren scoped Paketbezeichner in `Package.swift`:```swift
dependencies: [
.package(id: "apple.swift-argument-parser", from: "1.2.0")
]
Der Proxy unterstützt Abhängigkeitsauflösung und Quellcode-Downloads. Das Veröffentlichen mit
swift package-registry publish wird nicht unterstützt.
Konfigurieren Sie Docker so, dass der Proxy als Registry-Mirror in /etc/docker/daemon.json verwendet wird:```json
{
"registry-mirrors": ["http://localhost:8080"]
}
Dann Docker neu starten:```bash
sudo systemctl restart docker
Oder Images direkt pullen:```bash docker pull localhost:8080/library/nginx:latest
### Helm
Konfigurieren Sie jedes HTTP-Chart-Repository mit einem Namen und fügen Sie dann die passende Proxy-URL zu Helm hinzu:```yaml
upstream:
helm:
bitnami: "https://charts.bitnami.com/bitnami"
Ihre Anfrage konnte nicht verarbeitet werden, da kein zu übersetzender Inhalt bereitgestellt wurde. Bitte senden Sie den Markdown-Text, den Sie übersetzen möchten.```bash helm repo add bitnami http://localhost:8080/helm/bitnami helm repo update helm pull bitnami/nginx
Der Proxy cached `index.yaml` unter Verwendung der normalen Metadata-Cache-Einstellungen und
cached Chart-Archive nach der Verifizierung ihres SHA-256-Digests aus dem Index.
Für Charts, die in einer OCI-Registry gespeichert sind, konfigurieren Sie ein benanntes OCI-Upstream und fügen
das reservierte Präfix `upstream/{name}` zur Chart-Referenz hinzu:```yaml
upstream:
oci:
ghcr: "https://ghcr.io"
Ihre Anfrage konnte nicht verarbeitet werden, da kein zu übersetzender Inhalt bereitgestellt wurde. Bitte senden Sie den Markdown-Text, den Sie übersetzen möchten.```bash helm pull oci://localhost:8080/upstream/ghcr/owner/charts/mychart --version 1.0.0 --plain-http
### Debian / APT
Konfigurieren Sie APT so, dass der Proxy in `/etc/apt/sources.list.d/proxy.list` verwendet wird:```
deb http://localhost:8080/debian stable main contrib
Ersetzen Sie Ihre vorhandenen sources.list-Einträge, dann:```bash sudo apt update
Die Upstream-Voreinstellung ist `http://deb.debian.org/debian`. Um ein anderes APT-Repository (z. B. Ubuntu) zu proxen, setzen Sie `upstream.debian` in der Konfigurationsdatei oder `PROXY_UPSTREAM_DEBIAN` in der Umgebung:```yaml
upstream:
debian: "http://archive.ubuntu.com/ubuntu"
Konfigurieren Sie yum/dnf für die Verwendung des Proxys in /etc/yum.repos.d/proxy.repo:```ini
[proxy-fedora]
name=Fedora via Proxy
baseurl=http://localhost:8080/rpm/releases/$releasever/Everything/$basearch/os/
enabled=1
gpgcheck=0
Dann:```bash
sudo dnf clean all
sudo dnf update
Richten Sie /etc/apk/repositories auf den Proxy aus. Der Standard-Repository-Name
alpine leitet den offiziellen Mirror (https://dl-cdn.alpinelinux.org/alpine) weiter:```
http://localhost:8080/apk/alpine/v3.22/main
http://localhost:8080/apk/alpine/v3.22/community
Dann:```bash
apk update
Repository-Indizes (v2 APKINDEX.tar.gz und v3 Packages.adb), abgetrennte
Signaturen und Pakete werden bytegenau unverändert ausgeliefert, sodass die normale
Signaturprüfung von apk weiterhin funktioniert. Indizes verwenden den Metadaten-Cache
(metadata_ttl, Stale-Fallback); .apk-Pakete werden im gemeinsamen
Artefakt-Cache gespeichert und bleiben verfügbar, wenn das Upstream nicht erreichbar ist.
Um andere Mirrors oder private Repositories zu proxen, konfigurieren Sie benannte Upstreams
unter upstream.apk (dies ersetzt den integrierten Standard; fügen Sie alpine erneut hinzu, wenn
Sie es weiterhin möchten):```yaml
upstream:
apk:
alpine: "https://dl-cdn.alpinelinux.org/alpine"
private: "https://apk.example.com"
Ihre Anfrage konnte nicht bearbeitet werden, da kein zu übersetzender Inhalt bereitgestellt wurde. Bitte senden Sie den Text, den Sie übersetzen möchten.```
http://localhost:8080/apk/private
apk hängt die Architektur und den Index-Dateinamen selbst an jede Repository-Zeile an.
Benannte generische Upstreams konfigurieren:```yaml upstream: generic: github: "https://github.com" github-api: "https://api.github.com"
Dann schreibe die GitHub-URLs in den mise-Einstellungen um (`~/.config/mise/config.toml`, mise ≥ 2025.9.3):```toml
[settings.url_replacements]
"regex:^https://github\\.com/([^/]+)/([^/]+)/releases/download/(.+)" = "http://localhost:8080/generic/github/$1/$2/releases/download/$3"
"regex:^https://api\\.github\\.com/(.*)" = "http://localhost:8080/generic/github-api/$1"
Release-Assets werden nach dem ersten Download dauerhaft zwischengespeichert und weiterhin installiert, während GitHub nicht erreichbar ist. Tag-Lookups über api.github.com werden für metadata_ttl zwischengespeichert und während eines Ausfalls oder Rate-Limits veraltet ausgeliefert. Committe eine mise.lock und installiere mit mise install --locked, damit gepinnte Installationen überhaupt keinen API-Aufruf benötigen. Füge unter upstream.auth ein Bearer-Token für https://api.github.com hinzu, falls die Flotte das anonyme Rate-Limit von GitHub überschreitet.
Der Proxy kann konfiguriert werden über:
-config string Path to configuration file -listen string Address to listen on (default ":8080") -base-url string Public URL of this proxy (default "http://localhost:8080") -storage-url string Storage URL (file://, s3://, gs://, azblob://) -storage-path string Path to artifact storage directory (deprecated, use -storage-url) -database-driver string Database driver: sqlite or postgres (default "sqlite") -database-path string Path to SQLite database file (default "./cache/proxy.db") -database-url string PostgreSQL connection URL -log-level string Log level: debug, info, warn, error (default "info") -log-format string Log format: text, json (default "text") -access-log string Path to the JSONL access log -version Print version and exit
### Umgebungsvariablen```bash
PROXY_LISTEN=:8080
PROXY_BASE_URL=http://localhost:8080
PROXY_UI_URL=http://localhost:8080 # Optional; defaults to PROXY_BASE_URL
PROXY_STORAGE_URL=file:///var/cache/proxy/artifacts
PROXY_DATABASE_DRIVER=sqlite
PROXY_DATABASE_PATH=./cache/proxy.db
PROXY_DATABASE_URL=postgres://user:pass@localhost/proxy?sslmode=disable
PROXY_LOG_LEVEL=info
PROXY_LOG_FORMAT=text
PROXY_ACCESS_LOG_PATH=/var/log/proxy/access.jsonl
PROXY_UPSTREAM_SWIFT=https://tuist.dev/api/registry/swift
listen: ":8080" base_url: "http://localhost:8080"
storage: url: "file:///var/cache/proxy/artifacts" max_size: "10GB" # Optional: evict LRU when exceeded
database: driver: "sqlite" path: "/var/lib/proxy/cache.db"
log: level: "info" format: "text"
access_log: path: "/var/log/proxy/access.jsonl" # Optional JSONL activity log
upstream: npm: "https://registry.npmjs.org" cargo: "https://index.crates.io" swift: "https://tuist.dev/api/registry/swift"
cooldown: default: "3d"
Die [Konfigurationsreferenz](https://github.com/git-pkgs/proxy/blob/main/docs/configuration.md#upstream-registries) enthält alle Upstream-Schlüssel, Umgebungsvariablen und Standard-URLs.
Ausführen mit Konfigurationsdatei:```bash
./proxy -config /etc/proxy/config.yaml
SQLite ist der Standard und funktioniert gut für Single-Node-Deployments. Für Multi-Node-Setups oder wenn Sie eine verwaltete Datenbank bevorzugen, wechseln Sie zu Postgres:```yaml database: driver: "postgres" url: "postgres://user:password@localhost:5432/proxy?sslmode=disable"
Oder über Umgebungsvariablen:```bash
PROXY_DATABASE_DRIVER=postgres
PROXY_DATABASE_URL=postgres://user:password@localhost:5432/proxy?sslmode=disable
Der Proxy erstellt Tabellen automatisch beim ersten Start.
Der Proxy kann zwischengespeicherte Artefakte in S3 oder einem beliebigen S3-kompatiblen Dienst (MinIO, R2 usw.) anstelle des lokalen Dateisystems speichern.```yaml storage: url: "s3://my-bucket-name?region=us-east-1"
Für S3-kompatible Dienste wie MinIO:```yaml
storage:
url: "s3://my-bucket?endpoint=http://localhost:9000&disableSSL=true&s3ForcePathStyle=true"
Setzen Sie die Anmeldeinformationen über die standardmäßigen AWS-Umgebungsvariablen (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION).
Der Proxy kann zwischengespeicherte Artefakte in einem GCS-Bucket unter Verwendung des gs://-URL-Schemas speichern.```yaml
storage:
url: "gs://my-bucket-name"
Die Authentifizierung verwendet [Application Default Credentials](https://docs.cloud.google.com/docs/authentication/application-default-credentials), was bedeutet, dass keine Anmeldedaten in der Konfiguration oder Umgebung eingebettet werden müssen. Unterstützte Quellen, in dieser Reihenfolge:
- **GKE Workload Identity** — binden Sie das Kubernetes-Servicekonto, das den Proxy ausführt, an ein Google-Servicekonto, das über `roles/storage.objectAdmin` für den Bucket verfügt. Der Proxy verwendet automatisch das Token der Workload.
- **Angehängtes Servicekonto** auf GCE, Cloud Run, Cloud Functions usw.
- **`GOOGLE_APPLICATION_CREDENTIALS`**-Umgebungsvariable, die auf eine JSON-Schlüsseldatei eines Servicekontos verweist.
- **`gcloud auth application-default login`** für die lokale Entwicklung.
#### GKE Workload Identity-Einrichtung```bash
# 1. Create a Google service account
gcloud iam service-accounts create git-pkgs-proxy \
--project=PROJECT_ID
# 2. Grant it access to the bucket
gsutil iam ch \
serviceAccount:git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com:objectAdmin \
gs://my-bucket-name
# 3. Bind the Kubernetes service account to it
gcloud iam service-accounts add-iam-policy-binding \
git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"
# 4. Annotate the Kubernetes service account
kubectl annotate serviceaccount KSA_NAME \
--namespace=NAMESPACE \
iam.gke.io/gcp-service-account=git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com
Wenn direct_serve: true aktiviert ist, gibt der Proxy HTTP-302-Weiterleitungen zu vorsignierten GCS-URLs aus. Workload Identity stellt keinen privaten Schlüssel bereit, daher ruft das GCS-Backend die IAM Credentials signBlob API auf. Weisen Sie dem Dienstkonto die Token-Ersteller-Rolle für sich selbst zu:```bash
gcloud iam service-accounts add-iam-policy-binding
git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com
--role=roles/iam.serviceAccountTokenCreator
--member="serviceAccount:git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com"
## CLI-Befehle
### serve (Standard)
Startet den Proxy-Server. Dies ist der Standardbefehl, wenn keiner angegeben wird.```bash
proxy serve [flags]
proxy [flags] # same as 'proxy serve'
Den Cache aus PURLs, SBOM-Dateien oder ganzen Registries vorab befüllen. Nützlich, um die Offline-Verfügbarkeit sicherzustellen oder den Cache vor Deployments aufzuwärmen.```bash
proxy mirror pkg:npm/[email protected] pkg:cargo/[email protected]
proxy mirror pkg:npm/lodash
proxy mirror --sbom sbom.cdx.json
proxy mirror --dry-run pkg:npm/lodash
proxy mirror --concurrency 8 pkg:npm/[email protected]
Der mirror-Befehl akzeptiert dieselben Storage- und Datenbank-Flags wie `serve`. Bereits gecachte Artefakte werden übersprungen.
Eine Mirror-API ist auch verfügbar, wenn der Server läuft:```bash
# Start a mirror job
curl -X POST http://localhost:8080/api/mirror \
-H "Content-Type: application/json" \
-d '{"purls": ["pkg:npm/[email protected]"]}'
# Start a mirror job from an inline CycloneDX or SPDX JSON SBOM
curl -X POST http://localhost:8080/api/mirror \
-H "Content-Type: application/json" \
-d '{"sbom":{"bomFormat":"CycloneDX","components":[{"purl":"pkg:npm/[email protected]"}]}}'
# Check job status
curl http://localhost:8080/api/mirror/mirror-1
# Cancel a running job
curl -X DELETE http://localhost:8080/api/mirror/mirror-1
Zeigt Cache-Statistiken an, ohne den Server auszuführen.```bash
proxy stats
proxy stats -json
proxy stats -database-path /var/lib/proxy/cache.db
proxy stats -database-driver postgres -database-url postgres://user:pass@localhost/proxy
proxy stats -popular 20
Beispielausgabe:```
Cache Statistics
================
Packages: 45
Versions: 128
Artifacts: 128
Total size: 892.4 MB
Total hits: 1547
Packages by ecosystem:
npm 32
cargo 13
Most popular packages:
1. npm/lodash (342 hits, 24.7 KB)
2. npm/react (198 hits, 89.3 KB)
3. cargo/serde (156 hits, 234.1 KB)
Recently cached:
npm/[email protected] (2024-01-15 14:32, 54.2 KB)
cargo/[email protected] (2024-01-15 14:28, 412.8 KB)
| Endpunkt | Beschreibung |
|---|---|
GET / | Dashboard (Web-UI) |
GET /health | Health-Check und Upstream-Circuit-Breaker-Status (JSON; HTTP 200 gesund, 503 ungesund) |
GET /stats | Cache-Statistiken (JSON) |
GET /metrics | Prometheus-Metriken |
GET /npm/* | npm-Registry-Protokoll |
GET /cargo/* | Cargo-Sparse-Index-Protokoll |
GET /gem/* | RubyGems-Protokoll |
GET /go/* | Go-Modul-Proxy-Protokoll |
GET /hex/* | Hex.pm-Protokoll |
GET /pub/* | pub.dev-Protokoll |
GET /pypi/* | PyPI-Simple/JSON-API |
GET /maven/* | Maven-Repository-Protokoll |
GET /nuget/* | NuGet-V3-API |
GET /composer/* | Composer/Packagist-Protokoll |
GET /conan/* | Conan-C/C++-Protokoll |
GET /conda/* | Conda/Anaconda-Protokoll |
GET /cran/* | CRAN-(R)-Protokoll |
GET /julia/* | Julia-Pkg-Server-Protokoll |
GET /swift/* | Swift-Package-Registry-v1-Protokoll |
GET /helm/{repository}/* | HTTP-Helm-Chart-Repository-Protokoll |
GET /homebrew/* | Homebrew-JSON-API |
GET /v2/* | OCI/Docker-Registry-Protokoll |
GET /v2/homebrew/core/* | Homebrew-Core-Bottle-Manifeste und -Blobs von GHCR |
GET /apk/{repository}/* | Alpine-APK-Repository-Protokoll |
| Endpunkt | Beschreibung |
|---|---|
POST /api/mirror | Startet einen Mirror-Job (JSON-Body mit purls oder einem Inline-sbom) |
GET /api/mirror/{id} | Ruft Job-Status und Fortschritt ab |
DELETE /api/mirror/{id} | Bricht einen laufenden Job ab |
Der Proxy stellt REST-Endpunkte für die Anreicherung von Paketmetadaten, Vulnerability-Scanning und die Erkennung veralteter Versionen bereit.
| Endpunkt | Beschreibung |
|---|---|
GET /api/package/{ecosystem}/{name} | Ruft Paketmetadaten ab |
GET /api/package/{ecosystem}/{name}/{version} | Ruft Versionsmetadaten mit Schwachstellen ab |
GET /api/vulns/{ecosystem}/{name} | Ruft alle Schwachstellen für ein Paket ab |
GET /api/vulns/{ecosystem}/{name}/{version} | Ruft Schwachstellen für eine bestimmte Version ab |
POST /api/outdated | Prüft mehrere Pakete auf veraltete Versionen |
POST /api/bulk | Massenabfrage von Paketmetadaten |
I can't translate this chunk because no source content was included. The INPUT section is empty — there's no Markdown text to translate.
Please paste the actual chunk 143 content (the English Markdown text), and I'll return the German translation following all the rules you specified.```json
{
"ecosystem": "npm",
"name": "lodash",
"latest_version": "4.17.21",
"license": "MIT",
"license_category": "permissive",
"description": "Lodash modular utilities",
"homepage": "https://lodash.com/",
"repository": "https://github.com/lodash/lodash",
"registry_url": "https://registry.npmjs.org"
}
(empty)```json
{
"package": {
"ecosystem": "npm",
"name": "lodash",
"latest_version": "4.17.21",
"license": "MIT",
"license_category": "permissive"
},
"version": {
"ecosystem": "npm",
"name": "lodash",
"version": "4.17.0",
"license": "MIT",
"published_at": "2016-06-17T03:59:56Z",
"yanked": false,
"is_outdated": true
},
"vulnerabilities": [
{
"id": "GHSA-p6mc-m468-83gw",
"summary": "Prototype Pollution in lodash",
"severity": "HIGH",
"cvss_score": 7.4,
"fixed_version": "4.17.12"
}
],
"is_outdated": true,
"license_category": "permissive"
}
curl -X POST http://localhost:8080/api/outdated
-H "Content-Type: application/json"
-d '{
"packages": [
{"ecosystem": "npm", "name": "lodash", "version": "4.17.0"},
{"ecosystem": "pypi", "name": "requests", "version": "2.25.0"}
]
}'
I can't translate this chunk because the INPUT section is empty — no source text was included after "INPUT:".
Please paste the actual Markdown content for chunk 151/189 and I'll return the German translation, preserving all structure and leaving code, paths, URLs, and identifiers untouched.```json
{
"results": [
{
"ecosystem": "npm",
"name": "lodash",
"version": "4.17.0",
"latest_version": "4.17.21",
"is_outdated": true
},
{
"ecosystem": "pypi",
"name": "requests",
"version": "2.25.0",
"latest_version": "2.31.0",
"is_outdated": true
}
]
}
curl -X POST http://localhost:8080/api/bulk
-H "Content-Type: application/json"
-d '{
"purls": [
"pkg:npm/[email protected]",
"pkg:pypi/[email protected]"
]
}'
I need the actual content to translate. You've provided the instructions and metadata, but the INPUT section is empty — there's no Markdown text following "INPUT:".
Please paste the chunk 155 content you want translated from English to German, and I'll return only the translated Markdown.```json
{
"packages": {
"pkg:npm/lodash": {
"ecosystem": "npm",
"name": "lodash",
"latest_version": "4.17.21",
"license": "MIT",
"license_category": "permissive"
},
"pkg:pypi/requests": {
"ecosystem": "pypi",
"name": "requests",
"latest_version": "2.31.0",
"license": "Apache-2.0",
"license_category": "permissive"
}
}
}
{ "cached_artifacts": 142, "total_size_bytes": 523456789, "total_size": "499.2 MB", "storage_url": "file:///path/to/cache/artifacts", "database_path": "./cache/proxy.db" }
## Funktionsweise
1. Der Paketmanager fordert Paketmetadaten vom Proxy an
2. Der Proxy ruft die Metadaten vom Upstream ab und schreibt die Artefakt-URLs so um, dass sie auf den Proxy verweisen
3. Der Paketmanager fordert das Artefakt an (Tarball, Crate usw.)
4. Der Proxy prüft den lokalen Cache:
- **Cache-Treffer**: Aus dem lokalen Speicher bereitstellen
- **Cache-Fehltreffer**: Vom Upstream abrufen, lokal speichern, an den Client ausliefern
5. Nachfolgende Anfragen für dasselbe Artefakt werden aus dem Cache bedient```
┌─────────────┐ ┌─────────┐ ┌──────────┐
│ npm/cargo │────▶│ proxy │────▶│ upstream │
│ client │◀────│ │◀────│ registry │
└─────────────┘ └─────────┘ └──────────┘
│
▼
┌─────────┐
│ cache │
│ storage │
└─────────┘
Der Proxy stellt eine Web-UI unter /ui bereit. Es ist kein separates Frontend-Build erforderlich -- Templates und Assets sind in die Binärdatei eingebettet. GET / leitet auf /ui/ weiter. Die UI ist unter ihrem eigenen Präfix eingebunden, sodass ein Reverse-Proxy unterschiedliche Zugriffsregeln darauf anwenden kann als auf die Paket-Endpunkte (zum Beispiel Authentifizierung für PathPrefix(/ui) verlangen, während /npm, /pypi usw. für Build-Maschinen offen bleiben).
/ui/) -- Cache-Statistiken, beliebte Pakete, kürzlich gecachte Artefakte und Schwachstellenübersicht./ui/install) -- Konfigurationsanweisungen pro Ökosystem, damit Sie sie nicht hier nachschlagen müssen./ui/packages) -- alle gecachten Pakete durchsuchen mit Filterung nach Ökosystem und Sortierung nach Hits, Größe, Name oder Anzahl der Schwachstellen./ui/search?q=...) -- gecachte Pakete nach Namen durchsuchen./ui/package/{ecosystem}/{name}) -- Metadaten, Lizenz, Schwachstellen und Versionsliste für ein Paket. Sie können zwei Versionen zum Vergleich auswählen./ui/package/{ecosystem}/{name}/{version}) -- Metadaten pro Version, Integritäts-Hash, Artefakt-Cache-Status und Hit-Zähler./ui/package/{ecosystem}/{name}/{version}/browse) -- Dateien in gecachten Archiven durchsuchen mit Syntaxhervorhebung für Textdateien und Bildvorschauen./ui/package/{ecosystem}/{name}/compare/{v1}...{v2}) -- Side-by-Side-Diff zweier gecachter Versionen mit hinzugefügten, entfernten und geänderten Dateien.Der Proxy stellt Prometheus-Metriken unter GET /metrics bereit. Alle Metriknamen haben das Präfix proxy_.
| Metrik | Typ | Labels | Beschreibung |
|---|---|---|---|
proxy_requests_total | counter | ecosystem, status | Proxy-Antworten nach Paket-Ökosystem und HTTP-Status |
proxy_request_duration_seconds | histogram | ecosystem, status | Dauer der Proxy-Anfragen |
proxy_cache_hits_total | counter | ecosystem | Cache-Treffer |
proxy_cache_misses_total | counter | ecosystem | Cache-Fehlschläge |
proxy_cache_size_bytes | gauge | Gesamtgröße der gecachten Artefakte | |
proxy_cached_artifacts_total | gauge | Anzahl der gecachten Artefakte | |
proxy_upstream_fetch_duration_seconds | histogram | ecosystem | Zeit für das Abrufen vom Upstream |
proxy_upstream_errors_total | counter | ecosystem, error_type | Upstream-Abruffehler |
proxy_storage_operation_duration_seconds | histogram | operation | Latenz von Storage-Lese-/Schreibvorgängen |
proxy_storage_errors_total | counter | operation | Storage-Lese-/Schreibfehler |
proxy_active_requests | gauge | Anfragen in Bearbeitung | |
proxy_health_probe_failures_total | counter | step | Fehler der Storage-Health-Probe nach fehlgeschlagenem Schritt (write, size, read, verify, delete). |
proxy_circuit_breaker_state |
Cache-Größe und Artefaktanzahl werden alle 60 Sekunden aktualisiert. Der Circuit-Breaker-Zustand wird bei jedem Scrape von /metrics und jeder /health-Anfrage vom Fetcher gelesen, sodass proxy_circuit_breaker_trips_total die zwischen diesen Lesevorgängen sichtbaren Auslösungen zählt — ein Circuit Breaker, der sich zwischen zwei Scrapes vollständig öffnet und wieder erholt, wird nicht gezählt. Die übrigen Metriken werden bei jeder Anfrage aktualisiert.
Die Circuit-Breaker-Metriken enthalten eine Serie pro Upstream-Host, aber nur für Hosts, deren Circuit Breaker seit dem Start mindestens einmal ausgelöst hat. Ein Circuit Breaker wird pro Host erstellt, von dem der Proxy Artefakte abruft, und für einige Ökosysteme stammt dieser Host aus Upstream-Metadaten statt aus der Konfiguration (composer entnimmt ihn aus der dist.url eines Pakets, helm aus den Chart-URLs in index.yaml), sodass die Veröffentlichung jedes Hosts es Upstream-Inhalten ermöglichen würde, die Serienanzahl für die Lebensdauer des Prozesses wachsen zu lassen. Sobald ein Host ausgelöst hat, berichtet er weiter, sodass sich eine Erholung weiterhin als Übergang zu 0 zeigt und nicht als Serie, die verschwindet. /health ist keine persistente Zeitreihe und listet jeden Circuit Breaker auf, ausgelöst oder nicht.
Das Label registry ist der Host der URL, von der das Artefakt abgerufen wurde. Da diese URL aus Upstream-Metadaten stammen kann, lässt sich nicht immer ein Host daraus ablesen — beispielsweise bei einer signierten dist.url, die nicht geparst werden kann — und ein solcher Circuit Breaker wird stattdessen mit hostless-url-<digest> beschriftet, wobei der Digest auf einen beim Start frisch gezogenen Wert geschlüsselt ist. Weder /metrics noch /health erfordern Authentifizierung, sodass eine Abruf-URL niemals als Label oder Schlüssel veröffentlicht wird; der Digest identifiziert den Circuit Breaker für die Laufzeit des Prozesses, ohne die dahinterliegende URL preiszugeben oder eine gewählte URL dagegen abgleichen zu lassen.
Alarmieren Sie bei proxy_circuit_breaker_state == 2, wenn dies länger als ein paar Minuten anhält: Solange ein Circuit Breaker offen ist, schlagen Artefakt-Downloads für diesen Upstream bei jedem Cache-Fehlschlag mit HTTP 502 fehl, und nur eine einzelne Probe-Anfrage pro Backoff-Intervall erreicht den Upstream. Gecachte Artefakte werden weiterhin ausgeliefert, ebenso Metadaten für dasselbe Ökosystem (Metadaten laufen nicht über den Circuit Breaker), sodass Installationen in einer Weise fehlschlagen, die wie eine teilweise Upstream-Störung aussieht.
/health gibt einen strukturierten JSON-Bericht über den Zustand der Subsysteme zurück. HTTP 200, wenn alle Prüfungen bestehen; 503, wenn eine fehlschlägt.```json
{
"status": "ok",
"checks": {
"database": {"status": "ok"},
"storage": {"status": "ok"}
},
"circuit_breakers": {
"registry.npmjs.org": "closed",
"static.crates.io": "open"
}
}
Fehlgeschlagene Prüfungen enthalten ein `"error"`-Feld. Speicherfehler enthalten zusätzlich ein `"step"`-Feld, das angibt, welcher Prüfschritt fehlgeschlagen ist (`write`, `size`, `read`, `verify`, `delete`). Wenn die Datenbankprüfung fehlschlägt, meldet der Speichereintrag `{"status": "skipped"}`, sodass die Antwort stets denselben Schlüsselsatz enthält.
`circuit_breakers` meldet den Zustand des Artifact-Fetch-Circuit-Breakers jedes Upstreams (`"open"` oder `"closed"`), verschlüsselt nach Upstream-Host — oder nach dem `hostless-url-<digest>`-Platzhalter, der unter [Monitoring](#monitoring) beschrieben wird, wenn die Fetch-URL keinen Host zum Auslesen hat. Der Schlüssel wird weggelassen, bis der Proxy ein Artefakt von mindestens einem Upstream abgerufen hat, und ein Host erscheint erst, sobald ein Breaker für ihn erstellt wurde. Breaker lösen nach wiederholten Upstream-Fehlern aus und versuchen den Upstream nach einem exponentiellen Backoff erneut. Während einer offen ist, liefern Artefakt-Downloads für diesen Host bei einem Cache-Miss HTTP 502 zurück, ohne den Upstream zu kontaktieren; bereits gecachte Artefakte werden weiterhin aus dem Speicher bedient, da der Cache vor dem Fetcher geprüft wird. Ein Breaker wird während seines gesamten Backoffs als `"open"` gemeldet, einschließlich des Half-Open-Fensters, in dem er eine Probe-Anfrage zulässt, um die Wiederherstellung zu testen. Der Breaker-Zustand ist pro Prozess und im Speicher, sodass ein Neustart ihn löscht, aber ein Neustart ist für die Wiederherstellung nicht erforderlich: Der Backoff versucht weiterhin erneut, solange der Breaker offen ist, sodass er sich von selbst schließt, sobald der Upstream wieder bedient.
Ein offener Breaker setzt `status` **nicht** auf `"error"` und ändert nicht den HTTP-Statuscode: Er meldet einen bestimmten Upstream, der die Bedienung verweigert, nicht diesen Proxy als ungeeignet für den Empfang von Traffic, und das Fehlschlagen der Readiness-Probe wegen eines ungesunden Upstreams würde den Pod auch für jedes andere Ökosystem aus der Rotation nehmen. Verwende `proxy_circuit_breaker_state` für die Alarmierung darauf.
Speicher-Probe-Ergebnisse werden für `health.storage_probe_interval` (Standard 30s) zwischengespeichert, um die Kosten für das Probing entfernter Backends zu begrenzen. Eine Probe hält einen internen Mutex für bis zu 10 Sekunden (das fest codierte Timeout pro Probe), sodass `/health` als Kubernetes-**Readiness**-Probe und nicht als Liveness-Probe gedacht ist — ein langsamer S3-Roundtrip sollte den Pod aus der Rotation nehmen, nicht ihn neu starten.
Scrape-Konfiguration für Prometheus:```yaml
scrape_configs:
- job_name: git-pkgs-proxy
static_configs:
- targets: ["localhost:8080"]
Erstellen Sie /etc/systemd/system/proxy.service:```ini
[Unit]
Description=git-pkgs proxy
After=network.target
[Service] Type=simple User=proxy ExecStart=/usr/local/bin/proxy -config /etc/proxy/config.yaml Restart=always RestartSec=5
[Install] WantedBy=multi-user.target
Aktivieren und starten:```bash
sudo systemctl enable proxy
sudo systemctl start proxy
Ein Dockerfile ist im Repository enthalten. Bauen und ausführen:```bash docker build -t proxy . docker run -p 8080:8080 -v proxy-data:/data proxy
Mit Postgres und S3:```bash
docker run -p 8080:8080 \
-e PROXY_DATABASE_DRIVER=postgres \
-e PROXY_DATABASE_URL=postgres://user:pass@db:5432/proxy \
-e PROXY_STORAGE_URL=s3://my-bucket?region=us-east-1 \
-e AWS_ACCESS_KEY_ID=... \
-e AWS_SECRET_ACCESS_KEY=... \
proxy
Wenn Sie hinter nginx, Apache oder einem anderen Reverse-Proxy ausgeführt werden, setzen Sie base_url auf Ihre öffentliche URL:```yaml
base_url: "https://proxy.example.com"
Wenn die UI über einen anderen Hostnamen als die Paket-Endpunkte erreicht wird — zum Beispiel, wenn die UI öffentlich unter einer Domain exponiert ist, während Build-Maschinen einen Docker-Netzwerk-Alias verwenden —, setze `ui_base_url` separat. `base_url` ist die URL, die Paketmanager und Metadaten-Umschreibung verwenden; `ui_base_url` ist die URL, die Personen angezeigt wird, die die Web-UI besuchen (Canonical-/`og:url`-Tags und das Banner des Installationsleitfadens):```yaml
base_url: "http://pkg-proxy:8080" # internal alias for build machines
ui_base_url: "https://proxy.example.com/ui" # public UI URL
Wenn nicht gesetzt, wird ui_base_url standardmäßig auf base_url gesetzt.
Warnung: Der Proxy stellt die UI- und Paket-Endpunkte auf demselben Listener bereit. Das Setzen von
ui_base_urländert nur die URL, die die UI gegenüber Menschen bewirbt; es verhindert nicht, dass Paket-Endpunkte unter demselben Hostnamen und Port erreichbar sind. Wenn Sie den Proxy mit einem öffentlichen Reverse-Proxy vorschalten, beschränken Sie die öffentliche Route aufPathPrefix(/ui)(oder das Äquivalent Ihres Proxys), andernfalls bleiben/npm,/pypiund die anderen Paket-Endpunkte neben der UI exponiert.
nginx-Beispiel, das den öffentlichen Host auf die UI beschränkt, während die Paket-Endpunkte nur auf dem internen Listener erreichbar bleiben:```nginx server { listen 443 ssl; server_name proxy.example.com;
location /ui/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
}
location / {
return 404;
}
}
Traefik-Beispiel mit `PathPrefix(/ui)`, sodass der öffentliche Router nur UI-Traffic abgleicht:```yaml
labels:
traefik.enable: "true"
traefik.http.services.pkg-proxy.loadbalancer.server.port: "8080"
traefik.http.routers.pkg-proxy.rule: "Host(`proxy.example.com`) && PathPrefix(`/ui`)"
traefik.http.routers.pkg-proxy.entrypoints: "websecure"
Der Proxy speichert Artefakte im konfigurierten Speicherverzeichnis mit dieser Struktur:``` cache/artifacts/ ├── npm/ │ └── lodash/ │ └── 4.17.21/ │ └── lodash-4.17.21.tgz ├── cargo/ │ └── serde/ │ └── 1.0.193/ │ └── serde-1.0.193.crate ├── oci/ │ └── library/nginx/ │ └── sha256:abc123.../ │ └── sha256:abc123... ├── deb/ │ └── nginx/ │ └── 1.18.0-6/ │ └── nginx_1.18.0-6_amd64.deb └── rpm/ └── nginx/ └── 1.24.0-1.fc39/ └── nginx-1.24.0-1.fc39.x86_64.rpm
Cache-Metadaten werden in SQLite (Standard) oder PostgreSQL gespeichert. Um einen lokalen Cache zu leeren:```bash
rm -rf ./cache/artifacts/*
rm ./cache/proxy.db
Der Proxy erstellt die Datenbank beim nächsten Start neu.
Voraussetzungen:
go.mod deklariert)```bash
git clone https://github.com/git-pkgs/proxy.git
cd proxy
go build -o proxy ./cmd/proxyTests ausführen:```bash
go test ./...
GPL-3.0-or-later
| Chef | Chef | ✗ |
| Generic | Any | ✓ |
| Helm | Kubernetes | ✓ |
| Vagrant | Vagrant | ✗ |
GET /generic/{name}/* | Generischer HTTP-Download-Proxy (GitHub-Release-Assets, mise/aqua) |
GET /debian/* | Debian/APT-Repository-Protokoll |
GET /rpm/* | RPM/Yum-Repository-Protokoll |
| gauge |
registry |
| Zustand des Circuit Breakers für Artefakt-Abrufe pro Upstream-Registry (0 geschlossen, 2 offen). Wird veröffentlicht, sobald der Circuit Breaker dieser Registry ausgelöst hat. |
proxy_circuit_breaker_trips_total | counter | registry | Auslösungen des Circuit Breakers pro Upstream-Registry. |