CLI tool
home-operations/containers avatar
home-operations/containers

home-operations/containers: Rootless, digest-pinned images for self-hosters

Community project for building application containers

431 stars49 forksDockerfileApache-2.0

At a glance

What is it?
A community project that builds opinionated, rootless, multi-architecture containers for self-hosted apps. It trades pretty tags for digest pinning and rejects process supervisors, which makes it a clean fit for Kubernetes and Compose users who value reproducibility.
Who is it for?
Adopt this project if you run self-hosted apps on Kubernetes or Docker Compose and want rootless, multi-arch images that are signed and pinned to a digest. Do not adopt it if you need multiple release channels for apps like Prowlarr or Sonarr, or if you depend on s6-overlay style init.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Dockerfile, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What problem this project actually solves

The home-operations/containers repository publishes a set of container images for self-hosted applications, built with a specific set of constraints. The mission statement is explicit: semantically versioned, rootless, and multi-architecture containers. The project targets people who run apps like Home Assistant, Prowlarr, Radarr, or qBittorrent and want them to behave predictably across architectures. The README positions it as an opinionated alternative to linuxserver.io and Bitnami, where those projects use immutable tags but do not force digest pinning. This project insists on pinning to the sha256 digest of the image, which is a stronger guarantee than a tag that could be moved. The intended user is someone who already manages containers with Compose or Kubernetes and is willing to accept a less visually appealing tag format in exchange for verifiable immutability.

The mechanism: digest pinning and what it means in practice

The core design choice is that tags are not immutable. The README shows a table where both `rolling` and a specific version like `2025.5.1` are marked as not immutable. Only when you append `@sha256:8053...` does the image become immutable. This is a deliberate rejection of the linuxserver.io model, where a tag like `latest` is frozen to a specific build. Here, the tag is just a pointer, and the digest is the real identifier. The README says this approach ensures functionality and immutability, though it admits it is less visually appealing. For users, this means you must always reference the digest in your deployment files, or you risk pulling a changed image under the same tag. The project also uses semantic versioning, so tags like `2026.8.0` follow that scheme. The release cadence is monthly, based on the recent releases, which suggests a regular update flow.

Rootless by default, with explicit user mapping

Most containers run as a non-root user with UID and GID 65534:65534. That is the `nobody` user on many systems. The README shows how to override this in Docker Compose with `user: 1000:1000`, but warns that the data volume permissions must match. In Kubernetes, the security context is used, with `allowPrivilegeEscalation: false`, dropping all capabilities, and setting `readOnlyRootFilesystem: true`. The README notes that you may need to mount additional directories as `tmpfs` or `emptyDir` because a read-only root filesystem breaks apps that write to `/tmp`. This is a concrete constraint: you cannot just run these images without adjusting your deployment. The rootless default is a real security improvement, but it shifts the burden to the user to configure volumes correctly. The README also hardcodes the configuration volume to `/config`, and states that in most cases this path cannot be changed. That is a limitation for apps that expect a different config location.

Getting it running: commands and config keys from the README

The README gives two concrete deployment examples. For Docker Compose, you pull the image with the digest and set the user, read_only, and tmpfs keys. The example shows `image: ghcr.io/home-operations/home-assistant:2025.5.1@sha256:516ae5c85089b3f2960cf2a21dc3c105356969499964fabf0b0358e5f3a7e0a2`. For Kubernetes, you use a Deployment with the same image reference and a securityContext that drops all capabilities. To pass command-line arguments to applications that do not accept environment variables, the README points to Kubernetes documentation on defining commands and arguments, and shows an `args` list with `--port` and `8080`. There is no mention of a CLI tool or a build process in the README; this is purely a registry of prebuilt images. The verification command is `gh attestation verify --repo home-operations/containers oci://ghcr.io/home-operations/${APP}:${TAG}`, and there is also a cosign command with specific flags. These commands are the only way to confirm the image was built by GitHub CI.

Signature verification: the one security feature you should use

The images are signed using the `attest-build-provenance` GitHub Action. That produces a SLSA provenance attestation, which you can verify with either the GitHub CLI or cosign. The README gives exact commands. The `gh attestation verify` command checks that the image was built by the `home-operations/containers` repository. The cosign command is more verbose, requiring `--new-bundle-format --type slsaprovenance1` and a certificate OIDC issuer that matches GitHub's token service. This is a strong guarantee: you can verify that the image you pull was built from this repository's CI, not a malicious copy. The README does not state whether all images are signed or only some, but the presence of a dedicated section suggests it is a standard practice. For a project that relies on digest pinning, signature verification is the natural complement. Without it, a digest could theoretically be reproduced by an attacker, though that is difficult. The verification step is cheap and should be part of any deployment pipeline.

What this project eschews: no channels, no s6-overlay, no gosu

The README has a section titled 'Eschewed Features' that lists what the project deliberately does not support. It does not publish multiple channels for the same application. For example, Prowlarr, Radarr, Lidarr, and Sonarr only publish the `develop` branch, not the stable `master` branch. qBittorrent is only published with LibTorrent 2.x, and the README links to an issue for more information. This is a significant limitation for users who want a stable release of these apps, because the `develop` branch is by definition a development version. The project also avoids tools like s6-overlay, which is a process supervisor that some container images use to manage multiple processes. The README states that the project adheres to one process per container, which is a cleaner model but means you cannot bundle helper processes. The KISS principle is cited. These choices reduce maintenance burden but narrow the applicability. If you need the stable branch of Sonarr, this project is not for you.

Deprecation policy and maintenance cost

The README describes a deprecation process: containers may be deprecated if the upstream app is no longer maintained, if an official upstream image exists that aligns with the mission, or if the maintenance burden becomes unsustainable. Deprecated containers are announced with a release and remain in the registry for 6 months before removal. This is a clear policy, but it means you must track deprecation announcements, or you may find your image suddenly disappear after six months. The maintenance cost is on the project maintainers, but as a user, you inherit the cost of updating your digests whenever a new release comes out. The monthly release cadence suggests a steady stream of updates. The README encourages using official upstream images when possible, which implies that this project is a fallback, not a primary source. The license is Apache-2.0, which is permissive, but you should check each container's own licensing because the base images may have different terms.

Comparison with linuxserver.io and Bitnami: the real difference

The README explicitly names linuxserver.io and Bitnami as alternatives, but the difference is not just tag immutability. linuxserver.io uses immutable tags, meaning a tag like `latest` is frozen to a specific build and does not move. Bitnami does the same. This project rejects that model. Instead, it uses mutable tags that point to a digest, and forces you to pin to the digest. The README says this ensures functionality and immutability, but it is a different philosophy. With linuxserver.io, you can use `latest` and get a stable, unchanging image. Here, `rolling` or `2025.5.1` can change if the maintainers rebuild the tag, so you must always use the digest. This is more secure in theory, because a digest is unique, but it is less convenient because you have to update your deployment files on every release. The README also mentions that tools like Renovate can update containers based on digest or version changes, which mitigates the manual burden. The real trade-off is between a tag that never changes (linuxserver.io) and a digest that you must verify (this project).

Who should adopt this, and what to check first

Adopt this project if you run self-hosted apps on Kubernetes or Docker Compose and want rootless, multi-arch images that are signed and pinned to a digest. The verification commands are straightforward, and the rootless default is a strong security baseline. Do not adopt it if you need multiple release channels, like the stable branch of Sonarr, or if you rely on s6-overlay to manage processes. Before using any image, verify the SHA256 digest matches the one published in the release notes, check the /config volume path for your app, and test the user mapping against your data volume permissions. The README warns that the config volume is hardcoded and cannot be changed in most cases, so confirm that your app works with that path. Also, note the deprecation policy: if an official upstream image appears, this project may drop the container, so you should have a migration plan. The monthly release cadence means you will need to update your digests regularly, so consider using Renovate or a similar tool to automate that.

Editorial conclusion

Adopt this project if you run self-hosted apps on Kubernetes or Docker Compose and want rootless, multi-arch images that are signed and pinned to a digest. Do not adopt it if you need multiple release channels for apps like Prowlarr or Sonarr, or if you depend on s6-overlay style init. Before using any image, verify the SHA256 digest matches the one published in the release notes, check the /config volume path for your app, and test the user mapping against your data volume permissions.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Community notes

Community notes