Operational guide · Version 1.0

Build the vault.
Verify every layer.

A methodical, visual adaptation of Yeti 2.0 for establishing a 3-of-7 Bitcoin Core multisig arrangement with an air-gapped signing computer.

Mainnet procedure

Mistakes can permanently lose funds or expose keys. Rehearse with insignificant value, independently verify commands and software versions, and stop whenever an expected result differs.

Source guideYeti 2.0 v1.06
EnvironmentUbuntu 26.04
Wallet softwareBitcoin Core 31.1
Compared17 August 2026

Before you begin

  • Two dedicated laptops with at least 8 GB RAM and 64 GB storage; Chromebooks are unsuitable.
  • Two new USB drives with at least 16 GB capacity.
  • Seven 4.7 GB M-Disc DVDs or Verbatim Ultralife Gold archival DVDs.
  • One USB disc writer capable of writing the chosen archival media.
  • Approximately US$500 of equipment using the Yeti 2.0 estimate from 11 August 2026.

Security boundary: this page never asks for or accepts keys, seeds, descriptors, wallet files, addresses or PSBTs. Copy buttons only copy public commands shown on screen.

Adapted in original wording from Yeti 2.0. Compare the pinned guide content. Ice Core has not independently audited the Yeti 2.0 security design.

Begin with A1
A

Stage A

Initial setup

A1.1online

Download Ubuntu

Choose one laptop as the online computer and Bitcoin node. On the computer you are currently using, download the Ubuntu 26.04 AMD64 desktop image. Do not write it to the USB drive yet.

A1.2online

Verify the Ubuntu download

Use Terminal

  1. Open Terminal on the computer that downloaded Ubuntu.
  2. The commands change to your Downloads folder, fetch Ubuntu’s signed checksum files, import the named Ubuntu signing keys, authenticate the checksum list, and check the ISO hash.

Run these commands in order:

Hover over any part of the command for an explanation

cdChanges Terminal’s current working directory to the location that follows. ~/DownloadsThe Downloads folder inside the current user’s home directory; subsequent downloads will be saved here.
wgetDownloads a file from a web address to the current directory. https://releases.ubuntu.com/26.04/SHA256SUMSThe remote HTTPS address from which the named file is downloaded.
wgetDownloads a file from a web address to the current directory. https://releases.ubuntu.com/26.04/SHA256SUMS.gpgThe remote HTTPS address from which the named file is downloaded.
gpgThe GNU Privacy Guard program used to import public keys and verify digital signatures. --keyid-formatTells GPG how to display key identifiers in its output. longRequests full-length key identifiers, making the signing keys easier to distinguish. --keyserverTells GPG that the next value identifies the public key server to contact. hkp://keyserver.ubuntu.comIdentifies Ubuntu’s public key server using the HKP keyserver protocol. GPG contacts it to retrieve the specified public signing keys. --recv-keysTells GPG to download and import each public key identifier that follows. 0x46181433FBB754510x46181433FBB75451 identifies one of the Ubuntu signing public keys named by the Yeti 2.0 verification procedure. 0xD94AA3F0EFE210920xD94AA3F0EFE21092 identifies one of the Ubuntu signing public keys named by the Yeti 2.0 verification procedure.
gpgThe GNU Privacy Guard program used to import public keys and verify digital signatures. --keyid-formatTells GPG how to display key identifiers in its output. longRequests full-length key identifiers, making the signing keys easier to distinguish. --verifyChecks that a signature was made by a recognised key and that the signed file has not changed. SHA256SUMS.gpgThis is Ubuntu’s detached GPG signature for SHA256SUMS. GPG checks it using the imported Ubuntu signing keys. SHA256SUMSThis is Ubuntu’s downloaded checksum list. The verification command authenticates it, then the hash-checking command reads it to find the expected SHA-256 fingerprint for the ISO.
sha256sumRuns Linux’s SHA-256 checksum program to compare the downloaded ISO with Ubuntu’s authenticated checksum list. -cChecks local files against the fingerprints recorded in the following checksum list. SHA256SUMSThis is Ubuntu’s downloaded checksum list. The verification command authenticates it, then the hash-checking command reads it to find the expected SHA-256 fingerprint for the ISO. 2>&1Combines error output with normal output so grep can inspect every checksum result. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. grepFinds text matching the supplied pattern. OKKeeps only checksum-result lines containing OK, which marks a successful match.
Stop condition

Do not create the Linux USB unless both the signature check and ISO checksum check succeed. If either check fails or reports a mismatch, delete the downloaded files and stop.

A1.3online

Create the Linux USB

Write the verified Ubuntu image to a new USB drive, then label it with tape as the Linux USB.

Note

Windows users can use Rufus; macOS users can use balenaEtcher. Experienced terminal users may use dd, but selecting the wrong drive can destroy its contents.

A1.4online

Install the operating system

Power off the online laptop, insert the labelled Linux USB, and boot from it. Adjust the BIOS boot order if the installer does not appear.

  • Choose “Install Ubuntu”.
  • Use the default installation settings.
  • At Disk Setup, select “Erase disk and install Ubuntu”.
  • Choose passphrase encryption at the Encryption and File System screen.
  • Record the node password securely; losing it requires reinstalling and resynchronising the node, but does not affect the multisig wallet.
A2online

Update the online computer

Connect the online computer to Wi-Fi or Ethernet. Open Terminal with Ctrl + Alt + T, run each command, approve prompts, and wait for completion.

Note

Linux terminals use Ctrl + Shift + C and Ctrl + Shift + V for copy and paste.

Copy the commands below one at a time, paste each one into Terminal, and press the Enter/Return key on your keyboard to run it.

Hover over any part of the command for an explanation

sudoRuns the following program with administrator privileges, which are required for system-level changes. aptUbuntu’s package-management program; it finds, verifies, installs and updates software. updateTells apt to refresh its catalogue of available packages; it does not install upgrades itself.

Hover over any part of the command for an explanation

sudoRuns the following program with administrator privileges, which are required for system-level changes. aptUbuntu’s package-management program; it finds, verifies, installs and updates software. -yAutomatically answers “yes” to apt confirmation prompts. full-upgradeTells apt to install all available upgrades, including changes that add or remove dependencies.
A3.1online

Download Bitcoin Core 31.1

Open Terminal, change to ~/Downloads, and download the binary archive plus its signed checksums.

Hover over any part of the command for an explanation

cdChanges Terminal’s current working directory to the location that follows. ~/DownloadsThe Downloads folder inside the current user’s home directory; subsequent downloads will be saved here.

Hover over any part of the command for an explanation

wgetDownloads a file from a web address to the current directory. https://bitcoincore.org/bin/bitcoin-core-31.1/bitcoin-31.1-x86_64-linux-gnu.tar.gzThe remote HTTPS address from which the named file is downloaded.
wgetDownloads a file from a web address to the current directory. https://bitcoincore.org/bin/bitcoin-core-31.1/SHA256SUMSThe remote HTTPS address from which the named file is downloaded.
wgetDownloads a file from a web address to the current directory. https://bitcoincore.org/bin/bitcoin-core-31.1/SHA256SUMS.ascThe remote HTTPS address from which the named file is downloaded.
A3.2online

Verify the archive hash

Hover over any part of the command for an explanation

sha256sumRuns Linux’s SHA-256 checksum program to compare the downloaded ISO with Ubuntu’s authenticated checksum list. --ignore-missingSkips checksum entries for files that are not present locally. --checkReads published checksums and reports whether each downloaded file matches. SHA256SUMSThis is Bitcoin Core’s downloaded checksum list. sha256sum reads it to find the expected SHA-256 fingerprint for the archive being checked.
Stop condition

Continue only if the Bitcoin archive reports “OK”. If it does not, stop and do not use the download.

A3.3online

Verify contributor signatures

Download the Bitcoin Core builder keys, import them, and verify the signed checksum file.

Hover over any part of the command for an explanation

wgetDownloads a file from a web address to the current directory. -OTells wget to save the download under the filename that follows. guix.sigs.tar.gzguix.sigs.tar.gz is the local filename wget will use for the downloaded file. The preceding -O option assigns this name instead of retaining the filename from the web address. https://github.com/bitcoin-core/guix.sigs/archive/refs/heads/main.tar.gzThe remote HTTPS address from which the named file is downloaded.
tarReads or creates archive files. Here it is used to unpack downloaded archives. -xzfCombines three tar options: extract files, decompress gzip data, and read the following archive filename. guix.sigs.tar.gzguix.sigs.tar.gz is the gzip-compressed tar archive that tar will decompress and extract. The preceding -xzf options tell tar how to process this file.
gpgThe GNU Privacy Guard program used to import public keys and verify digital signatures. --importAdds the listed public signing keys to the local GPG keyring. guix.sigs-main/builder-keys/*This wildcard selects every builder public-key file inside the extracted guix.sigs directory so gpg can import all of them.
gpgThe GNU Privacy Guard program used to import public keys and verify digital signatures. --verifyChecks that a signature was made by a recognised key and that the signed file has not changed. SHA256SUMS.ascThis is the downloaded GPG signature for SHA256SUMS. gpg verifies it against the imported Bitcoin Core builder public keys.
Stop condition

Look for good signatures from several Bitcoin Core contributors. If none are good, stop and do not proceed.

A3.4online

Unpack the verified archive

Hover over any part of the command for an explanation

tarReads or creates archive files. Here it is used to unpack downloaded archives. -xzfCombines three tar options: extract files, decompress gzip data, and read the following archive filename. bitcoin-31.1-x86_64-linux-gnu.tar.gzbitcoin-31.1-x86_64-linux-gnu.tar.gz is the gzip-compressed tar archive that tar will decompress and extract. The preceding -xzf options tell tar how to process this file. -CTells tar to change to the following destination directory before extracting. ~~ is the extraction destination. Here ~ means the current user’s home folder, so tar places the unpacked Bitcoin Core folder there.

The verified software is now available at ~/bitcoin-31.1.

A4.1online

Enable pruning

Open bitcoin.conf inside the bitcoin-31.1 folder. Add the following on its own active line, save, and close the file.

Hover over any part of the command for an explanation

prune=5500A Bitcoin Core setting that keeps roughly 5,500 MiB of recent block data instead of retaining the entire blockchain.
A4.2online

Start the node and synchronise

In Terminal, change to ~/bitcoin-31.1/bin and start Bitcoin Core.

Hover over any part of the command for an explanation

./bitcoindRuns the Bitcoin Core daemon located in the current directory; “./” explicitly means this directory. -daemonStarts Bitcoin Core in the background so the terminal can be used for other commands.
Note

Initial synchronisation can take days or weeks and must finish before wallet testing. Always stop Bitcoin Core cleanly before shutting down:

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. stopAsks Bitcoin Core to shut down cleanly before the computer is powered off.
A5online

Boot a disposable offline session

Label the second laptop with tape as the offline computer. With it powered off, insert the labelled Linux USB and boot from it. Adjust BIOS boot order if needed.

  • Keep the labelled Linux USB inserted in this computer.
  • At the Ubuntu screen choose “Try Ubuntu”, not install.
  • Temporarily connect this live session to Wi-Fi or Ethernet for the next software-download step.
A6.1online

Save the Ice Core guide for offline use

Download the self-contained Ice Core Guide v1 onto this live session before disabling networking. It includes the complete guide, styles, diagrams and animation code in one HTML file.

Note

Open ice-core-guide-v1.html in the browser after networking is disabled. Keep the file in the live session so exact public commands remain available for copy and paste. The package contains no wallet data and makes no runtime network requests.

A6.2online

Install Bitcoin Core offline

Repeat every part of A3 on the offline computer: download Bitcoin Core, verify its hash and contributor signatures, and unpack it. Do not skip verification.

A6.3online

Install archival-disc software

Install Brasero while the temporary network connection is still available.

Hover over any part of the command for an explanation

sudoRuns the following program with administrator privileges, which are required for system-level changes. aptUbuntu’s package-management program; it finds, verifies, installs and updates software. updateTells apt to refresh its catalogue of available packages; it does not install upgrades itself.
sudoRuns the following program with administrator privileges, which are required for system-level changes. aptUbuntu’s package-management program; it finds, verifies, installs and updates software. -yAutomatically answers “yes” to apt confirmation prompts. installTells apt to install the named package. braseroNames the Brasero disc-writing package that apt should install.
Note

Ubuntu apt checks package authenticity. Yeti 2.0 notes that a dpkg message may appear after installation. Brasero will write the key backups to archival discs.

A7.1offline

Cut every network path

Hover over any part of the command for an explanation

nmcliThe command-line controller for Ubuntu’s NetworkManager service. networkingSelects NetworkManager’s overall networking state as the setting nmcli should change. offTells nmcli to switch NetworkManager networking off, disabling its managed network connections.
rfkillControls the operating system’s radio-frequency devices, such as Bluetooth adapters. blockTells rfkill to disable the radio device type named next. bluetoothSelects Bluetooth as the radio technology rfkill should block.
Stop condition

Networking must be off before any key material is generated or inserted. This disables Wi-Fi, Ethernet and Bluetooth at the operating-system level.

A7.2offline

Disable swap

Prevent the live system from writing memory contents to internal storage.

Hover over any part of the command for an explanation

sudoRuns the following program with administrator privileges, which are required for system-level changes. swapoffDisables swap so memory contents are not written to storage. -aApplies swapoff to every active swap area.
B

Stage B

Create the multisig wallet

B1offline

Start the offline daemon

Change to ~/bitcoin-31.1/bin in Terminal, then start Bitcoin Core.

Hover over any part of the command for an explanation

cdChanges Terminal’s current working directory to the location that follows. ~/bitcoin-31.1/binThe folder containing the verified Bitcoin Core executable programs unpacked earlier in the guide.
./bitcoindRuns the Bitcoin Core daemon located in the current directory; “./” explicitly means this directory. -daemonStarts Bitcoin Core in the background so the terminal can be used for other commands.
B2offline

Generate seven wallets

From ~/bitcoin-31.1/bin, create the seven participant wallets.

Hover over any part of the command for an explanation

forStarts a shell loop. Together with the condition that follows, it repeats the enclosed commands for the required numbered wallets. ((n=1;n<=7;n++))Controls the loop: start n at 1, continue while n is at most 7, and increase n by one after each pass.
doBegins the body of the for loop. The following commands run once for each value selected by the loop above.
 ./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. createwalletCreates a new Bitcoin Core wallet using the name that follows. "key_${n}"Creates the wallet name key_ followed by the current loop number, producing key_1 through key_7 across the seven iterations.
doneEnds the for loop after all iterations have completed.
B3offline

Collect descriptor xpubs

Build an in-memory array of the receiving descriptors from all seven wallets.

Hover over any part of the command for an explanation

declareUses Bash’s declare builtin to create the variable described by the following option and name. -AMakes the declared variable an associative array, whose entries can be addressed by text keys rather than only numeric positions. xpubsNames the new associative array xpubs. The loop below stores each wallet’s extracted public descriptor in this array.

forStarts a shell loop. Together with the condition that follows, it repeats the enclosed commands for the required numbered wallets. ((n=1;n<=7;n++))Controls the loop: start n at 1, continue while n is at most 7, and increase n by one after each pass.
doBegins the body of the for loop. The following commands run once for each value selected by the loop above.
 xpubs["xpub_${n}"]=$(./bitcoin-cliSelects the xpubs array entry numbered by the current loop value, runs bitcoin-cli inside $(...), and stores the processed descriptor output in that entry. -rpcwallet="key_${n}"Directs the Bitcoin Core instruction to the named wallet rather than another loaded wallet. listdescriptorsReturns the descriptors belonging to the selected wallet. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. jqReads JSON output and selects or reformats the requested fields. '.descriptors | [.[] | select(.desc | startswith("wpkh") and contains("/0/*") )][0] | .desc'This jq filter examines the wallet’s descriptor list, selects the first wpkh receiving descriptor whose path contains /0/*, and outputs its desc field. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. grepFinds text matching the supplied pattern. -PoCombines grep’s -P and -o options: use a Perl-compatible regular expression and output only the matching text. '(?<=\().*(?=\))'This grep pattern returns only the text inside the descriptor’s outer parentheses, removing the surrounding descriptor function. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. sedTransforms text according to the supplied substitution expression. 's /0/\* /<0;1>/* ')This sed substitution changes the descriptor’s single receive branch /0/* into the combined external-and-change branch /<0;1>/*.
doneEnds the for loop after all iterations have completed.
B4offline

Construct the 3-of-7 watch wallet

Combine all seven xpubs into a sorted 3-of-7 descriptor, calculate its checksum, create a blank watch-only wallet, and import the descriptor.

Hover over any part of the command for an explanation

desc="wsh(sortedmulti(3,${xpubs["xpub_1"]},${xpubs["xpub_2"]},${xpubs["xpub_3"]},${xpubs["xpub_4"]},${xpubs["xpub_5"]},${xpubs["xpub_6"]},${xpubs["xpub_7"]}))"Creates the shell variable desc and stores the complete wsh(sortedmulti(...)) descriptor in it. The descriptor requires any three of the seven xpubs collected in B3, and sortedmulti orders the public keys deterministically.

checksum=$(./bitcoin-cliCreates the shell variable checksum and begins a command substitution: the output produced inside $(...) becomes the variable’s value. ./bitcoin-cli calls the local Bitcoin Core command-line client. getdescriptorinfoAsks Bitcoin Core to inspect the descriptor supplied by the next element and calculate metadata including its checksum. $descExpands the desc variable created above, supplying the complete 3-of-7 descriptor to getdescriptorinfo. |Pipes Bitcoin Core’s JSON output into jq so only the required checksum is retained. jqRuns jq, a command-line JSON processor. -rTells jq to output the selected value as raw text rather than as a quoted JSON string. '.checksum')Selects the checksum property from Bitcoin Core’s JSON response, then closes the command substitution assigned to checksum.

multisig_desc="[{\"desc\": \"${desc}#${checksum}\", \"active\": true, \"timestamp\": \"now\"}]"Creates the multisig_desc shell variable containing the JSON import request. It combines the descriptor and checksum, marks the descriptor active, and uses “now” as its scan timestamp because this is a newly constructed wallet.

./bitcoin-cliRuns bitcoin-cli from the current ~/bitcoin-31.1/bin directory to send the following wallet-creation request to the local Bitcoin Core daemon. -namedEnables bitcoin-cli’s named-parameter mode for the createwallet RPC. The following values correspond to createwallet’s wallet_name, disable_private_keys, and blank parameters. createwalletCalls Bitcoin Core’s createwallet RPC to create the watch-only wallet container used by this guide. "multisig_watch_wallet"Sets the new wallet’s name to multisig_watch_wallet. The quotation marks keep the name together as one shell argument. trueSets disable_private_keys to true. This makes the wallet watch-only: it will contain no private signing keys. trueSets blank to true. Bitcoin Core creates an empty wallet so the multisig descriptor prepared above can be imported explicitly on the next line.
./bitcoin-cliRuns the local Bitcoin Core command-line client. -rpcwallet="multisig_watch_wallet"Directs this RPC call specifically to multisig_watch_wallet, the blank watch-only wallet created on the preceding line. importdescriptorsCalls importdescriptors, which adds the prepared multisig descriptor to the selected wallet. "$multisig_desc"Expands the multisig_desc variable and passes its JSON import request as one quoted argument.

./bitcoin-cliRuns the local Bitcoin Core command-line client. -rpcwallet="multisig_watch_wallet"Selects multisig_watch_wallet for this check. getwalletinfoRequests the wallet’s information so you can confirm the watch-only wallet was created and configured as expected.
B5.1offline

Export on the transfer USB

Label the second, unmarked USB as the transfer USB. Insert it in the offline computer and copy ~/.bitcoin/wallets/multisig_watch_wallet to it.

Note

In Files, enable “Show hidden files” to see ~/.bitcoin. Run sync and wait for it to finish before removing any USB.

B5.2online

Import on the online computer

Move the transfer USB to the online computer and copy multisig_watch_wallet into ~/.bitcoin/wallets. After blockchain synchronisation finishes, load it from ~/bitcoin-31.1/bin.

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. loadwalletLoads the named wallet directory so Bitcoin Core can use it. "multisig_watch_wallet"Supplies the literal wallet name multisig_watch_wallet as one argument to the preceding wallet command.
Note

Bitcoin CLI or Bitcoin-Qt can now show history and balance, generate receive addresses and PSBTs, and broadcast signed transactions. This wallet cannot sign.

B6offline

Create seven archival backups

In Brasero, create seven separate archival-disc backups. Each disc contains one key wallet, multisig_watch_wallet, and README.md. Number the physical discs permanently before burning.

  • Disc 1: key_1 + multisig_watch_wallet
  • Disc 2: key_2 + multisig_watch_wallet
  • Disc 3: key_3 + multisig_watch_wallet
  • Disc 4: key_4 + multisig_watch_wallet
  • Disc 5: key_5 + multisig_watch_wallet
  • Disc 6: key_6 + multisig_watch_wallet
  • Disc 7: key_7 + multisig_watch_wallet
C

Stage C

Test every backup

C1offline

Prove recovery is possible

Warning

This is intentionally destructive. Confirm all seven discs were written before continuing.

Stop Bitcoin Core, wait for it to exit, delete the entire ~/.bitcoin/wallets folder, and restart the daemon.

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. stopAsks Bitcoin Core to shut down cleanly before the computer is powered off.

Hover over any part of the command for an explanation

./bitcoindRuns the Bitcoin Core daemon located in the current directory; “./” explicitly means this directory. -daemonStarts Bitcoin Core in the background so the terminal can be used for other commands.
C2online

Generate the test destination

With multisig_watch_wallet loaded online through Bitcoin-Qt or the CLI, generate a fresh receive address.

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. -rpcwallet="multisig_watch_wallet"Directs the Bitcoin Core instruction to the named wallet rather than another loaded wallet. getnewaddressGenerates the next receive address from the watch-only wallet.

Send a small amount of bitcoin to this receive address from an exchange account or another Bitcoin wallet.

Warning

Send only a very small test amount—less than US$5 in Yeti 2.0. Bitcoin-Qt may display the address as a QR code.

C3online

Wait for the test funds

Only the synchronised online node can confirm the wallet balance.

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. -rpcwallet="multisig_watch_wallet"Directs the Bitcoin Core instruction to the named wallet rather than another loaded wallet. getbalancesReports confirmed and pending balances known to the selected wallet.
C4.1online

Build the PSBT

Set $amount and $destination_address yourself in the command below and verify both before running. Enter the amount in BTC using eight decimal places, for example 0.00010000.

Hover over any part of the command for an explanation

funded_psbt=$(./bitcoin-cliStarts bitcoin-cli inside a command substitution and assigns the PSBT text ultimately selected by jq to the shell variable funded_psbt. -rpcwallet="multisig_watch_wallet"Directs the Bitcoin Core instruction to the named wallet rather than another loaded wallet. -namedAllows Bitcoin Core arguments to be supplied by name rather than only by position. \Continues this same command onto the next displayed line. Press Enter only after the complete multi-line command has been pasted.
 walletcreatefundedpsbtSelects wallet coins and creates a funded but unsigned Partially Signed Bitcoin Transaction. \Continues this same command onto the next displayed line. Press Enter only after the complete multi-line command has been pasted.
 outputs="{\"$destination_address\": $amount}"Supplies the named outputs argument to walletcreatefundedpsbt. Its JSON maps the destination address you set to the BTC amount you set. \Continues this same command onto the next displayed line. Press Enter only after the complete multi-line command has been pasted.
 options='{"subtractFeeFromOutputs":[0]}'Supplies walletcreatefundedpsbt’s named options argument. subtractFeeFromOutputs:[0] deducts the transaction fee from output index 0. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.psbt')Selects the psbt field from jq’s JSON input as raw text, then closes the surrounding command substitution.

echoWrites the following value as text. "$funded_psbt"Expands the shell variable funded_psbt and preserves its complete value as one argument by surrounding it with quotes. >Redirects the preceding command’s output into the file named next, replacing that file if it already exists. ~/Desktop/unsigned.psbtNames the Desktop file that receives the newly created unsigned PSBT through the preceding > redirection.
C4.2both

Move the unsigned PSBT offline

Insert the transfer USB in the online computer, copy unsigned.psbt from the Desktop onto it, safely remove it, and carry it to the offline computer.

C5.1offline

Decode before signing

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. decodepsbtConverts a PSBT into readable structured information so its inputs, outputs, amount and destination can be inspected. "$(cat ~/Desktop/unsigned.psbt)"Runs cat to read the PSBT file from the Desktop and passes the complete file contents to decodepsbt as one quoted argument.
Stop condition

Inspect tx.vout and confirm destination_address and amount exactly match your intention. If either differs, stop and reevaluate.

C5.2offline

Recover three key wallets

Choose three archival discs. Insert them one by one and copy each key_# directory into ~/.bitcoin/wallets. Replace key_# below with each recovered wallet name.

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. loadwalletLoads the named wallet directory so Bitcoin Core can use it. "key_#"This is a placeholder wallet name. Replace # with the number of the recovered key wallet you intend to load, such as key_3.
./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. loadwalletLoads the named wallet directory so Bitcoin Core can use it. "key_#"This is a placeholder wallet name. Replace # with the number of the recovered key wallet you intend to load, such as key_3.
./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. loadwalletLoads the named wallet directory so Bitcoin Core can use it. "key_#"This is a placeholder wallet name. Replace # with the number of the recovered key wallet you intend to load, such as key_3.
C5.3offline

Sign with the three loaded keys

Note

Load only the three key wallets. If the watch wallet is loaded, unload it first with ./bitcoin-cli unloadwallet multisig_watch_wallet.

Hover over any part of the command for an explanation

psbt=$(catRuns cat inside a command substitution to read the signed or unsigned PSBT file, then assigns that file’s contents to the shell variable psbt. ~/Desktop/unsigned.psbt)Names the PSBT file that cat reads from the Desktop; the closing parenthesis ends the command substitution whose output is stored in the variable at the start of this line.

wallet1=$(./bitcoin-cliRuns bitcoin-cli to obtain the loaded-wallet list and assigns the selected wallet name to wallet1. listwalletsReturns the names of wallets currently loaded in Bitcoin Core. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it.jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.[0]')Selects loaded-wallet array entry 0 in jq, outputs that wallet name, and closes the surrounding command substitution.
wallet2=$(./bitcoin-cliRuns bitcoin-cli to obtain the loaded-wallet list and assigns the selected wallet name to wallet2. listwalletsReturns the names of wallets currently loaded in Bitcoin Core. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it.jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.[1]')Selects loaded-wallet array entry 1 in jq, outputs that wallet name, and closes the surrounding command substitution.
wallet3=$(./bitcoin-cliRuns bitcoin-cli to obtain the loaded-wallet list and assigns the selected wallet name to wallet3. listwalletsReturns the names of wallets currently loaded in Bitcoin Core. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it.jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.[2]')Selects loaded-wallet array entry 2 in jq, outputs that wallet name, and closes the surrounding command substitution.

psbt_1=$(./bitcoin-cliStarts a Bitcoin Core signing call and assigns its returned PSBT to psbt_1, ready for the next signing wallet. -rpcwallet="$wallet1"Directs the Bitcoin Core instruction to the named wallet rather than another loaded wallet. walletprocesspsbtLets the selected wallet inspect and, when it has the required private key, add its signature to the PSBT. "$psbt"Expands the shell variable psbt and preserves its complete value as one argument by surrounding it with quotes. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.psbt')Selects the psbt field from jq’s JSON input as raw text, then closes the surrounding command substitution.
psbt_2=$(./bitcoin-cliStarts a Bitcoin Core signing call and assigns its returned PSBT to psbt_2, ready for the next signing wallet. -rpcwallet="$wallet2"Directs the Bitcoin Core instruction to the named wallet rather than another loaded wallet. walletprocesspsbtLets the selected wallet inspect and, when it has the required private key, add its signature to the PSBT. "$psbt_1"Expands the shell variable psbt_1 and preserves its complete value as one argument by surrounding it with quotes. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.psbt')Selects the psbt field from jq’s JSON input as raw text, then closes the surrounding command substitution.
psbt_3=$(./bitcoin-cliStarts a Bitcoin Core signing call and assigns its returned PSBT to psbt_3, ready for the next signing wallet. -rpcwallet="$wallet3"Directs the Bitcoin Core instruction to the named wallet rather than another loaded wallet. walletprocesspsbtLets the selected wallet inspect and, when it has the required private key, add its signature to the PSBT. "$psbt_2"Expands the shell variable psbt_2 and preserves its complete value as one argument by surrounding it with quotes. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.psbt')Selects the psbt field from jq’s JSON input as raw text, then closes the surrounding command substitution.

echoWrites the following value as text. "$psbt_3"Expands the shell variable psbt_3 and preserves its complete value as one argument by surrounding it with quotes. >Redirects the preceding command’s output into the file named next, replacing that file if it already exists. ~/Desktop/signed.psbtNames the Desktop file that receives the three-signature PSBT through the preceding > redirection.
C5.4both

Return the signed PSBT online

Copy signed.psbt from the offline Desktop to the transfer USB. Remove it, insert it online, and copy signed.psbt to the online Desktop.

C5.5online

Decode again before broadcast

Hover over any part of the command for an explanation

./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. decodepsbtConverts a PSBT into readable structured information so its inputs, outputs, amount and destination can be inspected. "$(cat ~/Desktop/signed.psbt)"Runs cat to read the PSBT file from the Desktop and passes the complete file contents to decodepsbt as one quoted argument.
Stop condition

Again confirm destination_address and amount in tx.vout. If they do not match, stop and reevaluate.

C6.1online

Finalise and broadcast

Hover over any part of the command for an explanation

psbt=$(catRuns cat inside a command substitution to read the signed or unsigned PSBT file, then assigns that file’s contents to the shell variable psbt. ~/Desktop/signed.psbt)Names the PSBT file that cat reads from the Desktop; the closing parenthesis ends the command substitution whose output is stored in the variable at the start of this line.
hex=$(./bitcoin-cliRuns Bitcoin Core’s finalisation call inside a command substitution and assigns the extracted raw transaction hexadecimal to the shell variable hex. finalizepsbtCombines the completed PSBT data and produces the raw transaction hexadecimal needed for broadcast. "$psbt"Expands the shell variable psbt and preserves its complete value as one argument by surrounding it with quotes. |Pipes the output produced on the left into the program on the right, allowing the next part of this command to process it. jqReads JSON output and selects or reformats the requested fields. -rTells jq to output the selected value as raw text instead of a JSON-quoted string. '.hex')Selects the final transaction hex field from jq’s JSON input as raw text, then closes the surrounding command substitution.
./bitcoin-cliRuns Bitcoin Core’s command-line client from the current directory and sends the following instruction to bitcoind. sendrawtransactionSubmits the final raw transaction to the Bitcoin network through the online node. "$hex"Expands the shell variable hex and preserves its complete value as one argument by surrounding it with quotes.
Warning

After each transaction, delete old signed.psbt and unsigned.psbt files from the transfer USB and both Desktops.

C6.2both

Test all seven backups

Repeat C4–C6 three times so every key backup participates in a successful spend.

  • Test 1: keys 1, 2 and 3.
  • Test 2: keys 4, 5 and 6.
  • Test 3: key 7 plus any other two keys.
Stop condition

If a test fails, retry from C4 once. If it still fails, stop. Delete PSBTs, remove the watch wallet from the transfer USB, delete both computers’ ~/.bitcoin/wallets directories, and restart from A5 using fresh archival discs.

C7physical

Separate all seven discs

Place each disc in a separate envelope with a discreet succession message. Store the seven envelopes in seven geographically separate locations.

Warning

Three locations can jointly authorise a spend. Do not reveal wallet details in the external labelling. Only regard the wallet as tested after all three C6 transactions succeed.

D

Stage D

Use the wallet normally

D1offline

Start clean each time

With the offline laptop powered off, insert the Linux USB, boot, and select “Try Ubuntu”. The live session intentionally has no persistence.

D2offline

Download and verify again

Temporarily connect to your home network, download and verify Bitcoin Core as in A3, and save the guide if needed. Brasero does not need to be reinstalled for routine signing.

D3offline

Isolate before keys arrive

Stop condition

Complete this before inserting any key material.

Hover over any part of the command for an explanation

nmcliThe command-line controller for Ubuntu’s NetworkManager service. networkingSelects NetworkManager’s overall networking state as the setting nmcli should change. offTells nmcli to switch NetworkManager networking off, disabling its managed network connections.
rfkillControls the operating system’s radio-frequency devices, such as Bluetooth adapters. blockTells rfkill to disable the radio device type named next. bluetoothSelects Bluetooth as the radio technology rfkill should block.

Hover over any part of the command for an explanation

sudoRuns the following program with administrator privileges, which are required for system-level changes. swapoffDisables swap so memory contents are not written to storage. -aApplies swapoff to every active swap area.
D4online

Prepare the spend online

Create unsigned.psbt on the online computer as in C4, verify the amount and destination, and copy it to the transfer USB.

D5offline

Inspect the proposed spend

Move unsigned.psbt from the transfer USB to the offline Desktop and decode it as in C5. Confirm every output before proceeding.

D6offline

Assemble a signing quorum

Collect any three key discs, copy their wallet directories into ~/.bitcoin/wallets, and load only those three wallets.

D7offline

Apply three signatures

Run the C5 signing sequence to produce signed.psbt. Keep the watch-only wallet unloaded.

D8both

Cross back to the online side

Copy signed.psbt to the transfer USB, remove it from the offline computer, insert it online, and copy the file to the online Desktop.

D9online

Inspect once more, then send

Decode the signed PSBT online, verify its destination and amount again, then finalise and broadcast it as in C6.

D10both

End the signing session

Delete transaction files from both Desktops and the transfer USB. Shut down the offline computer after signing and export; its temporary keys disappear with the live session.

Warning

Keep both laptops dedicated exclusively to the Bitcoin Core workflow described by this guide.

Guide complete

Recovery proved.
Backups distributed.

Completion here is only that you've arrived at the end. It does not verify checklist state, or that any physical or Bitcoin operation succeeded.