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?
Best Answer
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
andSNAP_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 inSNAP_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 inSNAP_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
andSNAP_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 inSNAP_DATA
orSNAP_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 usesnap run --shell <snap>.<app>
, for example: