GPG is one of those tools everyone “should learn someday” but nobody wants to. The documentation is overwhelming, the terminology confusing, and the error messages cryptic (pun intended).

But GPG is also essential. It’s the foundation for pass, for signed git commits, for encrypted email, and for verifying software downloads. If you’re serious about security, you can’t avoid it.

This is the guide I wish I had when I started.

What is GPG actually?

GPG (GNU Privacy Guard) is an implementation of the OpenPGP protocol. It does two things:

  1. Encryption: Encrypt files so only the intended recipient can read them
  2. Signing: Digitally sign so others can verify something came from you

This works with asymmetric cryptography: you have a public key (which you share) and a private key (which you keep secret).

  • Someone wants to send you a secret → encrypts with your public key → only you can decrypt with your private key
  • You want to prove something is from you → sign with your private key → others verify with your public key

That’s it. The rest is implementation details.

Your first keypair in 5 minutes

Installation

# macOS
brew install gnupg

# Debian/Ubuntu
sudo apt install gnupg

# Arch
sudo pacman -S gnupg

Generate keypair

gpg --full-generate-key

You’ll get a few questions:

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

Choose (1) RSA and RSA for maximum compatibility, or (9) ECC for modern, shorter keys.

What keysize do you want? (3072)

Choose 4096 for RSA. More is better (within reasonable limits).

Key is valid for? (0)

Choose 2y (2 years). You can extend later. A key without expiry is risky — if you lose it, it’s valid forever.

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

Fill in your name and email. Comment can be empty.

Enter passphrase:

Choose a strong passphrase. This is the last line of defense if someone steals your private key.

Done. You now have a GPG keypair.

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). The short version (last 16 characters) is often used: MNO345PQR678STU9.

Immediately useful: encrypting files

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

Only they can decrypt it now.

Symmetric encryption (password)

No keys needed, just a password:

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

Handy for quick-and-dirty encryption, but less secure than asymmetric.

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 see “BAD signature”, the file was modified or the signature is fake.

Signing git commits

This is perhaps the most practical use case for GPG.

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/GitLab show a “Verified” badge on signed commits.

Add your public key to GitHub

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

Copy the output (including -----BEGIN PGP PUBLIC KEY BLOCK-----) and paste in GitHub → Settings → SSH and GPG keys → New GPG key.

Sharing your public key

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

Many people put their public key at example.com/.well-known/openpgpkey/ or simply example.com/pgp.asc.

Deep dive: subkeys

So far you have one keypair. But GPG supports subkeys: separate keys that hang under your master key.

Why subkeys?

Your master key is sacred. If it’s compromised, everything is lost. With subkeys:

  • Your master key stays offline (cold storage)
  • Subkeys are used daily
  • If a subkey leaks, you only revoke that subkey
  • Your identity (master key) remains intact

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 master key offline

This is where it gets serious:

# 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 you only have subkeys on your machine. The master key is safely on a USB stick in a vault.

gpg --list-secret-keys
# sec#  rsa4096 ...  ← the # means: master key not present

Hardware keys: YubiKey

The ultimate setup: your private keys on a hardware token.

Why?

  • Keys never leave the hardware
  • Malware can’t steal your keys
  • Physical security (you need the YubiKey)

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

Now you must connect the YubiKey to sign or decrypt.

GPG + SSH with YubiKey

You can use GPG authentication keys for SSH:

# 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 works via your YubiKey. One hardware token for GPG and SSH.

The downsides of GPG

And here’s where I’m being honest. GPG has serious problems.

The UX is terrible

GPG was designed in the ’90s and it feels like it. The command-line interface is inconsistent, error messages are cryptic, and simple tasks require obscure flags.

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

There are GUIs (Kleopatra, GPG Keychain), but they’re not great either.

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?

These are solved problems, but the solutions aren’t intuitive.

Web of Trust is effectively dead

The original PGP model was: people sign each other’s keys to build trust. In practice, almost nobody does this. Most people trust keys based on… hoping it’s correct.

Keyservers are problematic

Keyservers are:

  • Often slow or offline
  • Cannot verify if uploads are legitimate
  • Have had spam/abuse in the past
  • SKS keyserver network is largely broken

Alternative: keys.openpgp.org verifies email addresses.

Metadata leaks

GPG encrypts the content, but not:

  • Who the recipient is (visible in encrypted blob)
  • Filename and size
  • When it was encrypted

For high-risk situations this is a problem.

Email encryption has largely failed

PGP email (via Enigmail, etc.) never achieved mainstream adoption. The setup is too complex, the UX too poor, and alternatives (Signal, encrypted messaging) are much more user-friendly.

Alternatives exist

  • age: Modern, simple encryption tool. No key management hassle.
  • Signal: For messaging, much better UX.
  • Keybase: Was an attempt to make PGP user-friendly (now part of Zoom).

When GPG is the right choice

Despite the downsides, GPG is still the best option for:

  • Git commit signing: No good alternative
  • Password managers (pass): GPG is the standard
  • Software signing: Package managers expect GPG signatures
  • Encrypted backups: Battle-tested, widely supported
  • Interoperability: Anyone with GPG can read your messages

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 is on an air-gapped machine. Subkeys are on a YubiKey. I use GPG primarily for:

  • Git commit signing
  • Pass (password manager)
  • Occasionally encrypting files

For messaging I use Signal. For ad-hoc encryption sometimes age.

Practical tips

1. Backup 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. In a vault. Seriously.

2. Set a calendar reminder for expiry

Keys expire. If you don’t extend in time, you can’t decrypt your own files anymore.

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

3. Use a good passphrase

Your passphrase protects your private key. Make it long, unpredictable, and use a password manager to store it.

4. Verify fingerprints out-of-band

When you import someone’s public key, verify the fingerprint via another channel (phone, in person). Keyservers can be hacked.

Conclusion

GPG is powerful but complex. It’s the de-facto standard for asymmetric cryptography on the command line, but the UX is a constant source of frustration.

Is it worth learning? Yes, if you:

  • Want to sign git commits
  • Want to use pass
  • Want to encrypt files securely
  • Want to verify software

No, if you:

  • Just want to chat securely (use Signal)
  • Want simple file encryption (consider age)
  • Can’t handle CLI frustration

Start simple: generate a key, sign your git commits, and build from there. You don’t need to understand subkeys and YubiKeys right away. That comes later, when you’re ready.

GPG is like vim: a steep learning curve, but once you’re over the hill, you won’t want to go back.


Resources: