Files
verdande/docs/rune.md
T
Kristian WindandClaude Opus 5 20b8c12b4a build: imaget hentes fra vores egen Gitea, og runen peger derind
GitHub er utilgængeligt i ti dage. Koden ligger allerede begge steder; det, der
manglede, var imaget og et sted at bygge det.

**Imaget ligger i Gitea nu**, begge arkitekturer. Kopieret med
`docker buildx imagetools create`, som flytter hele manifest-indekset mellem to
registre uden at hente lagene ned — en `docker pull` på denne maskine ville have
hentet arm64 og efterladt serveren uden en amd64 at køre.

**Og det kan hentes uden legitimation, mens repoet bliver ved med at være
privat.** Det var ikke givet: panelets `PullImage` sætter aldrig `RegistryAuth`,
så et privat register er udelukket, og Gitea gør normalt en container-pakke privat
sammen med det repo, den hører til. Men en pakke bindes kun til et repo, når den
skubbes med et repo-link — og denne er ikke, så dens synlighed følger brugeren
`kw`, som er offentlig.

Bevist frem for antaget: `docker --config /tmp/tom pull` hentede den med samme
digest som GHCR havde. En bar `curl` mod `/v2/…/manifests/…` svarer 401 også for
et læsbart image, fordi registret uddeler et anonymt token først — så den er ikke
prøven, og den kostede en runde at gennemskue.

**Runen er bumpet til version 5.** Ikke fordi felterne ændrede sig, men fordi en
rune ikke opdaterer sig selv: panelet skriver rune-rækken fra en UI-handling, så
ændringen kræver **Runes → verdande → Update**, og katalog-listen caches ti
minutter.

**Et Actions-workflow til Gitea** ligger i `.gitea/workflows/`. Sin egen fil frem
for en delt: `secrets.GITHUB_TOKEN` findes ikke der, registret er et andet, og der
er ingen Releases-side at skrive til. En delt fil ville være fire betingede led,
der hver kun gælder ét af de to steder. Den laver ingen release, fordi
opdateringsnotitsen i appen læser GitHubs — skal den flyttes med, er det
`internal/update`, der skal have en ny adresse.

**Det virker ikke endnu:** der er ingen runner registreret på Gitea. Indtil der er,
bygges og skubbes imaget i hånden herfra.

Dokumentationen og landingssiden siger den nye adresse. Rune-siden er skrevet om,
hvor den fortalte om GHCR-pakkeindstillinger, og siger nu, hvordan man prøver
efter på den måde, der faktisk svarer på spørgsmålet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 16:53:18 +02:00

4.7 KiB

Installing as a Rune

verdande ships with a Rune manifest for Yggdrasil Panel.

If the image will not pull

create container: Error response from daemon:
No such image: gitea.nolimit.dk/kw/verdande:latest

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 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.

The package has to be readable without credentials. On Gitea that does not mean making the source repository public: a container package is only tied to a repository when it is pushed with a repository link, and this one is not — so its visibility follows the account, which is public, while kw/verdande stays private.

Check it the way a puller does, with no credentials at all:

docker --config /tmp/empty pull gitea.nolimit.dk/kw/verdande:latest

If that works, the panel can pull it. A plain curl against /v2/…/manifests/… answers 401 even for a readable image — the registry hands out an anonymous token first — so a bare curl is not the test.

Once it is public, press Start on the server you already have. There is no need to delete it and make another: the image reference is read from the rune at container-create time, and both Start and Restart recreate the container.

To keep the package private you have to put the image on the host yourself, before creating the server, and again after every release:

sudo docker login gitea.nolimit.dk -u kw
sudo docker pull gitea.nolimit.dk/kw/verdande:latest

Run it as the user the Docker daemon runs as — sudo if the panel does. The panel's own pull still fails silently; create simply finds the image already there.

!!! danger "This hides updates" The panel re-pulls on every recreate, fails quietly, and carries on with the local image. A new release then looks like it rolled out and did not. For something you intend to update, public is the right answer and host-pull is the stopgap.

Installing

  1. Runes → Carve a rune (upload) and pick rune/verdande.yaml from the repository.
  2. Create a server from it.
  3. Fill in the settings below.
  4. Start it, open the URL, create the first account.

!!! note "Updating the rune is a manual step" A rune does not update itself when this manifest changes. The panel writes the rune row from a UI action only — neither a restart nor a timer does it — so pick up a new manifest with Runes → verdande → Update, or install it again from Browse GitHub.

The catalogue list is cached in memory for ten minutes, so two attempts in a
row can both hand you the old version. Recent panel versions show the list's
age with a *fetch again* link.

Settings

Setting What to put
Public address The address you reach it on. {{PUBLIC_URL}} is the default and usually right.
SMTP host Your mail server. Leave blank and invite links are shown in the app instead of emailed.
SMTP port 587 for STARTTLS, 465 for implicit TLS.
SMTP username / password As your mail server expects.
Sender address What invites and reminders come from.
Use STARTTLS On, unless you are on port 465.
How long a login lasts 720h — thirty days.

!!! note "Why the public address cannot be guessed" The host port is not chosen until the server is created, so verdande has no way to work out its own address. The panel does, and passes it in as {{PUBLIC_URL}}.

Reaching it from outside

Give the server a Subdomain under its settings and enable Cloudflare Tunnel (subdomains) under Settings → Network. No port forwarding and no public IP.

Backups

The Rune's backup includes the whole /data directory, which is what you want — see the warning about copying the database alone.

Watchers

The manifest ships log watchers for database errors, repeated failed logins and HTTP 5xx. They appear under Settings → Kvasir Watchers as ordinary per-server rules you can edit or turn off.