Prebuilt image and Portainer
Instead of building on the server or NAS, let GitHub build the image and
download the finished image from the GitHub Container Registry (ghcr.io). The
workflow .github/workflows/docker-publish.yml builds for amd64 and arm64 on
every push to main and every release tag, and publishes the image with an SBOM
and signed build provenance. Pull requests only build (as a test).
- Create a repository on GitHub and push the project:
git init && git add . && git commit -m "Initial version"git branch -M maingit remote add origin https://github.com/sebastianflint/pve-panel.gitgit push -u origin main
.gitignorekeeps.env, the database andnode_modulesout of the repository; no secrets go to GitHub, and none are in the image. - Watch it build in the repository's Actions tab (the first run takes a
few minutes; the arm64 part is emulated). The image then appears under
Packages as
ghcr.io/sebastianflint/pve-panel. - Releases: see Versions, releases and updates (
npm version, thengit push --follow-tags). - Who may download it:
- Public package: anyone can pull it, no login needed on the NAS. Set it under the package's Package settings, Change visibility. The image contains code only, no configuration.
- Private package (default for a private repository): log the NAS in once with
a GitHub personal access token (classic) that only has
read:packages:sudo docker login ghcr.io -u sebastianflintover SSH, token as password.
- On the server or NAS you only need two files in one folder:
deploy/docker-compose.yml(saved there asdocker-compose.yml) and your.envwith, among the usual settings,PANEL_IMAGEonly if you want to pin a release (e.g.ghcr.io/sebastianflint/pve-panel:1.0.0); the default isghcr.io/sebastianflint/pve-panel:latest. Then create the Docker Project there, or rundocker compose up -d. - Updating: push changes (or a new tag), wait for the Actions run, then
redeploy the project;
pull_policy: alwaysfetches the new image. With a pinned release, change the version at the end ofPANEL_IMAGEfirst.
With Portainer: use deploy/docker-compose.portainer.yml instead (Stacks, Add
stack, Web editor) and enter your settings under Environment variables, or
load your .env there. Portainer uses those variables only to fill in ${...}
in the compose file and saves them to stack.env; the Portainer version passes
that file into the container (env_file: stack.env). With env_file: .env the
container starts without your settings and stops with
"Missing required environment variable JWT_SECRET".
Optional: verify an image came from your workflow with
gh attestation verify oci://ghcr.io/sebastianflint/pve-panel:latest --owner sebastianflint.
Dependabot (.github/dependabot.yml) proposes weekly updates for npm packages,
the Node base image and the workflow's actions.