GPG is one of those tools everyone keeps meaning to learn and never does. 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. I put it off for years myself.

The thing is, you keep bumping into it. GPG sits under pass, under signed git commits, under encrypted email, under verifying that the binary you just downloaded is the one the maintainer actually shipped. If you care about owning your security instead of trusting a vendor to handle it for you, you end up here eventually.

So here’s the guide I wish someone had handed me. We start with the absolute minimum that does something useful, and add one layer at a time. You can stop reading the moment you have enough.

What is GPG actually?

GPG (GNU Privacy Guard) is an implementation of the OpenPGP protocol. Strip away the jargon and it does two jobs:

  1. Encryption: scramble a file so only the intended recipient can read it
  2. Signing: stamp something so others can verify it came from you

Both jobs run on asymmetric cryptography. You have a public key that you hand out freely, and a private key that never leaves your control.

  • Someone wants to send you a secret → they encrypt with your public key → only you can decrypt it with your private key
  • You want to prove something is from you → you sign with your private key → anyone verifies with your public key

That’s the whole mental model. Everything below is just flags and file formats on top of those two ideas, so if the rest gets confusing, come back to this and it’ll click again.

Your first keypair in 5 minutes

This is the simplest version that actually does something. One command, a handful of questions, and you have working crypto. No subkeys, no hardware, no theory. Get this working first and the rest 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)

Choose (1) RSA and RSA if you want the widest compatibility, or (9) ECC if you want modern, shorter keys. When in doubt, RSA. Everything understands it.

What keysize do you want? (3072)

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

Key is valid for? (0)

Choose 2y (2 years). You can always extend it later. A key with no expiry feels convenient until the day it leaks, because then it stays valid forever and there’s no clock running out to limit the damage. An expiry date is a built-in failsafe.

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

Fill in your name and email. Leave the comment empty.

Enter passphrase:

Pick a strong passphrase here. If someone ever gets hold of your private key file, this passphrase is the only thing standing between them and your identity. Treat it accordingly.

Done. You have a working GPG keypair. That was the hard part of getting started, and it’s already behind you.

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 (fingerprint). People often use the short version, the last 16 characters: MNO345PQR678STU9.

Immediately useful: encrypting files

First layer of real usage. You have a key, now let’s actually do something with it. Encryption is the most immediately satisfying part, so we start here.

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 didn’t have to agree on a shared password over some side channel, which is the whole point of public key crypto.

Symmetric encryption (password)

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

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

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

Signing: proving something is 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 got modified after signing or the signature doesn’t belong to that key. Either way, don’t trust it.

Signing git commits

If you only ever use GPG for one thing, this is probably the thing. It’s the bit of GPG I touch every single day without thinking about it.

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. That badge is doing real work: it tells reviewers the commit actually came from you and wasn’t forged by someone setting user.email to your address.

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 let’s get it out into the world. There are a few ways, ranging 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 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 control rather than a third-party keyserver you don’t.

Going deeper: subkeys

Everything up to here works with the single keypair you generated at the start. That’s fine for getting going. But if you’re going to lean on GPG long term, this is the layer that makes it sustainable, so it’s worth understanding even if you don’t set it up today.

GPG supports subkeys: separate keys that hang underneath your master key.

Why bother with subkeys?

Your master key is your identity. If it’s compromised, you’ve lost the thing that proves you are you, and there’s no clean recovery. Subkeys let you keep that crown jewel out of harm’s way:

  • Your master key lives offline, in cold storage
  • Subkeys do the day-to-day work
  • If a subkey leaks, you revoke just that subkey and carry on
  • Your identity, the master key, stays untouched

The principle here is the same one behind keeping backups offline or limiting a service account’s permissions: shrink the blast radius so a single slip-up doesn’t take down everything.

Subkey structure

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 is the step that 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

Now your daily machine only carries subkeys. The master key sits on a USB stick in a drawer, or wherever you trust. If your 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

Hardware keys: YubiKey

This is the deepest layer, and honestly most people never need it. But if you want your private keys to physically refuse to leave the device they live on, a hardware token is how you get there.

Why?

  • The keys never leave the hardware, full stop
  • Malware on your laptop can’t copy what it can’t read
  • An attacker needs the physical YubiKey in hand, not just remote access

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 now on, signing or decrypting means plugging in the YubiKey and tapping it. A bit of friction in exchange for keys that can’t be silently exfiltrated.

GPG + SSH with YubiKey

Here’s a nice bonus: your GPG authentication subkey can double 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 your YubiKey. One hardware token covering both GPG and SSH, which is exactly the kind of consolidation I like.

The honest downsides of GPG

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 real, well-known problems, and you should walk in knowing them.

The UX is genuinely 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 have to 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, and they help a little, but they don’t fix the underlying weirdness.

Key management is complex

  • How do you backup keys safely?
  • How do you rotate keys without breaking everything?
  • How do you revoke a compromised key so everyone knows?
  • How do you share keys with people who don’t understand GPG?

All of these have answers, but the answers aren’t obvious, and you’ll find them by reading docs 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, building a network of trust you could trace. In practice 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 actually 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 reveals who the recipient is, the original filename and size, and when it was encrypted. If you’re in a situation where the existence of a conversation is as sensitive as its contents, that gap matters a lot.

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 dedicated messengers like Signal solved the same problem with a fraction of the friction. I won’t pretend I encrypt my email day to day, because I don’t.

Alternatives exist, and that’s fine

  • age: modern, dead-simple file encryption with no key management ceremony
  • Signal: for messaging, the UX is in a different league
  • Keybase: an honest attempt to make PGP friendly, now owned by Zoom

When GPG is still the right tool

With all that on the table, GPG remains the best option for a handful of jobs:

  • Git commit signing: there’s no real competitor
  • Password managers (pass): GPG is simply the standard it’s built on
  • Software signing: package managers expect GPG signatures, so you meet them where they are
  • Encrypted backups: old, boring, supported everywhere, which is exactly what you want for backups
  • Interoperability: 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. The subkeys live on a YubiKey. In practice I use GPG for three things:

  • Git commit signing
  • Pass, my password manager
  • Encrypting the odd file now and then

For chatting I use Signal, and for quick throwaway encryption I sometimes grab age. GPG doesn’t have to do everything to be worth keeping around.

Practical tips

1. 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 your only copy of a private key and there is no support line to call. The math doesn’t care that it was an accident.

2. Set a calendar reminder for expiry

Keys expire, and that’s by design. But if you forget to extend in time, you can lock yourself out of your own encrypted files. Future you will not be amused.

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

3. 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.

4. Verify fingerprints out-of-band

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

Where to stop

Remember the simplest version from the start: one command, one keypair, working crypto in five minutes. That’s still the whole foundation. Everything after it, subkeys, hardware tokens, keyservers, was optional depth you could add when you needed it.

So 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 genuinely ruin your day, go in with your eyes open.

My advice: start at the shallow end. Generate a key, turn on signed git commits, and live with that for a while. Subkeys and YubiKeys can wait until the day you actually want them.

GPG reminds me of vim. The learning curve is steep and a little hostile, but once you’re over it, you stop noticing the friction and just get the work done. And the work it does, owning your own keys instead of renting trust from a platform, is worth the climb.


Resources: