I’ve been managing keys since 1997—started on heavy iron back when “remote troubleshooting” meant driving to the data center at 2am. In that time, I’ve seen GnuPG called everything from “obsolete” to “impossible.” The truth is, most of the headaches come from treating 2026 infrastructure like it’s still 1999.

People solve the same thorny problems over and over, usually by making things more complicated than they need to be. If you are still manually syncing private keys across five different laptops via USB drive, you are doing it wrong.

Here is the pragmatic, “physics wins” approach to OpenPGP that I actually use.

The Philosophy: Cattle, Not Pets

We learned long ago in Ops to treat servers like cattle, not pets. Yet, we still treat GPG subkeys like precious heirlooms.

PGP keys have four functions. Two of them—Signing and Authenticating—are fungible. It does not matter which subkey signs your commit, as long as it ties back to your primary identity.

The Rule: Generate a new signing/auth subkey for every single device you own.

  • Laptop died? Revoke that specific subkey.
  • New workstation? Generate a new subkey.
  • Lost access? Who cares? They are trivially replaceable.

The Identity Crisis (UIDs)

A common mistake I see in r/devops is the “Omnibus Key”—one key with fifteen different email addresses attached.

Your primary key is your root identity. If you are signing Git commits for your employer, do not use your personal identity key.

  • Create a specific Primary Key for work. Use your work email as the UID.
  • Create subkeys off that primary.

Result: Your work signatures are tied only to your work identity.

If you leave that job, you revoke the whole key. Clean break.

The Configuration You Actually Need

Default GnuPG settings are suboptimal. We want a clean Ed25519 setup.

1. Create a Cert-Only Primary Key

We want a key that can only certify (manage) other keys.

gpg --quick-generate-key "Your Name <you@work.com>" ed25519 cert

2. Create Your Subkeys

Add the “cattle” keys. We add a signing key for Git, and an encryption key so colleagues can send you secrets (like initial passwords) securely.

gpg --edit-key "you@work.com"
gpg> addkey
# Select (10) ECC (sign only) -> Ed25519
# Valid for? Enter "2y"
gpg> addkey
# Select (12) ECC (encrypt only) -> Cv25519
# Valid for? Enter "2y"
gpg> save

Operational Hygiene: The “Kill Switch”

Before you go any further, generate a revocation certificate.

I once spent a holiday weekend trying to recover a key I’d “safely” stored on a USB drive… which turned out to be an encrypted volume where the password was stored inside that same volume. I had to burn the identity and start over.

Don’t be me. Generate the revocation cert now and print it out on actual paper.

gpg --output revoke.asc --gen-revoke "you@work.com"

Expiration Strategy

I set my subkeys to expire in 2 years. I have a calendar reminder to rotate them annually. To extend a key (when your annual reminder pops up), you must select the specific subkey first.

gpg --edit-key "you@work.com"
gpg> key 1        # Select signing subkey
gpg> expire       # Enter "2y"
gpg> key 1        # Deselect
gpg> key 2        # Select encryption subkey
gpg> expire       # Enter "2y"
gpg> save

The “One True Source”

This is the part that fixes 90% of the “I can’t verify this signature” errors.

Forget public keyservers. They are a mess of spam. The OpenPGP spec allows you to define a preferred-keyserver. It lets you say: “If you want my key, look HERE.”

1. Set the Preference

Tell the key where it lives using the keyserver subcommand.

gpg --edit-key "you@work.com"
gpg> keyserver https://keys.theopsmechanic.com/0xYOURFINGERPRINT.asc
gpg> save

2. Host It

Export the key and push it to your static site (Nginx, Cloudflare Pages, S3, etc).

gpg --armor --export "you@work.com" > static/mykey.asc

Offline the Master Key

People say “keep your master key offline” but rarely explain the mechanics.

Step 0: BACK UP EVERYTHING. Copy your entire ~/.gnupg directory to an encrypted USB drive.

Step 1: Remove the Secret Key We need to remove the master secret key from your laptop while keeping the subkeys active.

# 1. Export your secret SUBKEYS (this strips the master secret key)
gpg --export-secret-subkeys "you@work.com" > subkeys.gpg

# 2. Delete the secret key entirely from your keyring
gpg --delete-secret-key "you@work.com"

# 3. Import the subkeys back in
gpg --import subkeys.gpg

# 4. Clean up the temp file
shred -u subkeys.gpg

Step 2: Verify Run gpg -K (list secret keys). Look for the # symbol next to sec.

sec#  ed25519 2026-01-11 [C]  <-- The '#' means the secret key is NOT here. Good.
ssb   ed25519 2026-01-11 [S]  <-- Signing subkey present.

If you see sec#, you succeeded. Your laptop can sign commits, but it cannot create new subkeys or revoke your identity.

Making git log Actually Useful

We can fix “No Public Key” errors by embedding the URL to your key inside every signature you make.

Add this to your local GPG config:

# ~/.gnupg/gpg.conf
sig-keyserver-url https://keys.theopsmechanic.com/0xYOURFINGERPRINT.asc

The Catch: For this to work automatically, the verifier needs keyserver-options auto-key-retrieve enabled. Even without it, the URL provides a clear breadcrumb to solve the problem manually.

The Cheat Sheet

If you skipped the prose, here is the lifecycle.

1. Generate & Configure

# Create Cert-Only Master
gpg --quick-generate-key "User <email>" ed25519 cert

# Add Subkeys & URL
gpg --edit-key <FINGERPRINT>
gpg> addkey # Select Sign-Only -> "2y" expiry
gpg> addkey # Select Encrypt-Only -> "2y" expiry
gpg> keyserver https://your-domain.com/key.asc
gpg> save

# EMERGENCY BRAKE (Do not skip)
gpg --output revoke.asc --gen-revoke <FINGERPRINT>

2. Offline Master

This is the dangerous part. Focus.

gpg --export-secret-subkeys <FINGERPRINT> > subkeys.gpg
gpg --delete-secret-key <FINGERPRINT>
gpg --import subkeys.gpg
shred -u subkeys.gpg
# Verify: gpg -K must show 'sec#'

3. Distribute & Use

# Upload
gpg --armor --export <FINGERPRINT> > key.asc
# (Upload to https://your-domain.com/key.asc)

# Config
echo "sig-keyserver-url https://your-domain.com/key.asc" >> ~/.gnupg/gpg.conf
git config --global user.signingkey <SUBKEY_FINGERPRINT>
git config --global commit.gpgsign true

Prior Art & Further Reading

I am standing on the shoulders of giants (and paranoid sysadmins) here. If you want to go deeper:

  • Debian Wiki: Offline Master Key — The original bible on splitting master and subkeys.
  • DrDuh’s YubiKey Guide — If you want to take this logic and apply it to hardware tokens (highly recommended for high-security contexts).

Set it up once, correctly. Physics wins.