· · 13 min read Beginner

GPG explained: from first key to daily use

Learn how to use GPG for encryption and signing. From your first keypair to advanced features like subkeys and smartcards.

She seals a letter with a glowing key-shaped stamp while a hundred-handed postman creature fails to open it

TL;DR GPG encrypts files and signs things, and it sits under pass, under signed git commits and under the checksums maintainers publish. One command gives you a working keypair in five minutes. Subkeys and a YubiKey come later, if ever, and the UX is bad enough that I complain about it at length below.

GPG is a tool I kept meaning to learn and didn’t, for years. The docs are a wall of text, the terminology is its own dialect, and the error messages are cryptic in both senses of the word.

You keep bumping into it anyway. GPG sits under pass, under signed git commits, under encrypted email, under checking that the binary you just downloaded is the one the maintainer shipped. If you’d rather own your security than hand it to a vendor, you end up here sooner or later.

So here’s the guide I wish someone had handed me. It starts with the least that does something, and you can stop reading the moment you have enough.

What GPG does

GPG (GNU Privacy Guard) implements the OpenPGP protocol, and under the jargon it has two jobs. It encrypts a file so only the intended recipient can read it, and it signs something so other people can check it came from you.

Both run on asymmetric cryptography. You have a public key you hand out freely and a private key that never leaves your control. Someone who wants to send you a secret encrypts it with your public key, and only your private key opens it. When you want to prove something is yours, you sign it with your private key and anyone can check it against the public one.

Everything below is flags and file formats on top of those two ideas. If the rest gets confusing, come back to this paragraph.

Your first keypair in 5 minutes

One command, a handful of questions, and you have working crypto. No subkeys, no hardware, no theory. Get this working first; everything after it is optional.

Installation

# macOS
brew install gnupg

# Debian/Ubuntu
sudo apt install gnupg

# Arch
sudo pacman -S gnupg

Generate keypair

gpg --full-generate-key

It’ll ask you a few things.

Please select what kind of key you want:
   (1) RSA and RSA
   (9) ECC (sign and encrypt)

Pick (1) RSA and RSA for the widest compatibility, or (9) ECC for modern, shorter keys. When in doubt, RSA. Everything understands it.

What keysize do you want? (3072)

4096 for RSA. Bigger is fine here, within reason.

Key is valid for? (0)

2y, so 2 years. You can extend it later. A key with no expiry feels convenient right up to the day it leaks, because then it stays valid forever and nothing limits the damage. An expiry date is a failsafe you set once.

Real name: Tom Meurs
Email address: tom@example.com
Comment:

Your name and email. Leave the comment empty.

Enter passphrase:

Pick a strong passphrase. If someone ever gets hold of your private key file, this passphrase is all that stands between them and your identity.

Done. You have a working GPG keypair, and that was the hard part of getting started.

View keys

# List your public keys
gpg --list-keys

# List your private keys
gpg --list-secret-keys

Output looks like this:

pub   rsa4096 2026-01-26 [SC] [expires: 2028-01-26]
      ABC123DEF456GHI789JKL012MNO345PQR678STU9
uid           [ultimate] Tom Meurs <tom@example.com>
sub   rsa4096 2026-01-26 [E] [expires: 2028-01-26]

That long string is your key ID, the fingerprint. People often use the short version, the last 16 characters: MNO345PQR678STU9.

Encrypting a file

You have a key, so let’s use it. Encryption is the part you’ll feel first, so it comes first.

Encrypt for yourself

# Encrypt a file
gpg --encrypt --recipient tom@example.com secret.txt
# Creates secret.txt.gpg

# Decrypt
gpg --decrypt secret.txt.gpg > secret.txt

Encrypt for someone else

First you need their public key:

# Import a public key
gpg --import colleague-key.asc

# Or fetch from a keyserver
gpg --keyserver keyserver.ubuntu.com --recv-keys THEIR_KEY_ID

Then encrypt:

gpg --encrypt --recipient colleague@example.com secret.txt

Now only they can open it. You never had to agree on a shared password over some side channel, and that’s what public key crypto is for.

Symmetric encryption with a password

Sometimes you don’t want keys at all, just a password:

gpg --symmetric secret.txt
# Asks for password, creates secret.txt.gpg

Handy for a quick one-off. It’s weaker than the asymmetric route, because everything rests on one password you have to remember and somehow share, so I use it only when keys would be overkill.

Proving something came from you

Sign a file

# Create a detached signature
gpg --detach-sign document.pdf
# Creates document.pdf.sig

# Or embed the signature
gpg --sign document.pdf
# Creates document.pdf.gpg (signed + compressed)

# Or clearsign (readable with signature embedded)
gpg --clearsign message.txt
# Creates message.txt.asc

Verify signature

gpg --verify document.pdf.sig document.pdf

Output:

