From a8a29a963dee486bedcb0047a6c32872bfc67e19 Mon Sep 17 00:00:00 2001 From: Kristian Wind Date: Mon, 17 Aug 2026 11:52:34 +0200 Subject: [PATCH] docs: the registry has to be public, and docker login was the wrong advice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Installing the Rune still failed after v0.2.0 was published, with the same message as before: create container: Error response from daemon: No such image: ghcr.io/kristianwind/verdande:latest The advice in these pages — log the host's Docker daemon in — cannot work, and Yggdrasil's source says why. Its PullImage calls the Docker SDK's ImagePull with an empty image.PullOptions{}; RegistryAuth is never set, and there are no registry credentials anywhere in the panel. A private image answers 401. pullImageRetry discards that error on purpose ("second failure surfaces at create"), and ContainerCreate — which only ever looks locally — then reports the image as missing. The message is a liar: the tag is in the registry the whole time. docker login does not change this. It is client-side: the daemon stores no credentials, the CLI sends them itself with each request, and Yggdrasil is a different client that sends none. So the package has to be public, and the pages now say that rather than offering a login that does nothing. Keeping it private is still possible but is now described as what it is: putting the image on the host by hand before creating the server and again after every release. Co-Authored-By: Claude Opus 5 --- README.md | 8 -------- docs/rune.md | 41 +++++++++++++++++++++++++---------------- docs/self-hosting.md | 15 ++++++--------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index db1049c..4c39c65 100644 --- a/README.md +++ b/README.md @@ -126,14 +126,6 @@ and the manifest ships in this repository. It runs anywhere Docker does as well. ### With Docker directly -The package is private, and an anonymous pull fails with `No such image` rather -than with a permission error. Log the host's Docker daemon in once, with a GitHub -token carrying the `read:packages` scope: - -```bash -echo "$GHCR_TOKEN" | docker login ghcr.io -u kristianwind --password-stdin -``` - ```bash docker run -d --name verdande \ -p 8080:8080 \ diff --git a/docs/rune.md b/docs/rune.md index a876c91..b7f02b8 100644 --- a/docs/rune.md +++ b/docs/rune.md @@ -3,33 +3,42 @@ verdande ships with a Rune manifest for [Yggdrasil Panel](https://github.com/kristianwind/yggdrasil). -## Before you start: the registry is private - -The image lives at `ghcr.io/kristianwind/verdande` and the package is **private**, -so an anonymous pull fails with a message that reads as though the image does not -exist at all: +## If the image will not pull ``` create container: Error response from daemon: No such image: ghcr.io/kristianwind/verdande:latest ``` -That is a permission error wearing the wrong hat. The Docker daemon **on the -Yggdrasil host** has to be logged in once: +This message is a liar. It does not mean the tag is missing from the registry — +it means the image is not on the host, and the panel's attempt to fetch it failed +without saying so. + +The usual cause is a **private** GHCR package. Yggdrasil pulls anonymously: its +`PullImage` calls the Docker SDK with no `RegistryAuth`, so a private image comes +back 401. The pull error is discarded, and `ContainerCreate` — which only ever +looks locally — then reports the image as missing. + +!!! warning "`docker login` on the host does not help" + `docker login` is client-side. The daemon stores no credentials; the CLI + sends them itself with each request. Yggdrasil is a different client and + sends none, so logging in changes nothing for the panel. + +**Make the package public.** Under +[Packages → verdande → Package settings](https://github.com/users/kristianwind/packages/container/package/verdande) +→ *Change visibility*. The repository stays private; only the built image becomes +readable, which is what the manifest and these pages have always assumed. + +To keep it private you have to put the image on the host yourself, before +creating the server, and again after every release: ```bash echo "$GHCR_TOKEN" | docker login ghcr.io -u kristianwind --password-stdin +docker pull ghcr.io/kristianwind/verdande:latest ``` -`GHCR_TOKEN` is a GitHub personal access token with the **`read:packages`** scope -and nothing else. The login is stored in `~/.docker/config.json` for whichever -user runs the daemon — if Yggdrasil runs as root or through systemd, log in as -that user, not as yourself. - -!!! tip "Or make the package public" - Under **Packages → verdande → Package settings → Change visibility**. The - repository can stay private; only the built image becomes readable. Then no - login is needed anywhere and this section stops applying. +`GHCR_TOKEN` is a GitHub token with the `read:packages` scope. The panel's own +pull still fails silently; it simply finds the image already there. ## Installing diff --git a/docs/self-hosting.md b/docs/self-hosting.md index e078edc..eaf1bc9 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -5,15 +5,12 @@ cache, no queue and no second process. ## Docker -!!! warning "Log in to the registry first" - The package is private, and an anonymous pull fails with `No such image` - rather than with a permission error. Once per host: - - ```bash - echo "$GHCR_TOKEN" | docker login ghcr.io -u kristianwind --password-stdin - ``` - - `GHCR_TOKEN` is a GitHub token with the `read:packages` scope. +!!! note "If the pull is refused" + The GHCR package is public, so this needs no credentials. If it is ever set + back to private, `docker login ghcr.io` with a token carrying the + `read:packages` scope before pulling — and see + [the Rune page](rune.md#if-the-image-will-not-pull), because a private image + fails differently and much more confusingly under Yggdrasil. ```bash docker run -d --name verdande \