Ubuntu 20.04 LTS uses Snap to distribute certain packages by default, including Chromium. This was a mistake and yields dysfunctional systems. Here’s how to fix it.

Note

Updated on 2026-08-19. The set of packages Ubuntu ships as snap installers has grown since 2020: on 26.04 it includes Firefox and Thunderbird. More importantly, the pin originally given below does not work, and unattended-upgrades will silently undo the whole procedure if it is not blocked as well. Both are addressed below.

How

Remove all installed snaps:

for p in $(snap list | awk '{print $1}'); do
  sudo snap remove $p
done

Clean up the core package:

sudo systemctl stop snapd
for m in /snap/core/*; do
   sudo umount $m
done
sudo snap remove core
# If anything remains, the steps below will take care of it.

Deinstall snapd:

sudo apt autoremove --purge snapd

Remove leftover directories:

Warning

If you have been running the Firefox or Thunderbird snap, check ~/snap before deleting it. On first start, those snaps copy the profile into ~/snap/<app>/common/.mozilla and keep using that copy, so recent browser state may exist only there.

rm -rf ~/snap
sudo rm -rf /snap
sudo rm -rf /var/snap
sudo rm -rf /var/lib/snapd
sudo rm -rf /var/cache/snapd

Block future installs:

sudo bash -c "cat > /etc/apt/preferences.d/no-snap.pref" <<'EOL'
Package: snapd
Pin: release a=*
Pin-Priority: -1

Package: firefox thunderbird
Pin: release o=Ubuntu
Pin-Priority: -1
EOL

The second stanza states the intent plainly: on current Ubuntu releases, the firefox and thunderbird packages in Ubuntu’s own archive are not the applications. They are transitional debs whose stated purpose is “Installs Firefox snap”, and they carry Pre-Depends: snapd (>= 2.54). In principle the snapd stanza alone already makes them uninstallable, since the pre-dependency can no longer be satisfied. Pinning them directly avoids relying on the resolver to reach that conclusion, and keeps them from being offered in the first place.

Verify with:

apt-cache policy snapd firefox

The Ubuntu versions should show priority -1, and snapd should report Candidate: (none).

Warning

Until 2026 this post recommended Pin: origin "" for snapd. That does not work. An empty origin matches only local (file:) repositories, not http://archive.ubuntu.com. With that pin in place, apt-cache policy snapd still reports priority 500 and snapd remains installable. If you followed the older version of this post, delete /etc/apt/preferences.d/no-snapd.pref and use the file above.

A positive pin on the repository you do want — for instance Pin-Priority: 1000 on packages.mozilla.org — is not a substitute for this, for reasons explained below.

If desired, install Chromium using Debian packages or Chrome from Google’s own .debs.

Beware of unattended-upgrades

unattended-upgrades is enabled out of the box on desktop installs and runs from apt-daily-upgrade.timer. With the ineffective pin given in the original version of this post, it reinstalled snapd together with the Firefox snap overnight, twice in one week, without prompting. The trace is in /var/log/apt/history.log:

Start-Date: 2026-08-19  06:21:21
Commandline: /usr/bin/unattended-upgrade
Install: snapd:amd64 (2.76+ubuntu26.04.3, automatic)
Upgrade: firefox:amd64 (153.0.4~build1, 1:1snap1-0ubuntu8)

Two things combine here. First, Ubuntu’s firefox deb pre-depends on snapd, as described above. Second, its version carries an epoch — 1:1snap1-0ubuntu8 — so it sorts above every upstream build from packages.mozilla.org or the mozillateam PPA, however recent. Whatever you installed from upstream therefore looks, to apt, like an older version of Ubuntu’s snap installer.

Why a positive pin does not help

It is worth spelling out why pinning packages.mozilla.org to priority 1000 does not protect you here, because it is easy to assume it does.

unattended-upgrades does not use apt’s candidate selection. It opens its own cache and rewrites the pin policy first. From pinning_from_config() in /usr/bin/unattended-upgrade:

for pkg_file in self._cache.file_list:
    if not is_allowed_origin(pkg_file, self.allowed_origins):
        # Set the magic 'never' pin on not allowed origins
        pins.append(PkgFilePin(pkg_file.id, NEVER_PIN))   # -32768

Every repository outside Unattended-Upgrade::Allowed-Origins — by default, everything that is not the Ubuntu archive — is pinned to -32768. Your preference file raising packages.mozilla.org to 1000 is discarded with it. In the view that remains, the only firefox in existence is Ubuntu’s snap installer, it comes from an allowed origin, and it has a higher version than what is installed. So it is installed, and snapd follows as a pre-dependency.

The rule to remember: against unattended-upgrades, only a negative pin works. Raising the priority of the repository you want has no effect, because that pin is erased. Pinning the version you do not want to a negative priority does work, because per-package pins on allowed origins are left in place, and a negative priority makes a version uninstallable rather than merely unattractive.

A second layer

The negative pin above is sufficient. If you would rather not depend on pin semantics alone, unattended-upgrades also has an explicit blacklist:

sudo bash -c "cat > /etc/apt/apt.conf.d/51unattended-upgrades-no-snap" <<'EOL'
Unattended-Upgrade::Package-Blacklist { "^snapd$"; "^firefox$"; "^thunderbird$"; };
EOL

The entries are Python regexps matched with re.match, so the anchors are not decorative: a bare firefox would also match firefox-locale-nl and similar.

To confirm what unattended-upgrades intends to do, without letting it act:

sudo unattended-upgrade --dry-run --debug

Its decisions are also logged to /var/log/unattended-upgrades/unattended-upgrades.log. A line reading “Package firefox is kept back … due to local apt_preferences(5)” means the pin is doing its job.

Why

  • Stability: each snap’s upstream vendor can push updates any time they want; updates are mandatory and cannot be blocked. If a regression is introduced, it is not possible to hold back an upgrade or downgrade.
  • Security: each snap image contains all its dependencies. If a security vulnerability is present in a dependency it will remain until the upstream vendor pushes an update, even if the host system has an update already.
  • Cost: upgrades are mandatory and occur as soon as Internet connectivity is available. This incurs mandatory network costs. Snap images are large because they contain all their dependencies. This wastes storage even when storage is at a premium.
  • Performance: snap images are compressed and must be decompressed every time the program is loaded.
  • Compatibility: Snap programs cannot access or store files in directories mounted from secondary storage (secondary hard drive, network filesystem, etc.). Due to architectural restrictions in snapd it is not possible to migrate the data to a different filesystem and use a symlink. It prevents use of profile-sync-daemon.
  • Governance and misaligned incentives: the snap infrastructure is tied to a closed service (“Snap store”) run and controlled by Canonical. It’s not possible to set up additional software channels. Canonical can exert control and could be forced to deploy nefarious softwre to users residing under an authoritarian regime.
  • Filesystem: the snap directory is ~/snap in every home folder. It does not adhere to the filesystem standard (it should be hidden).

Ubuntu defaulting to snap packaging flies in the face of the open source movement and is a disgrace. I hope it will be removed in a later version.

References

Like this post? Share on: BlueSky ❄ Twitter ❄ HN ❄ Reddit ❄ LinkedIn ❄ Email


Raphael Poss Avatar Raphael Poss is an entrepreneur who occasionally publishes field notes on systems, leadership, and the messy edge between technology and people.
Comments

Interested to discuss? Leave your comments below.


Reading Time

~5 min read

Published

Last Updated

Category

Programming

Stay in Touch