Skip to main content
Private preview. fremforge is in private preview — invited customers only. Content is still subject to change. Request access →

Package caches

Every fremforge-hosted runner pod boots with two environment variables pre-set so your CI hits an in-region cache for the public registry traffic that would otherwise leave the EU:

VariableValueWhat it caches
NPM_CONFIG_REGISTRYhttp://cache-verdaccio.fremforge-prd.svc.cluster.local:4873/Public packages from registry.npmjs.org
DOCKER_MIRROR_URLhttp://cache-distribution.fremforge-prd.svc.cluster.local:5000Public images from registry-1.docker.io

The caches sit in the same OTC region as the runner pods (eu-de, Germany). Misses fall through to upstream via fremforge’s outbound proxy and the response is cached for the next workflow.

Why this is automatic

A typical npm ci pulls 30-60 MB of tarballs every build. Without the cache, that traffic crosses the NAT gateway and pulls from us-east-1 every time. With the cache, the same install drops to ~3-5s of intra-region traffic on warm packages.

You do not need to configure anything, npm, pnpm, and yarn v1 all honour NPM_CONFIG_REGISTRY automatically.

Override per workflow

To override (e.g. when you need to pull from a private registry), set the variable in your workflow env:

jobs:
  build:
    runs-on: fremforge
    env:
      NPM_CONFIG_REGISTRY: https://npm.your-company.example/
    steps:
      - run: npm ci

Step-level env: is also respected. The customer setting always wins over the fremforge default.

Docker Hub mirror

The Docker mirror is anonymous-only and only works against public Docker Hub images. Two consumption patterns:

kaniko (the default for in-runner image builds)

- name: Build image
  uses: int128/kaniko-action@v1
  with:
    context: .
    push: true
    extra-args: --registry-mirror=${{ env.DOCKER_MIRROR_URL }}

buildkit (docker buildx)

Configure the daemon at job start, then build as normal:

- name: Configure docker buildx mirror
  run: |
    mkdir -p /home/runner/.docker
    cat > /home/runner/.docker/config.json <<EOF
    { "registry-mirrors": ["${DOCKER_MIRROR_URL}"] }
    EOF
- uses: docker/setup-buildx-action@v3
- run: docker buildx build .

What is NOT cached

  • Private packages. Both caches are configured for anonymous-only upstream pulls. Customer Authorization headers never reach upstream and are never cached. If you need a private package, override NPM_CONFIG_REGISTRY or your Docker registry config per the examples above.
  • Dynamic API calls. GitHub-style API calls (e.g. npm view <package> against api.npmjs.org) are not cached, only the package-data registry endpoints are.
  • Source repos. git clone traffic to GitHub / GitLab / your own forge is not cached. Use Forgejo’s own packages registry (packages.frem.sh) when you control the source.
  • Anything outside the public registries. The caches do not proxy quay.io, gcr.io, ghcr.io, or any private registry. Configure those directly per workflow.

Performance expectation

  • Cold cache (first pull of a new package version): ~2-5s slower than upstream, the cache fetches from upstream, persists to OBS, then returns. Net latency = upstream pull + OBS write.
  • Warm cache (subsequent pulls of the same version): ~30-60s faster than upstream for a typical npm ci run, the cache serves from OBS intra-region.
  • Cache horizon: 90 days. Versions not requested for 90 days are evicted by the lifecycle policy. Practical effect: anything in active use stays warm forever.

Sovereignty story

The cache pods run inside fremforge-prd CCE; the cache storage lives in the eu-de OBS bucket fremforge-prd-cache-mirrors. No customer personal data ever transits these systems, they only see public package binaries.

The cache software itself (Verdaccio + distribution/distribution) is governed by the OpenJS and CNCF foundations respectively, both US-incorporated. The runtime binaries are mirrored to fremforge’s own SWR registry (eu-de) following the same supply-chain pattern as every other container image fremforge runs. Anonymous-only upstream pulls mean no customer credentials ever leave fremforge’s network.

DPA Annex B (sub-processor disclosure) does not list these caches because they handle internal tooling traffic only, no customer personal data is processed by either cache.

Status + incident response

Cache health is monitored by the cluster-internal cache-mirrors-availability watchdog (every 15 min) and an OBS cost-guard CES alarm fires at 100 GiB bucket size. Operator runbooks:

When a cache is degraded, workflows continue to run, the runner pods are configured to fall through to the upstream registry via fremforge’s outbound proxy. Expected impact: ~30-60s extra per uncached pull. No job failures.

Related

  • Runner image, what’s baked into the runner-base image (kaniko, buildkit, language toolchains)
  • Secrets, how to inject private-registry credentials per workflow
  • Outbound egress, allowed destinations, and outbound-proxy behaviour are covered in CI runners