GnuPG Configuration and Usage Guide
Create a primary key
The primary key is the corner stone in the Web of Trust for proving your identity. Once compromised, you need to start all over from scratch again. Therefore, it must be kept safe. One possible policy is to keep the primary key offline in an encrypted removable drive, and only distribute per-device subkeys for daily signing.
Suppose we are Alice. On the removable drive, create GnuPG home directory:
mkdir .gnupg
Give the directory 700 permissions:
chmod 700 .gnupg
Change the working directory of GnuPG for this terminal session:
export GNUPGHOME=/path/to/.gnupg
TipThis needs to be set for the terminal session every time when working on the removable drive.
Just to be sure that the above took effect:
gpg --list-keys --keyid-format LONG
Expected output:
gpg: keybox '/path/to/.gnupg/pubring.kbx' created
gpg: /path/to/.gnupg/trustdb.gpg: trustdb created
Generate a primary key:
gpg --gen-key
Check the generated key with --list-keys, there should now be a primary key for signing and certification (SC) and a subkey for encryption (E). The output will be similar to:
pub ed25519/9EE5F19B076C5F70 2026-04-29 [SC] [expires: 2029-04-28]
FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
uid [ultimate] Alice <alice@example.com>
sub cv25519/94FFC07581986626 2026-04-29 [E] [expires: 2029-04-28]
Here, FA33B59C88C72811E7FC2DB29EE5F19B076C5F70 is the primary key ID, and 94FFC07581986626 is the subkey ID of the encryption subkey.
Edit the key:
gpg --edit-key FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Change the expiry of the key to no expiry:
gpg> expire
Changing expiration time for the primary key.
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
sec ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/94FFC07581986626
created: 2026-04-29 expires: 2029-04-28 usage: E
[ultimate] (1). Alice <alice@example.com>
Delete the encryption key. We will handle encryption later.
gpg> key 94FFC07581986626
sec ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* cv25519/94FFC07581986626
created: 2026-04-29 expires: 2029-04-28 usage: E
[ultimate] (1). Alice <alice@example.com>
gpg> delkey
Do you really want to delete this key? (y/N) y
sec ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: ultimate validity: ultimate
[ultimate] (1). Alice <alice@example.com>
Save the changes:
gpg> save
Sharing the public key
We want to share out public key with our friend Bob, so that he can verify files signed by us, and send us encrypted files that we can decrypt.
On the removable drive, export the public key:
gpg --armor --output pub.asc --export FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Then, securely send the public key to Bob.
As Bob, import the public key:
gpg --import pub.asc
Optionally, fully trust the key by editing it:
gpg --edit-key FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
At the gpg> prompt:
gpg> trust
pub ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: unknown validity: unknown
[ unknown] (1). Alice <alice@example.com>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision? 4
pub ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: full validity: unknown
[ unknown] (1). Alice <alice@example.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
gpg> save
However, there’s a catch: we haven’t created keys for signing and encryption yet! Basically, the key isn’t very useful at this moment (although it can already be certified). Do come back and update Bob with the latest public key after creating the appropriate keys in later sections!
Getting the public key validated
If Bob trust that we are whom our key claims to be, he can sign our key, hence endorse the validity of our certificate. Here we suppose this is true, as Bob is our friend in real life.
With our public key shared to Bob, he can validate our public key with his primary key DE4E084E4060B0E3E511681C17D373C240C9B69E with:
gpg --local-user DE4E084E4060B0E3E511681C17D373C240C9B69E --edit-key FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
At the gpg> prompt:
gpg> sign
pub ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: full validity: unknown
Primary key fingerprint: FA33 B59C 88C7 2811 E7FC 2DB2 9EE5 F19B 076C 5F70
Alice <alice@example.com>
Are you sure that you want to sign this key with your
key "Bob <bob@example.com>" (17D373C240C9B69E)
Really sign? (y/N) y
gpg> save
Export the signed public key:
gpg --armor --output signed_pub.asc --export FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Then, securely send the public key back to us.
For us, on the removable drive, import the now signed public key:
gpg --import signed_pub.asc
To verify:
gpg --list-sigs --keyid-format LONG
Expected output:
pub ed25519/9EE5F19B076C5F70 2026-04-29 [SC]
FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
uid [ultimate] Alice <alice@example.com>
sig 3 9EE5F19B076C5F70 2026-04-29 [self-signature]
sig 17D373C240C9B69E 2026-04-29 Bob <bob@example.com>
Create and distribute per-device signing subkeys
On the removable drive, edit the key:
gpg --edit-key FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Create an ed25519 sign only key valid for 1 year:
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(10) ECC (sign only)
(12) ECC (encrypt only)
(14) Existing key from card
Your selection? 10
Please select which elliptic curve you want:
(1) Curve 25519 *default*
(4) NIST P-384
(6) Brainpool P-256
Your selection? 1
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 1y
Key expires at Thursday, April 29, 2027 PM08:43:43 UTC
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/DFA5BF3B65FD74F5
created: 2026-04-29 expires: 2027-04-29 usage: S
[ultimate] (1). Test <example@example.com>
Save the changes:
gpg> save
As seen above, the subkey ID of the newly created key is DFA5BF3B65FD74F5. Export this particular subkey to be later imported to the device that will use this key by running the following. Do not omit the exclamation mark ! at the end:
gpg --armor --output device_name.asc --export-secret-subkeys DFA5BF3B65FD74F5!
--armor: Create ASCII armored output
TipIt could be a good idea to keep track of the target device and creation date of each subkey.
Safely copy device_name.asc to the target device. Then, on the target device:
gpg --import device_name.asc
Verify that the subkey is imported, while the primary key is not:
gpg --list-secret-keys --keyid-format LONG
Expected output. Note that there is a # after sec:
sec# ed25519/9EE5F19B076C5F70 2026-04-29 [SC]
FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
uid [ unknown] Alice <alice@example.com>
ssb ed25519/DFA5BF3B65FD74F5 2026-04-29 [S] [expires: 2027-04-29]
Edit the key:
gpg --edit-key FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Ultimate trust the key if it hasn’t been trusted yet:
gpg> trust
pub ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: unknown validity: unknown
ssb ed25519/DFA5BF3B65FD74F5
created: 2026-04-29 expires: 2027-04-29 usage: S
[ unknown] (1). Alice <alice@example.com>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
pub ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: ultimate validity: unknown
ssb ed25519/DFA5BF3B65FD74F5
created: 2026-04-29 expires: 2027-04-29 usage: S
[ unknown] (1). Alice <alice@example.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
Optionally, change the password with passwd.
Save the changes:
gpg> save
The subkey is now good to use on the device. Repeat for every device and every expired key.
Since the primary key is now updated, it’s a good time to share the updated public key.
Signing files
On our device, to sign foo.txt with the DFA5BF3B65FD74F5 subkey:
gpg --local-user DFA5BF3B65FD74F5 --sign foo.txt
--local-user: The key to use for the signature
The signed file is foo.txt.gpg.
Alternatively, use --detach-sign to produce a separate signature without including the file’s content:
gpg --local-user DFA5BF3B65FD74F5 --detach-sign foo.txt
The detached signature is foo.txt.sig.
For text files, use --clear-sign to produce an inline signature:
gpg --local-user DFA5BF3B65FD74F5 --clear-sign foo.txt
The file with clear signature is foo.txt.asc.
Verifying signatures
Suppose our friend Bob, who has previously obtained our public key, wants to verify the file foo.txt signed by us.
To verify foo.txt.gpg signed by --sign, writing the contents of the original file to foo.txt:
gpg --output foo.txt --verify foo.txt.gpg
To verify foo.txt.sig signed by --detach-sign, make sure foo.txt is in the same directory, then run:
gpg --verify foo.txt.sig
To verify foo.txt.asc signed by -clear-sign, writing the contents of the original file to foo.txt:
gpg --output foo.txt --verify foo.txt.asc
Create and distribute encryption keys
The process is similar to that of create and distribute signing keys. When generating the subkey using addkey, instead of choosing (10) ECC (sign only), choose (12) ECC (encrypt only). However, unlike the signing subkey, which is created on a per-device basis, the encryption subkey is shared across all devices.
NoteUnfortunately, GnuPG is said to encrypt only for the most recent encryption subkey. Therefore, the encryption key has to be shared across all devices. (ref)
Repeat when the key expires. Since the primary key is now updated, it’s a good time to share the updated public key.
Encrypting files
Suppose our friend Bob, who has previously obtained our public key, wants to to send us an encrypted file bar.txt using the 3D486C4725CF62E2 subkey:
gpg --recipient 3D486C4725CF62E2 --encrypt bar.txt
TipIf Bob’s GnuPG complains about the following:
It is NOT certain that the key belongs to the person named in the user ID. If you *really* know what you are doing, you may answer the next question with yes.He can try signing our public key first.
Then, send the encrypted bar.txt.gpg to us.
Decrypting files
On our device, to decrypt bar.txt.gpg encrypted using our public key sent to us, writing the contents of the original file to bar.txt:
gpg --output bar.txt --decrypt bar.txt.gpg
Uploading the public key to a keyserver
Keyservers are of less use these days and most of them are not anymore in service. It is better to attach the key to a mail or provide keys using a Web Key Directory.
On the removable drive, to send the public key to the Synchronizing Key Server:
gpg --keyserver pool.sks-keyservers.net --send-key
Some other keyservers:
- Ubuntu:
keyserver.ubuntu.com
Once the public key is uploaded to one keyserver, it will propagate to the other keyservers.
The keys may obtain new signatures (verifications) from time to time. To download any new signatures and update the keys:
gpg --refresh-keys
Revoking a subkey
On the removable drive, edit the key:
gpg --edit-key FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Select the subkey to be revoked, for example, for the encryption key 3D486C4725CF62E2:
gpg> key 3D486C4725CF62E2
sec ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/DFA5BF3B65FD74F5
created: 2026-04-29 expires: 2027-04-29 usage: S
ssb* cv25519/3D486C4725CF62E2
created: 2026-04-29 expires: 2027-04-29 usage: E
[ultimate] (1). Alice <alice@example.com>
gpg> revkey
Do you really want to revoke this subkey? (y/N) y
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
Your decision? 1
Enter an optional description; end it with an empty line:
>
Reason for revocation: Key has been compromised
(No description given)
Is this okay? (y/N) y
sec ed25519/9EE5F19B076C5F70
created: 2026-04-29 expires: never usage: SC
trust: ultimate validity: ultimate
ssb ed25519/DFA5BF3B65FD74F5
created: 2026-04-29 expires: 2027-04-29 usage: S
The following key was revoked on 2026-04-29 by ? key 9EE5F19B076C5F70 Alice <alice@example.com>
ssb cv25519/3D486C4725CF62E2
created: 2026-04-29 revoked: 2026-04-29 usage: E
[ultimate] (1). Alice <alice@example.com>
gpg> save
Then, send the updated public key to a keyserver.
Additional useful GnuPG commands
Delete a key:
gpg --delete-secret-and-public-keys FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Export secret keys, useful for creating complete backups of the entire key:
gpg --armor --output sec.asc --export-secret-keys FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
Export all secret subkeys without the primary key, as opposed to export one specific subkey:
gpg --armor --output sec_sub.asc --export-secret-subkeys FA33B59C88C72811E7FC2DB29EE5F19B076C5F70
References
https://help.gitkraken.com/gitkraken-desktop/commit-signing-with-gpg/
https://superuser.com/questions/466396/how-to-manage-gpg-keys-across-multiple-systems
https://wiki.debian.org/Subkeys?action=show&redirect=subkeys
https://tjl73.altervista.org/secure_keygen/en/en.html
https://www.phildev.net/pgp/gpgwhy.html
https://www.gnupg.org/faq/gnupg-faq.html
https://help.ubuntu.com/community/GnuPrivacyGuardHowto
https://www.gnupg.org/documentation/manuals/gnupg/Operational-GPG-Commands.html