Skip to content
ohsudo, Home
Linux

apt "GPG error: NO_PUBKEY": add the key the right way, without apt-key

Fix apt "GPG error: The following signatures couldn't be verified: NO_PUBKEY": add the vendor's key to /etc/apt/keyrings with signed-by, and why apt-key is gone.

Intermediate4 min readApplies to Ubuntu 22.04+ · Debian 11+ · apt 2.x

by OhSudo ··

Checked on real software: Ubuntu 24.04, apt · November 2026How we check

Err:3 https://download.docker.com/linux/ubuntu noble InRelease
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8
W: GPG error: https://download.docker.com/linux/ubuntu noble InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8
E: The repository 'https://download.docker.com/linux/ubuntu noble InRelease' is not signed.

Each repository signs its packages, so that your machine can check they really come from there. apt has a repository in its list, and doesn’t have the key that verifies its signature.

The error gives you what you need: which repository, and which key. The fix is getting that key from the vendor and telling apt to use it for that one repository.

  1. Repositorysigns its package lists
  2. apt updatechecks the signature
  3. NO_PUBKEYno key to verify it with(breaks here)
apt checks every repository's signature with a key it already has. The repository is in the list; the key that verifies it isn't.

TL;DR

Using Docker as an example, with the address from the vendor’s install page:

Terminal window
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update

1. See which repository it is

The URL is in the error, and it’s what you need to identify. Find where it’s configured:

Terminal window
grep -rl 'download.docker.com' /etc/apt/sources.list /etc/apt/sources.list.d/

Do you still need it? Removing a repository you no longer use is often the best fix:

Terminal window
sudo rm /etc/apt/sources.list.d/old-thing.list
sudo apt update

2. Get the key from the vendor

Look up the install instructions on the vendor’s own site, which give the key’s address. A key comes in one of two formats:

Terminal window
curl -fsSL https://example.com/key.asc -o /tmp/key
file /tmp/key
file says Format What to do
PGP public key block Text (“armored”) Convert it with gpg --dearmor
OpenPGP Public Key or PGP/GPG key public ring Binary Copy it as it is

Then check that it’s the key your error asked for:

Terminal window
gpg --show-keys --keyid-format long /tmp/key

The output should contain 7EA0A9C3F273FCD8 or end with it. If it doesn’t, stop. You have the wrong key, or something’s wrong with the source.

3. Install it, for that repository only

Terminal window
sudo install -m 0755 -d /etc/apt/keyrings
sudo gpg --dearmor -o /etc/apt/keyrings/vendor.gpg /tmp/key
sudo chmod a+r /etc/apt/keyrings/vendor.gpg

Then point the repository’s line at it, in /etc/apt/sources.list.d/vendor.list:

deb [signed-by=/etc/apt/keyrings/vendor.gpg] https://example.com/apt stable main

Or in the newer format, in a .sources file:

Types: deb
URIs: https://example.com/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/vendor.gpg

Then run sudo apt update.

signed-by is what makes this better than the old way, as this key is only trusted for this one repository.

4. Why not apt-key?

Old guides show this:

Terminal window
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7EA0A9C3F273FCD8 # don't

apt-key is deprecated, and gone from recent Debian and Ubuntu releases, so you might see apt-key: command not found. It’s also how you get this warning on systems that still have it:

W: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

The problem is that a key in that shared keyring is trusted for every repository. A vendor’s key could then sign packages that look as though they come from Ubuntu. To move an old key to its own file:

Terminal window
sudo apt-key list
sudo apt-key export 7EA0A9C3F273FCD8 | sudo gpg --dearmor -o /etc/apt/keyrings/vendor.gpg
sudo apt-key del 7EA0A9C3F273FCD8

Then add signed-by as in section 3.

5. Other causes

A PPA. add-apt-repository normally imports the key by itself. If it failed:

Terminal window
sudo add-apt-repository --remove ppa:name/here
sudo add-apt-repository ppa:name/here

A vendor rotated its key. A key that worked last month now shows NO_PUBKEY or EXPKEYSIG. Download the new key from the vendor’s instructions, and overwrite your file.

An expired key. EXPKEYSIG means the key you have is past its date, and apt-key list or gpg --show-keys shows the date. Get the current one in the same way.

A clock that’s wrong. A machine with a date far in the past gets similar errors, including Release file … is not valid yet. Check timedatectl.

A corporate proxy that inspects traffic, and can return a page instead of the key. Run file /tmp/key to check what you downloaded. An HTML document isn’t a key.

The keys themselves. Ubuntu’s own archive key is in ubuntu-keyring, and Debian’s in debian-archive-keyring. If those are the ones missing, usually on an old release, reinstalling helps: sudo apt install --reinstall ubuntu-keyring.

6. In a Dockerfile

The commands are the same, and need curl and gnupg first, as images don’t have them. Keep it in a single RUN:

RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl gnupg \
&& install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg

A permission denied when reading that file usually means it wasn’t made readable with chmod a+r, since apt uses a separate user to read it.

Warning

Never use [trusted=yes], --allow-unauthenticated or --allow-insecure-repositories to get past this. They turn off the check that stops anyone on the network, or at the source, from feeding your server a fake package that runs as root. If you can’t get a key that matches, then don’t install from there.

Shell, we have a problem!

Similar, but different: E: Unable to locate package means the name isn’t in your list: see that article. The repository … does not have a Release file is usually an unsupported release, or a wrong URL. Temporary failure resolving is DNS. And on RHEL, the same thing is GPG check FAILED, solved with rpm --import and the vendor’s key.

Found this useful? Share it.

Found a mistake? Let us know at contact@ohsudo.com.

Articles

Related articles