Where can Ubuntu snaps write data?
Applications packaged as snaps in Ubuntu are installed (mounted) under the /snap/$SNAPPNAME
location. Everything under /snap
is mounted as a read-only file system, thus applications cannot write to that space, neither in other app's directories nor in their own.
While there is a home
interface that snaps can specify to read/write the user's home directory, it is reserved for security reasons and needs to be manually connected (enabled) by the user.
So where can an app inside a snap write its config, data and other files? Are there APIs to access special writeable locations?
Solution 1:
When you declare apps in your snapcraft.yaml
, it results in a binary wrapper being generated upon install and placed into /snap/bin/
, named after your package and app name (note that if the app is a service, this wrapper is instead a systemd .service file).
That wrapper contains most of the environment under which the application will run. The two environment variables that are most relevant to this question are SNAP_DATA
and SNAP_USER_DATA
. You can find more information about these in the documentation, but I'll describe them here as well:
SNAP_DATA
is a system-wide writable area (in/var/snap/
). This might be used to host logs for services, for instance.SNAP_USER_DATA
is a user-specific writable area in the home directory of the user running the application (specifically/home/<user>/snap/
). This might be used for user-specific configuration files, etc.
Both of these directories are very important to the upgrade/rollback functionality, since both of them are versioned. That is, each revision of a given snap has its own copy of these directories. Let me explain with an example.
Say you install revision 1 of the "foo" snap. That will create two directories:
-
/var/snap/foo/1
(SNAP_DATA
) -
/home/<user>/snap/foo/1
(SNAP_USER_DATA
)
Now say "foo" uses both of these. Maybe it has a service that hosts a database in SNAP_DATA
, and a binary that uses config files in SNAP_USER_DATA
.
Now revision 2 of "foo" is released, and it's automatically updated. The first thing that happens is that /var/snap/foo/1
is copied into /var/snap/foo/2
and /home/<user>/snap/foo/1
is copied into /home/<user>/snap/foo/2
. Then the new revision is fired up. It should notice that it's running on old data, and maybe it has some database migrations to run to the database in SNAP_DATA
. It does that, and away it goes.
Now say those migrations fail for whatever reason, and this application needs to be rolled back. It begins using the old revision of the /snap/foo application, where SNAP_DATA
was pointing to /var/snap/foo/1
and SNAP_USER_DATA
was pointing to /home/<user>/snap/foo/1
. This picks things up on the old version at the point before the migrations were run, since those operations were run on a copy of the data.
Long story short: don't use the home
interface to store data you can be storing in SNAP_DATA
or SNAP_USER_DATA
, since they're an integral part of the upgrade/rollback strategy. Take advantage of them!
UPDATE for v2.0.10:
Two new data directories were also introduced:
SNAP_COMMON
sits alongsideSNAP_DATA
, but is specifically unversioned. Every revision of the specific snap has access to this directory, so it's not copied upon upgrade/rollback etc. This might be used for particularly large, unversioned files (e.g. raw data that isn't really version-specific).SNAP_USER_COMMON
sits alongsideSNAP_USER_DATA
, but is again specifically unversioned. It might be used for storing non-version-specific data per user.
UPDATE for v2.15:
The files placed within /snap/bin
are no longer wrappers that define the environment, but symlinks to /usr/bin/snap
. So the way to determine the environment under which an application runs would be to use snap run --shell <snap>.<app>
, for example:
$ sudo snap install hello-world
$ snap run --shell hello-world
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
$ env | grep SNAP
SNAP_USER_COMMON=/home/kyrofa/snap/hello-world/common
SNAP_REEXEC=
SNAP_LIBRARY_PATH=/var/lib/snapd/lib/gl:
SNAP_COMMON=/var/snap/hello-world/common
SNAP_USER_DATA=/home/kyrofa/snap/hello-world/27
SNAP_DATA=/var/snap/hello-world/27
SNAP_REVISION=27
SNAP_NAME=hello-world
SNAP_ARCH=amd64
SNAP_VERSION=6.3
SNAP=/snap/hello-world/27