gpg: Signature made Mon Jan 26 12:00:00 2026 CET
gpg: using RSA key ABC123...
gpg: Good signature from "Tom Meurs <tom@example.com>"

If you ever see “BAD signature”, the file changed after it was signed or the signature belongs to another key. Either way, don’t trust it.

Signing git commits

If you only ever use GPG for one thing, make it this one. It’s the bit of GPG I touch every day without noticing.

Configure git

# Tell git which key to use
git config --global user.signingkey YOUR_KEY_ID

# Automatically sign all commits
git config --global commit.gpgsign true

# Automatically sign all tags
git config --global tag.gpgsign true

Create signed commit

git commit -S -m "This commit is signed"

GitHub and GitLab put a “Verified” badge next to signed commits. The badge tells a reviewer the commit came from you and wasn’t forged by someone who set user.email to your address, which anyone can do.

Add your public key to GitHub

# Export your public key
gpg --armor --export tom@example.com

Copy the output, including the -----BEGIN PGP PUBLIC KEY BLOCK----- line, and paste it into GitHub under Settings, then SSH and GPG keys, then New GPG key.

Sharing your public key

A signature is useless to anyone who doesn’t have your public key, so it has to get out into the world. There are a few ways, from “email it” to “put it on a keyserver”.

Export

# As ASCII (for email, websites)
gpg --armor --export tom@example.com > tom-public.asc

# As binary
gpg --export tom@example.com > tom-public.gpg

Upload to a keyserver

gpg --keyserver keyserver.ubuntu.com --send-keys YOUR_KEY_ID

Now anyone can find your key with:

gpg --keyserver keyserver.ubuntu.com --search-keys tom@example.com

Put it on your website

Plenty of people host their public key at example.com/.well-known/openpgpkey/ or just example.com/pgp.asc. Hosting it yourself means people fetch it from infrastructure you run rather than a keyserver somebody else runs.

Subkeys, so the master key can go offline

Everything up to here works with the one keypair you generated at the start, and for getting going that’s fine. If you’re going to lean on GPG for years, subkeys are what make that bearable, so read this even if you set it up later.

GPG supports subkeys, separate keys that hang under your master key.

Why subkeys

Your master key is your identity. Lose control of it and you’ve lost the thing that proves you’re you, with no clean way back. Subkeys keep that key out of harm’s way. The master key lives offline, in cold storage. Subkeys do the day-to-day work. If a subkey leaks, you revoke that one subkey and carry on, and the master key, your identity, stays untouched.

It’s the same principle as keeping backups offline or trimming a service account’s permissions. Shrink the blast radius, so one slip doesn’t take everything with it.

Subkey structure

A typical setup:

Master key [C] (certify) - keep offline
├── Subkey [S] (signing) - daily use
├── Subkey [E] (encryption) - daily use
└── Subkey [A] (authentication) - SSH login

Create subkeys

gpg --edit-key tom@example.com

In the GPG prompt:

gpg> addkey
Please select what kind of key you want:
   (4) RSA (sign only)
   (6) RSA (encrypt only)

# Create a sign-only subkey
# Create an encrypt-only subkey

gpg> save

Take the master key offline

This step takes a bit of nerve, because you’re about to delete secret key material from your daily machine on purpose:

# Export everything (backup!)
gpg --armor --export-secret-keys tom@example.com > master-backup.asc

# Export only subkeys
gpg --armor --export-secret-subkeys tom@example.com > subkeys.asc

# Delete secret keys from your machine
gpg --delete-secret-keys tom@example.com

# Import only the subkeys
gpg --import subkeys.asc

Your daily machine now carries subkeys only. The master key sits on a USB stick in a drawer, or wherever you trust. If the laptop gets stolen or owned, the attacker gets subkeys you can revoke, not the key that defines you.

gpg --list-secret-keys
# sec#  rsa4096 ...  ← that # means the master key isn't present

Moving the subkeys to a YubiKey

Most people never need this, and I won’t push you there. But if you want your private keys to physically refuse to leave the device they live on, a hardware token is how.

What the hardware buys you

The keys never leave the hardware, full stop. Malware on your laptop can’t copy what it can’t read. And an attacker needs the physical YubiKey in hand, not just a shell on your machine.

Move keys to YubiKey

gpg --edit-key tom@example.com

gpg> key 1  # select subkey
gpg> keytocard
Please select where to store the key:
   (1) Signature key
   (3) Authentication key

gpg> key 2  # select next subkey
gpg> keytocard

gpg> save

From then on, signing or decrypting means plugging in the YubiKey and tapping it. A small pause every time, in exchange for keys nobody can copy off your disk.

GPG + SSH with YubiKey

There’s a bonus. Your GPG authentication subkey doubles as your SSH key.

# In ~/.bashrc or ~/.zshrc
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)

