├── static ├── .nojekyll └── img │ └── social-card.jpg ├── README.md ├── src ├── pages │ ├── markdown-page.md │ └── index.module.css ├── components │ └── HomepageFeatures │ │ ├── styles.module.css │ │ └── index.js └── css │ └── custom.css ├── versions.tf ├── common.nix ├── .gitignore ├── shell.nix ├── parsetf.nix ├── .github └── workflows │ └── deployment.yml ├── main.tf ├── sidebars.js ├── network.nix ├── package.json ├── docs ├── credits.md ├── REQUIRED-CLEANUP.md ├── bonus-RTL.md ├── bonus-Fulcrum.md ├── intro.md ├── bonus-Mempool.md ├── chans-invoices.md ├── cln.md ├── init.md ├── bonus-Zeus.md └── bitcoind.md └── docusaurus.config.js /static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ./docs/intro.md -------------------------------------------------------------------------------- /static/img/social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisguida/nixos-mutinynet-tutorial/HEAD/static/img/social-card.jpg -------------------------------------------------------------------------------- /src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | digitalocean = { 4 | source = "digitalocean/digitalocean" 5 | version = "~> 2.0" 6 | } 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /common.nix: -------------------------------------------------------------------------------- 1 | { modulesPath, lib, ... }: 2 | { 3 | imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [ 4 | (modulesPath + "/virtualisation/digital-ocean-config.nix") 5 | ]; 6 | 7 | deployment.targetUser = "root"; 8 | system.stateVersion = "23.11"; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { } }: 2 | let 3 | myTerraform = pkgs.terraform.withPlugins (tp: [ tp.digitalocean ]); 4 | ter = pkgs.writeShellScriptBin "ter" '' 5 | terraform $@ && terraform show -json > show.json 6 | ''; 7 | in 8 | pkgs.mkShell { 9 | buildInputs = with pkgs; [ curl jq morph myTerraform ter ]; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /parsetf.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { } 2 | , lib ? pkgs.lib 3 | }: 4 | let 5 | resourcesInModule = type: module: 6 | builtins.filter (r: r.type == type) module.resources ++ 7 | lib.flatten (map (resourcesInModule type) (module.child_modules or [ ])); 8 | resourcesByType = type: resourcesInModule type payload.values.root_module; 9 | payload = builtins.fromJSON (builtins.readFile ./show.json); 10 | in 11 | { 12 | inherit resourcesByType; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 996px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/deployment.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | on: 3 | push: 4 | branches: 5 | - master 6 | permissions: 7 | contents: write 8 | jobs: 9 | build-and-deploy: 10 | concurrency: ci-${{ github.ref }} 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 🛎️ 14 | uses: actions/checkout@v4 15 | - name: Install and Build 🔧 16 | run: | 17 | npm ci 18 | npm run build 19 | - name: Deploy 🚀 20 | uses: JamesIves/github-pages-deploy-action@v4 21 | with: 22 | folder: build 23 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | provider "digitalocean" {} 2 | 3 | resource "digitalocean_droplet" "node" { 4 | name = "node${count.index + 1}" 5 | region = "nyc3" 6 | # size = "s-1vcpu-1gb" 7 | 8 | # cheapest vps with 600GB disk. needed to save money after the bitcoind build 9 | # since DO does not allow shrinking disk once expanded. 10 | size = "m6-4vcpu-32gb" 11 | 12 | # largest vps on DO. needed to build bitcoind. $2/hr at time of writing. 13 | # size = "c-48" 14 | 15 | # smallest compute optimized droplet. good for initial setup before bitcoind build. 16 | # size = "c-2" 17 | 18 | # my image, use your own 19 | image = 140788016 20 | 21 | # my ssh key, use your own 22 | ssh_keys = [39451484] 23 | 24 | # 20 nodes 25 | count = 20 26 | } 27 | 28 | -------------------------------------------------------------------------------- /sidebars.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) 4 | 5 | /** 6 | * Creating a sidebar enables you to: 7 | - create an ordered group of docs 8 | - render a sidebar for each doc of that group 9 | - provide next/previous navigation 10 | 11 | The sidebars can be generated from the filesystem, or explicitly defined here. 12 | 13 | Create as many sidebars as you want. 14 | 15 | @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} 16 | */ 17 | const sidebars = { 18 | // By default, Docusaurus generates a sidebar from the docs folder structure 19 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 20 | 21 | // But you can create a sidebar manually 22 | /* 23 | tutorialSidebar: [ 24 | 'intro', 25 | 'hello', 26 | { 27 | type: 'category', 28 | label: 'Tutorial', 29 | items: ['tutorial-basics/create-a-document'], 30 | }, 31 | ], 32 | */ 33 | }; 34 | 35 | export default sidebars; 36 | -------------------------------------------------------------------------------- /src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #531daa; 10 | --ifm-color-primary-dark: #4b1a99; 11 | --ifm-color-primary-darker: #471991; 12 | --ifm-color-primary-darkest: #3a1477; 13 | --ifm-color-primary-light: #5b20bb; 14 | --ifm-color-primary-lighter: #5f21c3; 15 | --ifm-color-primary-lightest: #6d28da; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #7df9ff; 23 | --ifm-color-primary-dark: #57f7ff; 24 | --ifm-color-primary-darker: #44f6ff; 25 | --ifm-color-primary-darkest: #0bf4ff; 26 | --ifm-color-primary-light: #a3fbff; 27 | --ifm-color-primary-lighter: #b6fcff; 28 | --ifm-color-primary-lightest: #effeff; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | } 31 | -------------------------------------------------------------------------------- /network.nix: -------------------------------------------------------------------------------- 1 | # 1. 2 | let 3 | resourcesByType = (import ./parsetf.nix { }).resourcesByType; 4 | 5 | droplets = resourcesByType "digitalocean_droplet"; 6 | nodes = builtins.filter (d: d.name == "node") droplets; 7 | 8 | # 2. 9 | mkNode = resource: { name, pkgs, ... }: { 10 | imports = [ ./common.nix ]; 11 | deployment.targetHost = resource.values.ipv4_address; 12 | networking.hostName = resource.values.name; 13 | # networking.firewall.allowedTCPPorts = [ 9735 ]; 14 | system.stateVersion = "23.11"; 15 | users.users.bitcoiner = { 16 | isNormalUser = true; 17 | description = "bitcoiner"; 18 | extraGroups = [ "wheel" ]; 19 | packages = with pkgs; [ 20 | vim 21 | ]; 22 | password = "btcpp"; 23 | }; 24 | services.openssh = { 25 | settings.PasswordAuthentication = true; 26 | extraConfig = '' 27 | ClientAliveInterval 120 28 | ClientAliveCountMax 720 29 | ''; 30 | }; 31 | }; 32 | in 33 | # 3. 34 | { 35 | network = { 36 | pkgs = import { }; 37 | }; 38 | } // # 5. 39 | # 4. 40 | builtins.listToAttrs (map (r: { name = r.values.name; value = mkNode r; }) nodes) 41 | 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiny", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids" 15 | }, 16 | "dependencies": { 17 | "@docusaurus/core": "3.7.0", 18 | "@docusaurus/preset-classic": "3.7.0", 19 | "@mdx-js/react": "^3.0.0", 20 | "clsx": "^2.0.0", 21 | "prism-react-renderer": "^2.3.0", 22 | "react": "^19.0.0", 23 | "react-dom": "^19.0.0" 24 | }, 25 | "devDependencies": { 26 | "@docusaurus/module-type-aliases": "3.7.0", 27 | "@docusaurus/types": "3.7.0" 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.5%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 3 chrome version", 37 | "last 3 firefox version", 38 | "last 5 safari version" 39 | ] 40 | }, 41 | "engines": { 42 | "node": ">=18.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/credits.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Credits" 3 | sidebar_position: 11 4 | --- 5 | 6 | 7 | # Credits! 8 | 9 | ## Special thanks to: 10 | 11 | ### The nix-bitcoin project 12 | https://github.com/fort-nix/nix-bitcoin 13 | 14 | ### The Mutiny Wallet team / The Mutinynet project 15 | https://mutinywallet.com

16 | https://mutinynet.com 17 | 18 | ### Justinas 19 | - Thanks for writing a [great tutorial on Morph and Terraform](https://justinas.org/nixos-in-the-cloud-step-by-step-part-1) 20 | 21 | https://github.com/justinas

22 | 23 | ### HashiCorp / Terraform 24 | - Thanks for writing a [great DigitalOcean deployment tool](https://www.terraform.io/). 25 | 26 | ### Morph 27 | - Thanks for writing a [great NixOS deployment tool](https://github.com/DBCDK/morph). 28 | 29 | ### Lisa Neigut 30 | - Thanks for showing me the [tutorial that made this workshop possible](https://justinas.org/nixos-in-the-cloud-step-by-step-part-1) 31 | - Also thanks for organizing the excellent [btc++ conference](https://btcplusplus.dev) 32 | 33 | https://github.com/niftynei

34 | https://x.com/niftynei 35 | 36 | ### Bitcoin y Lightning GDL 37 | - Thanks for helping me test this workshop! 38 | - Special thanks to: 39 | - Frank 40 | - Chris R. 41 | - Jorge M. O. 42 | 43 | https://x.com/btc_ln_gdl 44 | -------------------------------------------------------------------------------- /docs/REQUIRED-CLEANUP.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Required Cleanup" 3 | sidebar_position: 10 4 | --- 5 | 6 | 7 | # REQUIRED: Cleanup 8 | 9 | - In this section we will withdraw all our play money from our nodes and close all our channels. 10 | - This will help tidy things up on the mutinynet chain once the workshop is over. 11 | - I will destroy all the droplets at the end of the day. 12 | 13 | # Close all your channels and withdraw or donate all your money 14 | ## Close all your channels: 15 | ```sh 16 | lightning-cli listpeers | jq -r '.peers[] | .id' | xargs -I {} lightning-cli close {} 17 | ``` 18 | 19 | ## Track the closes on chain and make sure they all succeed 20 | - You can keep track of the closes with `lightning-cli listpeerchannels` and `lightning-cli listfunds` 21 | 22 | ## Once all your channels are closed, withdraw all your money from the node 23 | - To withdraw to an address you generate in Sparrow: 24 | ``` 25 | lightning-cli withdraw all 26 | ``` 27 | 28 | - To donate all your mutinysats to Chris: 29 | ``` 30 | lightning-cli withdraw tb1qdq6ttfganrlhch5jrv27ewtnnpwphp96hfq7m2 all 31 | ``` 32 | 33 | Let me know when you've finished withdrawing your money so I can shut down your droplet. These things aren't free. 34 | 35 | Hope you enjoyed the workshop! 36 | 37 | --cguida 38 | 39 | - [ ] Close all your channels 40 | - [ ] Withdraw all your sats 41 | - [ ] Notify Chris when this is done so he can destroy your VPS 42 | -------------------------------------------------------------------------------- /docs/bonus-RTL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Bonus Rtl" 3 | sidebar_position: 6 4 | --- 5 | 6 | 7 | # BONUS: Ride The Lightning 8 | 9 | - In this section we will install and use Ride The Lightning (RTL)! 10 | - RTL is a webapp GUI for lightning nodes. 11 | - It is compatible with LND, CLN, and Eclair. 12 | - We're using it with CLN, of course. 13 | 14 | # Exercise: Install and use RTL 15 | 16 | ## Add RTL to your config 17 | Copy this into your config: 18 | 19 | ```nix 20 | services.rtl = { 21 | enable = true; 22 | nodes.clightning.enable = true; 23 | }; 24 | ``` 25 | 26 | ## Switch to the new config 27 | 28 | ``` 29 | sudo nixos-rebuild switch --flake /etc/nixos/#btcpp-berlin-mutinynet 30 | ``` 31 | 32 | ## Start an SSH tunnel 33 | - SSH tunnels are the best way to access admin interfaces like RTL which really are not meant to be exposed publicly. 34 | - This guarantees that only someone with SSH access to our machine can control our Lightning node. 35 | 36 | Open a terminal window and start a new SSH session like this: 37 | 38 | ```sh 39 | ssh -L 3000:127.0.0.1:3000 bitcoiner@ 40 | ``` 41 | 42 | This will open an SSH tunnel from `localhost` on your VPS (where RTL is on port 3000) to `localhost` on your local machine. 43 | - The tunnel will continue to work as long as you keep the SSH session open. 44 | - If you're having trouble connecting, try deactivating any VPNs and restarting the tunnel. 45 | - Make sure you don't have two tunnels open to the same port. 46 | 47 | ## Use RTL in your browser 48 | You can now open a browser to `localhost:3000` and this should open RTL. 49 | 50 | Go back to your SSH session and grab your RTL password: 51 | ```sh 52 | sudo cat /etc/nix-bitcoin-secrets/rtl-password 53 | ``` 54 | 55 | Paste your RTL password into your browser window and you're in! 56 | 57 | You can now control your CLN node from a user-friendly UI. 58 | 59 | - [ ] Install RTL 60 | - [ ] Create an SSH tunnel to your RTL instance 61 | - [ ] Use RTL for great glory 62 | -------------------------------------------------------------------------------- /src/components/HomepageFeatures/index.js: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import Heading from '@theme/Heading'; 3 | import styles from './styles.module.css'; 4 | 5 | const FeatureList = [ 6 | { 7 | title: 'Easy to Use', 8 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, 9 | description: ( 10 | <> 11 | Docusaurus was designed from the ground up to be easily installed and 12 | used to get your website up and running quickly. 13 | 14 | ), 15 | }, 16 | { 17 | title: 'Focus on What Matters', 18 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, 19 | description: ( 20 | <> 21 | Docusaurus lets you focus on your docs, and we'll do the chores. Go 22 | ahead and move your docs into the docs directory. 23 | 24 | ), 25 | }, 26 | { 27 | title: 'Powered by React', 28 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, 29 | description: ( 30 | <> 31 | Extend or customize your website layout by reusing React. Docusaurus can 32 | be extended while reusing the same header and footer. 33 | 34 | ), 35 | }, 36 | ]; 37 | 38 | function Feature({Svg, title, description}) { 39 | return ( 40 |
41 |
42 | 43 |
44 |
45 | {title} 46 |

{description}

47 |
48 |
49 | ); 50 | } 51 | 52 | export default function HomepageFeatures() { 53 | return ( 54 |
55 |
56 |
57 | {FeatureList.map((props, idx) => ( 58 | 59 | ))} 60 |
61 |
62 |
63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /docs/bonus-Fulcrum.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Bonus Fulcrum" 3 | sidebar_position: 7 4 | --- 5 | 6 | 7 | # BONUS: Fulcrum 8 | 9 | - In this section we will install and use Fulcrum. 10 | - Fulcrum is a high-performance full-index personal electrum server. 11 | - You can use it as the backend for many wallet, including Sparrow and Electrum. 12 | - We'll try it with Sparrow in this section. 13 | 14 | # Exercise: Install and run Fulcrum 15 | 16 | ## Add Fulcrum to your config 17 | 18 | ```nix 19 | services.fulcrum = { 20 | enable = true; 21 | }; 22 | ``` 23 | 24 | ## Switch to the new config 25 | 26 | ``` 27 | sudo nixos-rebuild switch --flake /etc/nixos/#btcpp-berlin-mutinynet 28 | ``` 29 | 30 | ## Start an SSH tunnel 31 | Then, open a terminal window and start a new SSH session like this: 32 | 33 | ```sh 34 | ssh -L 50001:127.0.0.1:50001 bitcoiner@ 35 | ``` 36 | 37 | If you want to use the same SSH session for both RTL and Fulcrum, you can instead do: 38 | ```sh 39 | ssh -L 3000:127.0.0.1:3000 -L 50001:127.0.0.1:50001 bitcoiner@ 40 | ``` 41 | 42 | - This will open an SSH tunnel from `localhost` on your VPS (where Fulcrum is exposed on port 50001) to localhost on your local machine. 43 | - If you're having trouble connecting, try deactivating any VPNs and restarting the tunnel. 44 | - Make sure you don't have two tunnels open to the same port. 45 | 46 | You can now use your Fulcrum server as a backend for any desktop wallet, such as Sparrow. 47 | 48 | ## Install Sparrow 49 | Go to https://sparrowwallet.com/download/ and install Sparrow for your machine. 50 | 51 | ## Run Sparrow 52 | The exact method will vary depending on your OS. 53 | 54 | ## Connect Sparrow to your Fulcrum instance 55 | - Go to File->Preferences->Server->Edit Existing Connection 56 | - In "URL" put `127.0.0.1` and `50001` for the port 57 | - Make sure `SSL` is off 58 | - Make sure `Use Proxy` is off 59 | - Click `Test Connection`. This should say "Connected to Fulcrum" 60 | 61 | ## Restart in Testnet Mode 62 | 63 | - Go to Tools->Restart in Testnet to be able to interact with Mutinynet wallets. 64 | 65 | ## Create a wallet and send some transactions 66 | 67 | - Your CLN node can be used as a second on-chain mutinynet wallet 68 | - You can also send to your fellow mutinynet users 69 |

70 | - [ ] Install Fulcrum 71 | - [ ] Create an SSH tunnel to your Fulcrum instance 72 | - [ ] Connect Sparrow Desktop to your Fulcrum instance 73 | 74 | -------------------------------------------------------------------------------- /docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Intro" 3 | sidebar_position: 1 4 | slug: / 5 | --- 6 | 7 | 8 | # Deploying Your First NixOS Machine 9 | 10 | Speaker: [Chris Guida](https://github.com/chrisguida)

11 | Twitter: [@cguida6](https://x.com/cguida6) 12 | 13 | Welcome! 14 | 15 | In this tutorial, you'll set up a [Mutinynet](https://mutinynet.com) bitcoin and lightning node, and you'll open some channels and send some sats! 16 | 17 | - If you're doing this tutorial at the [btc++ conference in Berlin](https://btcplusplus.dev/berlin23/talks#cguida) on Friday, October 6, 2023, I've already set up a VPS for you to use in this workshop. 18 | - If you're doing this tutorial sometime later, you can use any NixOS machine. The config will be a bit different since the tutorial uses a config tailored to DigitalOcean. Reach out to me and I'll be happy to help you set it up :) 19 | 20 | So all you need to do is read through each section and follow the examples, and at the end you'll have a working mutinynet bitcoin and lightning node, which you can then deploy anywhere and customize to fit any bitcoin use case! 21 | 22 | ## Nix-bitcoin 23 | - Nix-bitcoin is a collection of NixOS modules that allow users to easily configure a large number of interconnected bitcoin-related services on a NixOS system. 24 | - We're using [a fork of] it today to show off how easy it makes working with bitcoin and lightning. 25 | - Nix-bitcoin is designed with security in mind, but the system we're building today is a toy system for demo and testing purposes only. 26 | - If you want to build a secure production system, make sure you read and understand the documentation on [nixbitcoin.org](https://nixbitcoin.org). 27 | 28 | ## Mutinynet 29 | - [Mutinynet](https://mutinynet.com) is a custom signet based on a [fork of bitcoind](https://github.com/benthecarman/bitcoin/tree/configure-signet-blockitme), built by the [Mutiny Wallet](https://mutinywallet.com) team. 30 | - This allows Mutinynet to have a very fast and predictable 30-second block time, which makes it ideal for testing, especially for L2 stuff like Lightning. 31 | 32 | ## Session Agenda: 33 | - Build a mutinynet lightning node 34 | - bitcoind 35 | - CLN 36 | - Bonus exercises 37 | - RTL 38 | - Fulcrum / Sparrow 39 | - Mempool 40 | 41 | ## Chris's Hackathon Plugin Ideas He Could Help You With: 42 | 43 | 1. (Easy) Use nix-bitcoin to install additional services 44 | 2. (Medium) Make a nix devShell 45 | 3. (Hard) Nixify CLN 46 | -------------------------------------------------------------------------------- /docs/bonus-Mempool.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Bonus Mempool" 3 | sidebar_position: 8 4 | --- 5 | 6 | 7 | # BONUS: Mempool 8 | 9 | - In this section we will install and use Mempool.space (Mempool). 10 | - Mempool is a pretty and functional block explorer 11 | 12 | # Exercise: Install and run Mempool 13 | 14 | ## Add Mempool and Tor to your config 15 | 16 | ```nix 17 | # enable Tor hidden services, and tor client 18 | services.tor = { 19 | enable = true; 20 | client.enable = true; 21 | }; 22 | 23 | # enable mempool service, use Fulcrum as backend for address lookups, 24 | # and enable Tor hidden service for mempool 25 | services.mempool = { 26 | enable = true; 27 | electrumServer = "fulcrum"; 28 | tor = { 29 | proxy = true; 30 | enforce = true; 31 | }; 32 | }; 33 | nix-bitcoin.onionServices.mempool-frontend.enable = true; 34 | ``` 35 | 36 | ## Switch to the new config 37 | 38 | ``` 39 | sudo nixos-rebuild switch --flake /etc/nixos/#btcpp-berlin-mutinynet 40 | ``` 41 | 42 | ## Access via Tor-enabled browser (can also use an SSH tunnel, see below) 43 | ### (If you don't already have a Tor-enabled browser, I recommend skipping to the SSH tunnel method) 44 | If you have Tor Browser (or some other Tor-enabled browser), you can access your mempool frontend via your .onion URL 45 | Here's are some [decent guides for enabling Tor in Firefox on various OSes](https://docs.start9.com/latest/guides/device-guides/). 46 | Tor can be a bit slow, but the hidden service will be accessible to anyone who knows the .onion URL. 47 | 48 | ### Get your onion URL 49 | ```sh 50 | sudo cat /var/lib/tor/onion/mempool-frontend/hostname 51 | ``` 52 | 53 | ### Visit your mempool's onion address 54 | Paste the .onion address into your browser and enjoy! 55 | 56 | ## Access via SSH tunnel 57 | Open a terminal window and start a new SSH session like this: 58 | 59 | ```sh 60 | ssh -L 60845:127.0.0.1:60845 bitcoiner@ 61 | ``` 62 | 63 | If you want to use the same SSH session for RTL, Fulcrum, and Mempool you can instead do: 64 | ```sh 65 | ssh -L 3000:127.0.0.1:3000 -L 50001:127.0.0.1:50001 -L 60845:127.0.0.1:60845 bitcoiner@ 66 | ``` 67 | 68 | - This will open an SSH tunnel from `localhost` on your VPS (where Mempool is exposed on port 60845) to localhost on your local machine. 69 | - If you're having trouble connecting, try deactivating any VPNs and restarting the tunnel. 70 | - Make sure you don't have two tunnels open to the same port. 71 | 72 | You can now visit `localhost:60845` in a browser and enjoy! 73 | 74 | - [ ] Install Mempool and Tor 75 | - [ ] Create an SSH tunnel to your RTL instance or grab your .onion URL 76 | - [ ] Use Mempool for great glory 77 | -------------------------------------------------------------------------------- /docs/chans-invoices.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Chans Invoices" 3 | sidebar_position: 5 4 | --- 5 | 6 | 7 | # Fun with opening channels and paying invoices 8 | 9 | - In this section we open channels with our fellow mutinynet lightning node operators and send each other off-chain mutinysats! 10 | 11 | # Exercise: Open channels and pay invoices 12 | 13 | ## Grab some free sats from the faucet 14 | - First, generate a new wallet address so you can deposit some sats on your node: 15 | 16 | ``` 17 | lightning-cli newaddr 18 | ``` 19 | 20 | Copy your deposit address and paste it into https://faucet.mutinynet.com to receive some free mutinynet sats! 21 | ## Get your node URI and announce it to your peers 22 | 23 | To get your node URI, first enter: 24 | ``` 25 | lightning-cli getinfo 26 | ``` 27 | - Your node URI looks like `@:` (the port is usually optional, though you'll want to include it for this exercise). 28 | - Share this URI with your peers! 29 | 30 | ## Connect to some peers 31 | - Once you've announced your URI to everyone, anyone can connect to your node (and you to them) by entering: 32 | ``` 33 | lightning-cli connect 34 | ``` 35 | (a.k.a. `lightning-cli connect @:9735`) 36 | 37 | - Connect to a handful of peers. You will be transacting with them shortly. 38 | 39 | ## Open some channels 40 | - See all the peers you have by running `lightning-cli listpeers | jq -r '.peers[] | .id, .netaddr[0]'` 41 | - Once you have some peers, you can open channels to them with `lightning-cli fundchannel `. The `amount` field can be specified as a number of sats by appending `sat` to the end of the sat amount you want to open the channel for. So, for example `lightning-cli fundchannel 260a95d3d46afbca770cff6890 1000000sat` (to open a 1-million-sat channel). 42 | - Once you have some channels, now the real fun begins! 43 | 44 | ## Creating and paying invoices 45 | - Make an invoice for 1,000 sats and send it to anyone! 46 | ``` 47 | lightning-cli invoice 1000sat test test 48 | ``` 49 | 50 | then copy and paste the `bolt11` field to the payer. 51 | 52 | - Pay invoices with: 53 | 54 | ``` 55 | lightning-cli pay 56 | ``` 57 | 58 | ## Keep it rolling 59 | - Keep creating payments and sending them until you're satisfied. 60 | - Keep track of your on-chain and channel balances with `lightning-cli bkpr-listbalances` 61 | - You can also use `lightning-cli summary` to see a nice little ASCII depiction of your node 62 | 63 | If there's still time left in the workshop, let's do some bonus stuff! 64 | 65 | - [ ] Grab some free sats from the mutinynet faucet 66 | - [ ] Connect to some peers 67 | - [ ] Open some channels 68 | - [ ] Make some invoices 69 | - [ ] Pay some invoices 70 | - [ ] Look at your node's bookkeeper balance and summary 71 | -------------------------------------------------------------------------------- /docs/cln.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Cln" 3 | sidebar_position: 4 4 | --- 5 | 6 | 7 | # CLN 8 | 9 | - In this section we install and sync `lightningd` (aka [Core Lightning](https://github.com/ElementsProject/lightning), aka CLN) on our NixOS box! 10 | - This will build and install `lightningd` v23.05.2 via the `nix-bitcoin` `bitcoind` NixOS module, using a Nix flake. 11 | - It will also configure `lightningd` as a system service and sync it with your mutinynet bitcoind node. You should wait until bitcoind is finished syncing before starting CLN, otherwise it might take a while to sync. If you accidentally do this, there are steps below to speed things up. 12 | - Shoutout to the `nix-bitcoin` team for maintaining this software for anyone to use! 13 | 14 | # Exercise: Add signet lightningd nix-bitcoin module to your system config 15 | 16 | While our bitcoin node is syncing to mutinynet, let's add a mutinynet CLN node! 17 | 18 | Add this after `nix-bitcoin.operator.name` in `/etc/nixos/configuration.nix` (make sure to edit the file with `sudo`) 19 | 20 | ```nix 21 | services.clightning = { 22 | enable = true; 23 | address = "0.0.0.0"; 24 | plugins.summary.enable = true; 25 | 26 | # enable some cool CLN features 27 | extraConfig = '' 28 | experimental-offers 29 | experimental-dual-fund 30 | experimental-splicing 31 | ''; 32 | }; 33 | ``` 34 | 35 | Make sure to add your user to the `clightning` group: 36 | 37 | ```nix 38 | extraGroups = [ "wheel" "bitcoin" "clightning" ]; 39 | ``` 40 | 41 | Finally, open port 9735 to your firewall so othernodes can connect to you: 42 | 43 | Change this line: 44 | ```nix 45 | networking.firewall.allowedTCPPorts = [ 8333 ]; 46 | ``` 47 | 48 | to look like: 49 | 50 | ```nix 51 | networking.firewall.allowedTCPPorts = [ 8333 9735 ]; 52 | ``` 53 | 54 | switch again! 55 | 56 | ``` 57 | sudo nixos-rebuild switch --flake /etc/nixos/#btcpp-berlin-mutinynet 58 | ``` 59 | 60 | Now logout and log back in to reflect the new user changes. 61 | 62 | Once back in, check your lightning node: 63 | 64 | ``` 65 | lightning-cli getinfo 66 | ``` 67 | 68 | If you started your lightning node before your bitcoin node was done syncing, this can result in a slow CLN initial sync. If this happens, you may want to just nuke it and start over, (once bitcoind is finished syncing): 69 | 70 | ``` 71 | sudo rm -rf /var/lib/clightning/signet/ && sudo systemctl restart clightning 72 | ``` 73 | 74 | This should allow CLN to sync instantly. 75 | 76 | Obviously don't do this if you already have money and channels on your node, as these will be lost. Of course, this is just signet, so the money isn't real anyway. 77 | 78 | Now open some channels and send some sats! 79 | 80 | - [ ] Create flake 81 | - [ ] Add bitcoind to system config 82 | - [ ] Add `nix-bitcoin` `operator` and `generate-secrets` to config 83 | - [ ] Switch to the new config 84 | - [ ] Log out and log back in to update your user's groups 85 | - [ ] Test new bitcoind by running `bitcoin-cli -getinfo` 86 | -------------------------------------------------------------------------------- /docs/init.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Init" 3 | sidebar_position: 2 4 | --- 5 | 6 | 7 | # Set up your NixOS VPS 8 | 9 | - If you're doing this tutorial at the btc++ conference in Berlin on Friday, October 6, 2023, I've already set up a VPS for you to use in this workshop. 10 | - If you're doing this tutorial sometime later, you can use any NixOS machine. The config will be a bit different since the tutorial uses a config tailored to DigitalOcean. Reach out to me and I'll be happy to help you set it up :) 11 | - If you just want to do the same thing I did with `terraform` and `morph`, follow [this excellent tutorial](https://justinas.org/nixos-in-the-cloud-step-by-step-part-1). The files I used for Terraform and Morph are included in [the github repo for the current tutorial](https://github.com/chrisguida/Deploying-Your-First-NixOS-Machine). 12 | 13 | # Exercise: Generate and switch to a new config 14 | 15 | Get your ip address and log into it: 16 | - user: `bitcoiner` 17 | - password: `btcpp` 18 | ```sh 19 | ssh bitcoiner@ 20 | ``` 21 | 22 | The following command will generate a new `configuration.nix` and `hardware-configuration.nix` for your system. 23 | 24 | This command will spit out a warning: `warning: not overwriting existing /etc/nixos/configuration.nix`. You can safely ignore this warning. 25 | 26 | We don't need the `configuration.nix` as we're replacing it in the next step. We just need `hardware-configuration.nix`. 27 | 28 | ```sh 29 | sudo nixos-generate-config 30 | ``` 31 | 32 | Delete the automatically generated config and make a new one: 33 | 34 | ```sh 35 | sudo rm /etc/nixos/configuration.nix 36 | sudo vim /etc/nixos/configuration.nix 37 | ``` 38 | 39 | Then type `i` (for insert) and copy and paste this into the file: 40 | 41 | ```nix 42 | { modulesPath, lib, pkgs, ... }: 43 | { 44 | imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [ 45 | 46 | # import the autogenerated `hardware-configuration.nix` 47 | ./hardware-configuration.nix 48 | 49 | # import the digitalocean-specific settings 50 | (modulesPath + "/virtualisation/digital-ocean-config.nix") 51 | ]; 52 | 53 | # Resolve a conflict between the DO-specific config and `hardware-configuration.nix` 54 | fileSystems."/".device = lib.mkForce "/dev/disk/by-label/nixos"; 55 | 56 | # set the stateVersion 57 | system.stateVersion = "23.11"; 58 | 59 | # enable flakes and nix commands 60 | nix.extraOptions = "experimental-features = nix-command flakes"; 61 | 62 | # declare user `bitcoiner` 63 | users.users.bitcoiner = { 64 | isNormalUser = true; 65 | description = "bitcoiner"; 66 | 67 | # feel free to change this or use an ssh key 68 | # delete this if you only want SSH key access 69 | password = "btcpp"; 70 | 71 | # here's how to set an SSH key: 72 | # openssh.authorizedKeys.keys = [ 73 | # "" 74 | # ]; 75 | 76 | # Allow the `bitcoiner` user to use `sudo` 77 | extraGroups = [ "wheel" ]; 78 | 79 | # install vim. I like it better than `nano`, but you can use either 80 | packages = with pkgs; [ 81 | vim 82 | 83 | # you'll want `jq` to parse your CLN node's command output 84 | jq 85 | ]; 86 | }; 87 | 88 | # Configure OpenSSH 89 | services.openssh = { 90 | 91 | # Allow password authentication 92 | settings.PasswordAuthentication = true; 93 | 94 | # Lengthen the default SSH session timeout 95 | # (The DO default is annoyingly short) 96 | extraConfig = '' 97 | ClientAliveInterval 120 98 | ClientAliveCountMax 720 99 | ''; 100 | }; 101 | } 102 | ``` 103 | 104 | Then hit ESCAPE (to exit insert mode) and type `ZZ` to save and exit vim 105 | 106 | Now let's switch to the new config (same as the old config, but now you're editing it locally instead of me editing it remotely) 107 | 108 | ```sh 109 | sudo nixos-rebuild switch 110 | ``` 111 | 112 | Now log out and log back in. Your password should still work, and this command should still work: 113 | 114 | ```sh 115 | sudo vim /etc/nixos/configuration.nix 116 | ``` 117 | 118 | Type `:q!` then press ENTER to quit `vim` without saving. 119 | 120 | - [ ] Generate config 121 | - [ ] Edit it 122 | - [ ] Switch to the new config 123 | - [ ] Test config by running `sudo vim /etc/nixos/configuration.nix` 124 | 125 | Now on to the more exciting part! 126 | -------------------------------------------------------------------------------- /docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // `@type` JSDoc annotations allow editor autocompletion and type checking 3 | // (when paired with `@ts-check`). 4 | // There are various equivalent ways to declare your Docusaurus config. 5 | // See: https://docusaurus.io/docs/api/docusaurus-config 6 | 7 | import {themes as prismThemes} from 'prism-react-renderer'; 8 | 9 | // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) 10 | 11 | /** @type {import('@docusaurus/types').Config} */ 12 | const config = { 13 | title: 'NixOS MutinyNet Tutorial', 14 | tagline: 'Welcome to the NixOS MutinyNet Tutorial. This guide will walk you through setting up and using MutinyNet with NixOS.', 15 | url: 'https://chrisguida.github.io', 16 | baseUrl: '/nixos-mutinynet-tutorial/', 17 | organizationName: 'chrisguida', // Usually your GitHub org/user name. 18 | projectName: 'nixos-mutinynet-tutorial', // Usually your repo name. 19 | onBrokenLinks: 'throw', 20 | onBrokenMarkdownLinks: 'warn', 21 | 22 | i18n: { 23 | defaultLocale: 'en', 24 | locales: ['en'], 25 | }, 26 | 27 | presets: [ 28 | [ 29 | 'classic', 30 | /** @type {import('@docusaurus/preset-classic').Options} */ 31 | ({ 32 | docs: { 33 | routeBasePath: '/', 34 | sidebarPath: './sidebars.js', 35 | }, 36 | theme: { 37 | customCss: './src/css/custom.css', 38 | }, 39 | }), 40 | ], 41 | ], 42 | 43 | themeConfig: 44 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 45 | ({ 46 | // Replace with your project's social card 47 | image: 'img/social-card.jpg', 48 | colorMode: { 49 | defaultMode: 'dark', 50 | disableSwitch: false, 51 | respectPrefersColorScheme: false, 52 | }, 53 | navbar: { 54 | title: 'Tiny Lightning Node Tutorial', 55 | items: [ 56 | { 57 | href: 'https://github.com/chrisguida/nixos-mutinynet-tutorial/', 58 | label: 'GitHub', 59 | position: 'right', 60 | }, 61 | ], 62 | }, 63 | footer: { 64 | style: 'dark', 65 | links: [ 66 | { 67 | title: 'Docs', 68 | items: [ 69 | { 70 | label: 'Intro', 71 | to: '/', 72 | }, 73 | { 74 | label: 'Init', 75 | to: '/init', 76 | }, 77 | { 78 | label: 'Bitcoind', 79 | to: '/bitcoind', 80 | }, 81 | { 82 | label: 'Cln', 83 | to: '/cln', 84 | }, 85 | { 86 | label: 'Chans Invoices', 87 | to: '/chans-invoices', 88 | }, 89 | { 90 | label: 'Bonus RTL', 91 | to: '/bonus-RTL', 92 | }, 93 | { 94 | label: 'Bonus Fulcrum', 95 | to: '/bonus-Fulcrum', 96 | }, 97 | { 98 | label: 'Bonus Mempool', 99 | to: '/bonus-Mempool', 100 | }, 101 | { 102 | label: 'Bonus Zeus', 103 | to: '/bonus-Zeus', 104 | }, 105 | { 106 | label: 'Required Cleanup', 107 | to: '/REQUIRED-CLEANUP', 108 | }, 109 | { 110 | label: 'Credits', 111 | to: '/credits', 112 | } 113 | ], 114 | }, 115 | { 116 | title: 'Social Links', 117 | items: [ 118 | { 119 | label: 'X (twitter)', 120 | href: 'https://x.com/cguida6', 121 | }, 122 | ], 123 | }, 124 | { 125 | title: 'More', 126 | items: [ 127 | { 128 | label: 'GitHub', 129 | href: 'https://github.com/chrisguida/nixos-mutinynet-tutorial/', 130 | }, 131 | ], 132 | }, 133 | ], 134 | copyright: `Copyright © ${new Date().getFullYear()} NixOS MutinyNet Tutorial. Built with Docusaurus.`, 135 | }, 136 | prism: { 137 | theme: prismThemes.github, 138 | darkTheme: prismThemes.dracula, 139 | }, 140 | }), 141 | }; 142 | 143 | export default config; 144 | -------------------------------------------------------------------------------- /docs/bonus-Zeus.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Bonus Zeus" 3 | sidebar_position: 9 4 | --- 5 | 6 | 7 | # BONUS: Zeus Wallet 8 | 9 | - In this section we will install and use the [Zeus mobile wallet](https://zeusln.com/) to access and control our CLN node. 10 | 11 | # Exercise: Install and connect Zeus Wallet to CLN via Tor 12 | ## Install Zeus on your phone 13 | 14 | First things first, make sure you download and install [Zeus](https://zeusln.com/). We'll need it again in a few steps. 15 | 16 | ## Add c-lightning-REST to your config 17 | 18 | 19 | - [c-lightning-REST](https://github.com/Ride-The-Lightning/c-lightning-REST) is a service from the RTL team that exposes an LND-like REST interface. It is the recommended way to connect a mobile client like Zeus. 20 | - You can see nix-bitcoin's documentation for Zeus [here](https://github.com/fort-nix/nix-bitcoin/blob/24bc983363aab940ac42b1954335d3d57a63a00c/docs/services.md#use-zeus-mobile-lightning-wallet-via-tor) 21 | 22 | ```nix 23 | services.clightning-rest = { 24 | enable = true; 25 | # lndconnect is a binary the nix-bitcoin team created 26 | # to display connection information for remote wallets 27 | lndconnect = { 28 | enable = true; 29 | 30 | # additionally show tor hidden service for rest API 31 | onion = true; 32 | }; 33 | }; 34 | ``` 35 | 36 | ## Switch to the new config 37 | 38 | ``` 39 | sudo nixos-rebuild switch --flake /etc/nixos/#btcpp-berlin-mutinynet 40 | ``` 41 | 42 | ## Access via Tor (see below for connecting via Tailscale) 43 | 44 | Tor can be a bit slow, but it's easier to set up than the other methods. 45 | 46 | Run the following command on your node to create a QR code with address and authentication information: 47 | 48 | ```sh 49 | lndconnect-clightning 50 | ``` 51 | 52 | ### Configure Zeus 53 | 54 | - Add a new node and scan the QR code 55 | - Name it something meaningful like "Mutinynet Tor" Click `SAVE NODE CONFIG` 56 | - Congrats, now you can control your node on the go! 57 | 58 | ## Access via Tailscale (optional) 59 | Tailscale uses Wireguard under the hood and is similar to the [Wireguard method detailed in the nix-bitcoin docs](https://github.com/fort-nix/nix-bitcoin/blob/24bc983363aab940ac42b1954335d3d57a63a00c/docs/services.md#use-zeus-mobile-lightning-wallet-via-wireguard), except you are slightly trusting Tailscale the company as a rendezvous point between your phone and server. Your traffic is still encrypted using SSL however, so as long as you verify the SSL cert the first time you connect, it's impossible for Tailscale to read your traffic. 60 | 61 | If you would like to use your node on mainnet, please consider using Wireguard as described in the link above, or use a [headscale](https://headscale.net) server instead. 62 | 63 | ### Create Tailscale.com account and connect your phone 64 | 65 | For the purposes of this section, Tailscale is fine. Go ahead and [create an account](https://tailscale.com/), then install the Tailscale app on your phone and register your phone to your account. 66 | 67 | ### Install tailscale on your server and connect it too 68 | 69 | - Add the following to your config: 70 | 71 | ```nix 72 | services.tailscale.enable = true; 73 | ``` 74 | 75 | - Now open port 3001 in your firewall so you can connect to your REST API over Tailscale: 76 | 77 | Change this line: 78 | ```nix 79 | networking.firewall.allowedTCPPorts = [ 8333 9735 ]; 80 | ``` 81 | 82 | to look like: 83 | 84 | ```nix 85 | networking.firewall.allowedTCPPorts = [ 3001 8333 9735 ]; 86 | ``` 87 | 88 | ... and switch again! 89 | 90 | - Now run: 91 | ```sh 92 | sudo tailscale up 93 | ``` 94 | 95 | - This will display a link that you can click to register your server on your tailnet, allowing your phone and your server to communicate as though they are on the same LAN, but from anywhere in the world. 96 | 97 | ### Configure Zeus 98 | 99 | - Go to your Tor node's connection settings page by clicking on the gear next to its icon. 100 | - Scroll to the bottom and click `DUPLICATE NODE CONFIG`. This will allow us to reuse the macaroon, which is the same regardless of our connection method. 101 | - In the `Host` field, erase the .onion URL and put your server's Tailscale IP address (you can find this with `tailscale status`) 102 | - Click Save node config 103 | - Congrats, now you can control your node on the go, without having to deal with Tor's latency and reliability issues! 104 | 105 |

106 | 107 | - [ ] Install Zeus and Tailscale 108 | - [ ] Create two node connections in Zeus, one for Tor and one for Tailscale 109 | - [ ] Control your Lightning node from anywhere like a god 110 | -------------------------------------------------------------------------------- /docs/bitcoind.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Bitcoind" 3 | sidebar_position: 3 4 | --- 5 | 6 | 7 | # Bitcoind 8 | 9 | - In this section we install and sync `bitcoind` on our NixOS box! 10 | - This will build the [mutinynet fork of bitcoind](https://github.com/benthecarman/bitcoin/tree/configure-signet-blockitme) from source, and install via a [modified version](https://github.com/fort-nix/nix-bitcoin/commit/e177c2eb4895c152df7baabb892a9a401daa582c) of the `nix-bitcoin` `bitcoind` NixOS module, using a Nix flake. 11 | - It will also configure `bitcoind` as a system service and start the initial block download. Syncing Mutinynet should be fairly quick; it should be done in just a few minutes. 12 | - Shoutout to [@benthecarman](https://github.com/benthecarman/) and the Mutiny Wallet team for maintaining this fork of bitcoin and making life super easy for developers! 13 | - Shoutout to [@erikarvstedt](https://github.com/erikarvstedt/) for modifying `nix-bitcoin` so we could run Mutinynet! 14 | 15 | # Exercise: Add mutinynet bitcoind `nix-bitcoin` module to your system config 16 | 17 | First, create a new file, `/etc/nixos/flake.nix`: 18 | 19 | ```sh 20 | sudo vim /etc/nixos/flake.nix 21 | ``` 22 | 23 | Activate insert mode (`i`) and copy this in: 24 | 25 | ```nix 26 | { 27 | description = "btcpp-berlin-mutinynet machine configuration"; 28 | 29 | # pull in the modified `nix-bitcoin` flake into our flake 30 | inputs.nix-bitcoin.url = "github:chrisguida/nix-bitcoin/mempool-and-fix-no-feerate"; 31 | 32 | # for a mainnet node, you would just do: 33 | # inputs.nix-bitcoin.url = "github:fort-nix/nix-bitcoin"; 34 | 35 | # However, the main branch of nix-bitcoin does not have bitcoind-mutinynet, nor mempool, 36 | # so it will not work with this tutorial. 37 | # Stay tuned, though. Mempool is close :) https://github.com/fort-nix/nix-bitcoin/pull/505 38 | 39 | outputs = { self, nix-bitcoin }: { 40 | nixosConfigurations = { 41 | 42 | # Our machine config 43 | btcpp-berlin-mutinynet = nix-bitcoin.inputs.nixpkgs.lib.nixosSystem { 44 | modules = [ 45 | 46 | # import the default NixOS modules from nix-bitcoin 47 | nix-bitcoin.nixosModules.default 48 | 49 | # import configuration.nix into our flake 50 | ./configuration.nix 51 | ]; 52 | }; 53 | }; 54 | }; 55 | } 56 | ``` 57 | 58 | Exit out of insert (ESCAPE) and hit `ZZ` again to save and exit. 59 | 60 | Now let's edit `configuration.nix` again: 61 | 62 | ```sh 63 | sudo vim /etc/nixos/configuration.nix 64 | ``` 65 | (I recommend pasting this after the services.openssh section): 66 | 67 | ```nix 68 | services.bitcoind = { 69 | 70 | # enable the bitcoind service from our flake 71 | enable = true; 72 | 73 | # enable the transaction index (optional) (needed for 74 | # block explorers and some address indexers) 75 | txindex = true; 76 | 77 | # listen for peer connections 78 | address = "0.0.0.0"; 79 | listen = true; 80 | 81 | # set fallback fee (required for mutinynet because fee estimate is always 0) 82 | # enable block filters (optional) 83 | extraConfig = '' 84 | fallbackfee=0.00000253 85 | blockfilterindex=1 86 | peerblockfilters=1 87 | ''; 88 | }; 89 | ``` 90 | 91 | Make sure to have nix-bitcoin generate your secrets, and set an operator (this can go immediately after the above): 92 | 93 | ```nix 94 | nix-bitcoin.generateSecrets = true; 95 | nix-bitcoin.operator.name = "bitcoiner"; 96 | ``` 97 | 98 | Also make sure to add your user to the `bitcoin` group: 99 | 100 | Change the `users.users.bitcoiner.extraGroups` line from 101 | 102 | ```nix 103 | extraGroups = [ "wheel" ]; 104 | ``` 105 | 106 | to 107 | 108 | 109 | ```nix 110 | extraGroups = [ "wheel" "bitcoin" ]; 111 | ``` 112 | 113 | Finally, open port 8333 in your firewall so your node is contributing to the network: 114 | ```nix 115 | networking.firewall.allowedTCPPorts = [ 8333 ]; 116 | ``` 117 | 118 | then switch your system to use your new flake: 119 | 120 | ``` 121 | sudo nixos-rebuild switch --flake /etc/nixos/#btcpp-berlin-mutinynet 122 | ``` 123 | 124 | log out of SSH and log back in to pick up the changes to your user. 125 | 126 | make sure the bitcoin node is running and track IBD progress (mutinynet's entire blockchain is under 500MB at the time of writing and IBD should take just a few minutes): 127 | 128 | ```sh 129 | bitcoin-cli -getinfo 130 | ``` 131 | 132 | - [ ] Create flake 133 | - [ ] Add bitcoind to system config 134 | - [ ] Add `nix-bitcoin` `operator` and `generate-secrets` to config 135 | - [ ] Switch to the new config 136 | - [ ] Log out and log back in to update your user's groups 137 | - [ ] Test new bitcoind by running `bitcoin-cli -getinfo` 138 | --------------------------------------------------------------------------------