Read-only mirror — the public repositories of the Forgejo instance, refreshed every 10 minutes. The live instance (fg.dieschoenewolke.de) is reachable only over the VPN; clone here with https://git.dieschoenewolke.de/git/<owner>/<repo>.git.
summaryrefslogtreecommitdiff
path: root/AGENTS.md
blob: 594ffaacb76dfa0215c7601ef4708d701e0f26ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# AGENTS — distroless-mirror

Public read-only OCI mirror of `gcr.io/distroless/{static,base,cc,python3}` on
`img.dieschoenewolke.de`, served by zot on the VPS. `README.md` has the
architecture, the deploy sequence and the zot-vs-registry:2 rationale.

## Rules

- **Read-only is a property of the registry, not of the edge.** Keep
  `http.accessControl.repositories."**".anonymousPolicy` at `["read"]` and keep
  the config free of any `auth` block. Adding htpasswd or an LDAP block would
  create an authenticated write path that the internet could reach.
- The port publish stays `127.0.0.1:5000`. The edge vhost is the only entry
  point; never publish zot on `0.0.0.0` or a host interface.
- Keep the tag allowlist short (`latest|nonroot|debug|debug-nonroot`). It bounds
  both disk and what an anonymous client can make zot fetch from gcr.io.
- `platforms` stays `linux/amd64` + `linux/arm64`. Without the allowlist zot
  copies every child of the index (arm, ppc64le, riscv64, s390x) and the mirror
  triples in size on a 28 GB root.
- Marker tags (`synced-<repo>-<tag>-<digest12>`) are written only after a
  successful pull **by digest** through the public hostname. Do not move tag
  creation before the verification, and do not mark from the digest comparison
  alone.
- Sync one way only: VPS pulls from gcr.io; nothing pushes into the registry.

## Traps

- `edge-nginx/nginx/default.conf` is a single-file bind mount. Write in place
  (`cat new > default.conf`), then `docker exec edge-nginx nginx -t` and
  `nginx -s reload` (or force-recreate). Replacing the file breaks the mount.
- AppSec must stay off for this host: docker/containerd/skopeo/crane user
  agents trip CRS scanner rules. The CrowdSec IP bouncer still applies.
- Do not test from the VPS: its own requests go through AppSec and can be
  challenged. Test from codeserver over the public name.
- The wildcard `*.dieschoenewolke.de` SAN covers `img`; a new **name** needs a
  DNS record, not a certificate change. A new apex-level domain would need the
  certbot SAN list and a 300 s deSEC propagation wait.
- zot's periodic sync updates an existing tag only on the next `pollInterval`
  (2 h). A digest mismatch in the auditor is therefore "pending", not "failed";
  only a 404 for a ref that was already marked is a regression.
- `proxy_buffering off` and `proxy_max_temp_file_size 0` are deliberate: layer
  blobs are streamed, not spooled onto the 28 GB root filesystem.
- zot GC removes untagged manifests after `gcDelay` (1 h). Never rely on an
  untagged digest staying pullable — keep the tag (or a marker tag) that
  references it.