# Enable SSH support in gpg-agent
echo "enable-ssh-support" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent

Now ssh authenticates through the YubiKey. One hardware token for both GPG and SSH, which is exactly the kind of consolidation I like.

The downsides

I’d be selling you something if I stopped here and pretended GPG is a joy to use. It isn’t. It’s a powerful tool with well-known problems, and you should walk in knowing them.

The UX is bad

GPG was designed in the ’90s and it shows. The command-line interface is inconsistent, the error messages are cryptic, and routine tasks hide behind flags you look up every time.

gpg: decryption failed: No secret key
# What does this mean? Key expired? Wrong key? No idea.

There are GUIs like Kleopatra and GPG Keychain. They help a little. They don’t fix the underlying weirdness.

Key management is complex

How do you back up keys safely? Rotate them without breaking everything? Revoke a compromised key so everyone hears about it? Share keys with people who don’t understand GPG? All of these have answers, none of them obvious, and you’ll go looking at the worst possible moment, like when a key is about to expire.

Web of Trust is effectively dead

The original PGP idea was that people sign each other’s keys and build a network of trust you could trace. Almost nobody does this anymore. Most people import a key and trust it because the fingerprint looked roughly right, which isn’t much of a trust model.

Keyservers are a mess

The classic keyservers are often slow or offline, can’t verify that an upload belongs to the person it claims, and have a history of spam and abuse. The old SKS keyserver network is largely broken at this point.

The better option is keys.openpgp.org, which at least verifies that you control the email address on the key before it’ll serve it.

Metadata leaks

GPG encrypts the contents and nothing else. The encrypted blob still shows who the recipient is, the original filename and size, and when it was encrypted. If the existence of a conversation is as sensitive as its contents, that gap matters.

Email encryption never took off

PGP email, through tools like Enigmail, never reached normal people. The setup is too fiddly, the UX too rough, and Signal solved the same problem with a fraction of the effort. I don’t encrypt my email day to day, and I won’t pretend otherwise.

Alternatives exist, and that’s fine

age does modern, dead-simple file encryption with no key management ceremony. Signal handles messaging with a UX in a different league. Keybase was an earnest attempt to make PGP friendly, and it’s owned by Zoom now.

When GPG is still the right tool

With all that on the table, GPG stays the best option for a handful of jobs. Git commit signing has no serious competitor. pass is built on GPG, so a password manager in the terminal means GPG. Package managers expect GPG signatures on software, so you meet them where they are. For encrypted backups it’s old, boring and supported everywhere, which is exactly what you want from a backup. And anyone with GPG can read what you send, no account or app required.

My setup

# ~/.gnupg/gpg.conf
default-key ABC123...
keyserver hkps://keys.openpgp.org
auto-key-retrieve

# Modern crypto preferences
personal-cipher-preferences AES256 AES192 AES
personal-digest-preferences SHA512 SHA384 SHA256
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed

My master key lives on an air-gapped machine and the subkeys live on a YubiKey. Day to day I use GPG for three things. Git commit signing, pass, and the odd file now and then. Signal for chat, and age when I want throwaway encryption. GPG doesn’t have to do everything to be worth keeping around.

Practical tips

Back up your keys

# Now. Before you forget.
gpg --armor --export-secret-keys > ~/backup/gpg-secret-keys.asc
gpg --armor --export > ~/backup/gpg-public-keys.asc
gpg --export-ownertrust > ~/backup/gpg-ownertrust.txt

Put this on an encrypted USB stick, somewhere safe, and do it now. Lose the only copy of a private key and there’s no support line to call.

Set a calendar reminder for expiry

Keys expire, and that’s by design. Forget to extend in time and you can lock yourself out of your own encrypted files.

gpg --edit-key tom@example.com
gpg> expire
# Choose new date
gpg> save

Use a good passphrase

Your passphrase is the lock on your private key. Make it long and unpredictable, and let a password manager remember it, so you’re not tempted to pick something you can type from memory.

Verify fingerprints out-of-band

When you import someone’s public key, confirm the fingerprint through a separate channel, a phone call or in person. Keyservers can be compromised. A fingerprint you checked yourself is worth more than one a server handed you.

Where to stop

One command, one keypair, working crypto in five minutes. That’s still the foundation. Subkeys, hardware tokens and keyservers are depth you add when you need it, and not before.

Is GPG worth learning? Yes, if you want to sign git commits, use pass, encrypt files properly or verify software you download. Skip it if all you want is secure chat, where Signal wins, or trivial file encryption, where age is friendlier. And if CLI papercuts ruin your day, go in with your eyes open.

Start at the shallow end. Generate a key, turn on signed git commits, and live with that for a while. Subkeys and a YubiKey can wait until the day you want them. I sign every commit with a subkey on a YubiKey, and I still look up the flag for a detached signature every time I need one.


Further reading: