Skip to main content Link Menu Expand (external link) Document Search Copy Copied

OSTree and /var handling

  1. OSTree and /var handling
    1. Default commit/image /var handling
    2. Pitfalls
    3. Examples
      1. debs/RPMs which drop files into /opt (i.e. /var/opt)
      2. Apache default content in /var/www/html
      3. User home directories and databases
      4. /var/lib/containers
      5. dnf /var/lib/dnf/history.sqlite
    4. Previous ostree /var and tmpfiles.d /usr/share/factory/var

Default commit/image /var handling

As of OSTree 2024.3, when a commit is “deployed” (queued to boot), the initial content of /var in a commit will be placed into the “stateroot” (default var) if the stateroot var is empty.

The semantics of this are intended to match that of Docker “volumes”; consider that ostree systems have the equivalent of VOLUME /var by default.

It is still strongly recommended to use systemd tmpfiles.d snippets to populate directory structure and the like in /var on firstboot, because this is more resilent.

Even better, use StateDirectory= for systemd units.


On subsequent upgrades, normally /var would not be empty anymore (as it’s typically expected that basics like /var/tmp etc. are created, if not also other local state such as /var/log etc.). Hence, no updates from the commit/container will be applied.

To be clear then:

  • Any files which already exist will not be updated.
  • Any files which are deleted in the new version will not be deleted on existing systems.


debs/RPMs which drop files into /opt (i.e. /var/opt)

The default OSTree “strict” layout has /opt be a symlink to /var/opt. Including any packaged content that “straddles” /usr and /var (i.e. /var/opt) will over time cause drift because changes in the package will not be reflected on disk.

For situations like this, it’s strongly recommended to enable either composefs.enabled = true or the root.transient = true option for ostree-prepare-root.conf and change ensure your commit/container image has /opt as a plain directory. In the former case, content in /opt will be immutable at runtime, the same as everything else in /usr. In the latter case content it will be writable but transient.

There’s also a currently-experimental ../man/ostree-state-overlay@.service.xml which can manage stateful writable overlays for individual mounts.

Apache default content in /var/www/html

In general, such static content would much better live in /usr - or even better, in an application container.

User home directories and databases

The semantics here are likely OK for the use case of “default users”.


Pulling container images into OSTree commits like this would be a bad idea; similar problems as RPM content.

dnf /var/lib/dnf/history.sqlite

For $reasons dnf has its own database for state distinct from the RPM database, which on rpm-ostree systems is in /usr/share/rpm (under the read-only bind mount, managed by OS updates).

In an image/container-oriented flow, we don’t really care about this database which mainly holds things like “was this package user installed”. This data could move to /usr.

Previous ostree /var and tmpfiles.d /usr/share/factory/var

From OSTree versions 2023.8 to v2024.3 the /usr/lib/tmpfiles.d/ostree-tmpfiles.conf file included this snippet:

# Automatically propagate all /var content from /usr/share/factory/var;
# the ostree-container stack is being changed to do this, and we want to
# encourage ostree use cases in general to follow this pattern.
C+! /var - - - - -

Until version 0.13.2 of the ostree-ext project, content in /var in fetched container images is moved to /usr/share/factory/var, but this no longer happens when targeting ostree v2024.3.

Together, this will have the semantic that on OS updates, on the next boot (early in boot), any new files/directories will be copied. For more information on this, see man tmpfiles.d.

This has been reverted, and the semantics defer to the above ostree semantic.