···2525- Data integrity of keys have been greatly improved
2626- Unknown SSH keys will be immediately rejected unless `--ssh-accept-host` is passed.
27272828+### Documented
2929+3030+- Added a real tutorial, and seperated many how-to guides.
3131+ The tutorial leads the user through creating and deploying a Wire Hive.
3232+2833## [0.5.0] - 2025-09-18
29343035### Added
+1-1
README.md
···6677wire is a tool to deploy nixos systems. its usage is inspired by colmena however it is not a fork.
8899-Read the [The Guide](https://wire.althaea.zone/guide/wire.html), or continue reading this readme for development information.
99+Read the [The Guide](https://wire.althaea.zone/guides/installation.html), or continue reading this readme for development information.
10101111## Tree Layout
1212
···11---
22comment: true
33-title: Applying Your Config
33+title: Apply your Config
44description: How to apply a node with wire.
55---
66···10101111## What does it mean to 'apply'?
12121313-Once you have [created a hive](./getting-started), you can now "apply" your
1313+Once you have created a hive, you can now "apply" your
1414configuration to nodes in your hive. Simply, "applying" is the term used by wire to describe **deploying the
1515config**.
1616
···11---
22comment: true
33-title: Flakes
44-description: Learn how to output a hive from a flake.
33+title: How-to Keep Using nixos-rebuild
44+description: How to combine outputs.nixosConfigurations with outputs.wire
55---
6677# {{ $frontmatter.title }}
8899{{ $frontmatter.description }}
10101111-## Output a hive
1212-1313-::: tip
1414-If you have skipped ahead, please read the previous page to understand the
1515-concept of a hive.
1616-:::
1717-1818-You can use wire with a flake by outputting a hive with the `wire` flake output.
1919-Just like when using a `hive.nix`, you must provide `meta.nixpkgs` which will
2020-come from an input.
2121-2222-::: code-group
2323-<<< @/snippets/getting-started/flake.nix [flake.nix]
2424-:::
2525-2626-```
2727-❯ nix flake show
2828-git+file:///some/path
2929-└───colmena: unknown
3030-```
3131-3232-## How to keep using `nixos-rebuild`
1111+## An Example
33123413You can provide `makeHive` with your `nixosConfigurations` with the `inherit`
3514nix keyword. `makeHive` will merge any nodes and nixosConfigurations that share
-112
doc/guide/getting-started.md
···11----
22-comment: true
33-title: Getting Started
44-description: Getting started with Wire Tool!
55----
66-77-# {{ $frontmatter.title }}
88-99-## Installation
1010-1111-Wire can be heavy to compile. You should enable the substituter `wires.cachix.org`.
1212-1313-::: code-group
1414-1515-<<< @/snippets/getting-started/cache.nix [module.nix]
1616-<<< @/snippets/getting-started/nix.conf
1717-1818-:::
1919-2020-### Supported Nix & NixOS versions
2121-2222-Wire is currently _tested_ against `unstable`, `24.11` and `25.05`.
2323-For each channel, it is tested against the given channel's `pkgs.lix`.
2424-2525-There is currently a bug when our VM tests are ran with nixcpp. Nixcpp will try
2626-to download a file in a network sandbox, whereas Lix will not. We don't know
2727-how to solve it. Please see [#126](https://github.com/wires-org/wire/issues/126)
2828-2929-### NixOS / Home Manager
3030-3131-::: code-group
3232-3333-<<< @/snippets/getting-started/nixos.flake.nix [flake.nix (NixOS)]
3434-<<< @/snippets/getting-started/hm.flake.nix [flake.nix (Home Manager)]
3535-<<< @/snippets/getting-started/configuration.nix
3636-<<< @/snippets/getting-started/home.nix
3737-3838-:::
3939-4040-## Your First Hive
4141-4242-Wire groups your machines into _nodes_, which are NixOS configurations with
4343-additional information for deployment. Start by creating a `hive.nix` in the same directory as your
4444-`configuration.nix`.
4545-4646-::: info
4747-4848-To include wire in these examples, we are using
4949-[npins](https://github.com/andir/npins). To create this setup you
5050-would run `npins add github wires-org wire`.
5151-5252-:::
5353-5454-A `hive.nix` is an attribute set with NixOS configurations, each with a unique
5555-name. Add a node for your local machine:
5656-5757-```nix:line-numbers [hive.nix]
5858-let
5959- sources = import ./npins;
6060- wire = import sources.wire;
6161-in wire.makeHive {
6262- meta.nixpkgs = import sources.nixpkgs { };
6363-6464- my-local-machine = {
6565- imports = [./configuration.nix];
6666-6767- # If you don't know, find this value by running
6868- # `nix eval --expr 'builtins.currentSystem' --impure`
6969- nixpkgs.hostPlatform = "x86_64-linux";
7070- };
7171-}
7272-```
7373-7474-### A Remote Machine
7575-7676-Lets add another node to your hive! This one is an example of a remote machine.
7777-7878-```nix:line-numbers [hive.nix]
7979-let
8080- sources = import ./npins;
8181- wire = import sources.wire;
8282-in wire.makeHive {
8383- meta.nixpkgs = import sources.nixpkgs { };
8484-8585- my-local-machine = {
8686- imports = [./local-machine/configuration.nix];
8787- nixpkgs.hostPlatform = "x86_64-linux";
8888- };
8989-9090- my-remote-machine = {
9191- deployment = {
9292- # buildOnTarget defaults to `false`, enable this
9393- # if the machine is strong enough to build itself.
9494- buildOnTarget = true;
9595- target = {
9696- # Some IP or host that this node is reachable by ssh under,
9797- # defaults to "my-remote-machine" (node name).
9898- host = "10.1.1.2";
9999- # A user you can non-interactively login through ssh by,
100100- # defaults to "root".
101101- user = "root";
102102- };
103103- };
104104- imports = [./remote-machine/configuration.nix];
105105- nixpkgs.hostPlatform = "x86_64-linux";
106106- };
107107-}
108108-```
109109-110110-> [!TIP]
111111-> Read more options in [the reference](/reference/module#deployment-target) to adjust options such as
112112-> ssh port.
···11---
22comment: true
33-title: Targeting Nodes
33+title: Target Nodes
44description: Tags, nodes, and how to target them with Wire Tool.
55---
66
-49
doc/guide/wire.md
···11----
22-comment: true
33----
44-55-# What is Wire?
66-77-<p style="display: flex; gap: 8px">
88- <a href="https://github.com/wires-org/wire/actions/workflows/test.yml?query=branch%3Amain">
99- <img alt="Rust Tests Status" src="https://img.shields.io/github/actions/workflow/status/wires-org/wire/test.yml?branch=main&style=flat-square&label=Rust%20Tests">
1010- </a>
1111-1212- <a href="https://hydra.althaea.zone/jobset/wire/main">
1313- <img alt="BuildBot Build & VM Test Status" src="https://img.shields.io/github/checks-status/wires-org/wire/main?style=flat-square&label=BuildBot%20Build%20%26%20VM%20Tests">
1414- </a>
1515-1616- <a href="https://github.com/wires-org/wire/actions/workflows/pages.yml?query=branch%3Amain">
1717- <img alt="Documentation Status" src="https://img.shields.io/github/actions/workflow/status/wires-org/wire/pages.yml?branch=main&style=flat-square&label=Documentation">
1818- </a>
1919-</p>
2020-2121-Wire is a tool to deploy NixOS systems. Its usage is inspired by [colmena](https://colmena.cli.rs/). In many places it's configuration attempts to remain a superset[^1] of colmena, however it is **not** a fork.
2222-2323-[^1]: A lot of your colmena module options will continue to work with wire, but wire has additional ergonomic changes you can take advantage of.
2424-2525-::: warning
2626-Wire is alpha software, please use at your own risk. Many features listed in this documentation may not be complete / implemented.
2727-:::
2828-2929-<div class="tip custom-block" style="padding-top: 8px">
3030-3131-Ready? Skip to the [Quickstart](./getting-started).
3232-3333-</div>
3434-3535-## Why Wire?
3636-3737-::: info
3838-The following is the goal for a stable release and not fully implemented.
3939-:::
4040-4141-| Features | Wire | Colmena |
4242-| ------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------- |
4343-| Secret Management | :white_check_mark: | :white_check_mark: |
4444-| Parallel Evaluation | :white_check_mark: | [Experimental](https://colmena.cli.rs/unstable/features/parallelism.html#parallel-evaluation-experimental) |
4545-| Node Tagging | :white_check_mark: | :white_check_mark: |
4646-| Pipeline Support | :white_check_mark: | :x:[^2] |
4747-| Magic Rollback | :white_check_mark: (Planned) | :x: |
4848-4949-[^2]: You need to write custom nix code to use Colmena hive metadata inside environments like CI pipelines, bash scripting, etc., which requires a knowledge of its internals.
+30
doc/guides/flakes/overview.md
···11+---
22+comment: true
33+title: Flakes
44+description: How to output a hive from a flake.
55+---
66+77+# {{ $frontmatter.title }}
88+99+{{ $frontmatter.description }}
1010+1111+## Output a hive
1212+1313+::: tip
1414+If you have skipped ahead, please read the previous page to understand the
1515+concept of a hive.
1616+:::
1717+1818+You can use wire with a flake by outputting a hive with the `wire` flake output.
1919+Just like when using a `hive.nix`, you must provide `meta.nixpkgs` which will
2020+come from an input.
2121+2222+::: code-group
2323+<<< @/snippets/getting-started/flake.nix [flake.nix]
2424+:::
2525+2626+```
2727+❯ nix flake show
2828+git+file:///some/path
2929+└───colmena: unknown
3030+```
···11+---
22+comment: false
33+title: Wire Tutorial Overview
44+description: In this tutorial we will create and deploy a Wire Hive.
55+---
66+77+# {{ $frontmatter.title }}
88+99+Wire is a tool to deploy NixOS systems. Its usage is inspired by [colmena](https://colmena.cli.rs/). In many places it's configuration attempts to remain a superset[^1] of colmena, however it is **not** a fork.
1010+1111+[^1]: A lot of your colmena module options will continue to work with wire, but wire has additional ergonomic changes you can take advantage of.
1212+1313+::: warning
1414+Wire is alpha software, please use at your own risk. Many features listed in this documentation overall may not be complete / implemented, however features covered in this this tutorial are considered complete.
1515+:::
1616+1717+---
1818+1919+In this tutorial we will create and deploy a Wire Hive. Along the way we will
2020+encounter [npins](https://github.com/andir/npins), simple NixOS
2121+configurations, virutal machines, and deployment keys.
2222+2323+<div class="tip custom-block" style="padding-top: 8px">
2424+2525+Ready? Skip to [Nix Setup](./part-one/nix-setup).
2626+2727+</div>
2828+2929+## Why Wire?
3030+3131+| Features | Wire | Colmena |
3232+| ------------------------ | ------------------ | ------------------ |
3333+| Node Tagging | :white_check_mark: | :white_check_mark: |
3434+| Secret Management | :white_check_mark: | :white_check_mark: |
3535+| Parallel Evaluation | :white_check_mark: | :white_check_mark: |
3636+| Node Tagging | :white_check_mark: | :white_check_mark: |
3737+| Remote Builds | :white_check_mark: | :white_check_mark: |
3838+| Pipeline Support | :white_check_mark: | :x:[^2] |
3939+| Non-Root Deployments[^4] | :white_check_mark: | :x:[^3] |
4040+4141+[^2]: You need to write custom nix code to use Colmena hive metadata inside environments like CI pipelines, bash scripting, etc., which requires a knowledge of its internals. Recently it agained the [eval feature](https://colmena.cli.rs/unstable/features/eval.html) which has improved the situation since wire was first started.
4242+4343+[^3]: See https://github.com/zhaofengli/colmena/issues/120
4444+4545+[^4]:
4646+ You may deploy with _any_ user who can login through SSH, whether they be
4747+ `wheel` or not. You may need to enter your password multiple times for the various elevated
4848+ steps wire needs to perform.
+188
doc/tutorial/part-one/basic-hive.md
···11+---
22+comment: true
33+title: Basic Hive & Deployment
44+description: Creating a basic hive and deploying changes to the virtual machine.
55+---
66+77+# {{ $frontmatter.title }}
88+99+{{ $frontmatter.description }}
1010+1111+## Editing `hive.nix`
1212+1313+Open a text editor and edit `hive.nix`. You should copy this example, which imports
1414+the npins sources we added. It also calls `makeHive`, and gives Wire `nixpkgs`
1515+from npins as well.
1616+1717+```nix:line-numbers [hive.nix]
1818+let
1919+ # import npins sources
2020+ sources = import ./npins;
2121+ # import `wire` from npins sources
2222+ wire = import sources.wire;
2323+in
2424+wire.makeHive {
2525+ # give Wire nixpkgs from npins
2626+ meta.nixpkgs = import sources.nixpkgs { };
2727+2828+ # we'll edit this part
2929+}
3030+```
3131+3232+Lets check out what wire sees with `wire show`.
3333+3434+```sh
3535+[nix-shell]$ wire show
3636+ WARN wire: use --json to output something scripting suitable
3737+Hive {
3838+ nodes: {},
3939+ schema: 0,
4040+}
4141+```
4242+4343+The line `nodes: {}` means theres no "nodes" in our hive.
4444+4545+## Adding The First Node
4646+4747+Lets add the virtual machine as a node to the hive with the name
4848+`virtual-machine`. Additionally, we will add `deployment.target`, recalling we
4949+forwarded sshd `virtual-machine:22` to the port `localhost:2222`:
5050+5151+```nix:line-numbers [hive.nix]
5252+let
5353+ sources = import ./npins;
5454+ wire = import sources.wire;
5555+in
5656+wire.makeHive {
5757+ meta.nixpkgs = import sources.nixpkgs { };
5858+5959+ virtual-machine = { # [!code ++]
6060+ deployment.target = { # [!code ++]
6161+ port = 2222; # [!code ++]
6262+ hosts = [ "localhost" ]; # [!code ++]
6363+ }; # [!code ++]
6464+6565+ nixpkgs.hostPlatform = "x86_64-linux"; # [!code ++]
6666+ }; # [!code ++]
6767+}
6868+```
6969+7070+## A naive `wire apply`
7171+7272+If we tried to run `wire apply` on our hive at this stage, it likely won't work.
7373+If you've used NixOS before, you'll notice that many important options are
7474+missing. But let's try anyway:
7575+7676+```sh
7777+[nix-shell]$ wire apply
7878+ERROR apply{goal=Switch on=}:goal{node=virtual-machine}: lib::hive::node: Failed to execute `Evaluate the node`
7979+Error: × 1 node(s) failed to apply.
8080+8181+Error:
8282+ × node virtual-machine failed to apply
8383+ ├─▶ wire::Evaluate
8484+ │
8585+ │ × failed to evaluate `--file /home/marsh/scratch/wire-tutorial/hive.nix topLevels.virtual-machine` from the context
8686+ │ │ of a hive.
8787+ │
8888+ ╰─▶ nix --extra-experimental-features nix-command --extra-experimental-features flakes eval --json --file /home/marsh/scratch/
8989+ wire-tutorial/hive.nix topLevels.virtual-machine --log-format internal-json failed (reason: known-status) with code 1 (last 20
9090+ lines):
9191+ error:
9292+ … while evaluating '(evaluateNode node).config.system.build.toplevel' to select 'drvPath' on it
9393+ at /nix/store/5pfz0v479gnciac17rcqi2gwyz8pl4s0-source/runtime/evaluate.nix:65:23:
9494+ 64|
9595+ 65| getTopLevel = node: (evaluateNode node).config.system.build.toplevel.drvPath;
9696+ | ^
9797+ 66| in
9898+9999+ … while calling the 'head' builtin
100100+ at /nix/store/n3d1ricw0cb5jd8vvfym6ig0mw7x7sv9-source/lib/attrsets.nix:1701:13:
101101+ 1700| if length values == 1 || pred here (elemAt values 1) (head values) then
102102+ 1701| head values
103103+ | ^
104104+ 1702| else
105105+106106+ (stack trace truncated; use '--show-trace' to show the full trace)
107107+108108+ error:
109109+ Failed assertions:
110110+ - The ‘fileSystems’ option does not specify your root file system.
111111+ - You must set the option ‘boot.loader.grub.devices’ or 'boot.loader.grub.mirroredBoots' to make the system bootable.
112112+ trace: evaluation warning: system.stateVersion is not set, defaulting to 25.11. Read why this matters on https://nixos.org/
113113+ manual/nixos/stable/options.html#opt-system.stateVersion.
114114+115115+```
116116+117117+The command complained about not defining any fileSystems or a boot loader.
118118+The `${sources.nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix` imported in
119119+`vm.nix` does
120120+extra work to make our virtual machine work, which we are currently missing.
121121+122122+## Importing `vm.nix`
123123+124124+Lets import our `vm.nix` to this hive to fix our evaluation errors.
125125+Additionally, add a new package such as `vim` to our configuration:
126126+127127+```nix:line-numbers [hive.nix]
128128+let
129129+ sources = import ./npins;
130130+ wire = import sources.wire;
131131+in
132132+wire.makeHive {
133133+ meta.nixpkgs = import sources.nixpkgs { };
134134+135135+ virtual-machine = {
136136+ deployment.target = {
137137+ port = 2222;
138138+ hosts = [ "localhost" ];
139139+ };
140140+141141+ imports = [ # [!code ++]
142142+ ./vm.nix # [!code ++]
143143+ ]; # [!code ++]
144144+145145+ environment.systemPackages = [ pkgs.vim ]; # [!code ++]
146146+147147+ nixpkgs.hostPlatform = "x86_64-linux";
148148+ };
149149+}
150150+```
151151+152152+## Our first deploy
153153+154154+Trying our basic `wire apply` again with these changes:
155155+156156+```sh
157157+[nix-shell]$ wire apply
158158+...
159159+ INFO lib::nix_log: stopping the following units: boot.mount
160160+ INFO lib::nix_log: NOT restarting the following changed units: systemd-fsck@dev-disk-by\x2dlabel-ESP.service
161161+ INFO lib::nix_log: activating the configuration...
162162+ INFO lib::nix_log: setting up /etc...
163163+ INFO lib::nix_log: restarting systemd...
164164+ INFO lib::nix_log: reloading user units for root...
165165+ INFO lib::nix_log: restarting sysinit-reactivation.target
166166+ INFO lib::nix_log: reloading the following units: dbus.service
167167+ INFO lib::nix_log: the following new units were started: boot.automount, sysinit-reactivation.target, systemd-tmpfiles-resetup.service
168168+ INFO apply{goal=Switch on=}:goal{node=virtual-machines}: lib::hive::node: Executing step `Upload key @ PostActivation`
169169+ INFO apply{goal=Switch on=}: wire::apply: Successfully applied goal to 1 node(s): [Name("virtual-machines")]
170170+```
171171+172172+Now, lets confirm these changes were applied to the virtual machine by executing
173173+`vim` in the virtual machine window:
174174+175175+```sh [Virtual Machine]
176176+[root@wire-tutorial:~]# vim --version
177177+VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Jan 01 1980 00:00:00)
178178+```
179179+180180+Nice! You successfully deployed a new NixOS configuration to a **remote host**!
181181+182182+::: info
183183+This followed common steps of adding the node's `deployment.target` details and
184184+importing it's pre-existing NixOS configuration (in this case, `vm.nix`), a
185185+pattern you'll be using a lot if you chose to adopt wire.
186186+:::
187187+188188+In the next section, we'll cover how to deploy secrets / keys to our remote node.
+44
doc/tutorial/part-one/nix-setup.md
···11+---
22+comment: true
33+title: Nix Setup
44+description: Installing npins, nix, and enabling the binary cache.
55+---
66+77+# {{ $frontmatter.title }}
88+99+{{ $frontmatter.description }}
1010+1111+::: warning
1212+This page is for the purposes for the **Tutorial**.
1313+You should read [Guides - Installation](/guides/installation.html) for installing Wire for
1414+regular use.
1515+:::
1616+1717+## Nix Installation
1818+1919+You should install nix if you do not have it on your system already.
2020+There are detailed steps to installing Nix on [nix.dev](https://nix.dev/install-nix).
2121+2222+By the end of the installation, you should see something like this:
2323+2424+```sh
2525+$ nix --version
2626+nix (Nix) 2.11.0
2727+```
2828+2929+## Using `cache.althaea.zone`
3030+3131+Because Wire can be heavy to compile, it is distributed with a [binary
3232+cache](https://wiki.nixos.org/wiki/Binary_Cache). It's URL is
3333+`https://cache.althaea.zone` and it's public key is
3434+`cache.althaea.zone:BelRpa863X9q3Y+AOnl5SM7QFzre3qb+5I7g2s/mqHI=`.
3535+3636+You should trust the substituter `https://wires.cachix.org` by
3737+either editing `/etc/nix/nix.conf` or updating your NixOS configuration:
3838+3939+::: code-group
4040+4141+<<< @/snippets/getting-started/nix.conf
4242+<<< @/snippets/getting-started/cache.nix [configuration.nix]
4343+4444+:::
+110
doc/tutorial/part-one/repo-setup.md
···11+---
22+comment: true
33+title: Preparing Repo & Shell
44+description: Adding npins sources and a nix development shell.
55+---
66+77+# {{ $frontmatter.title }}
88+99+{{ $frontmatter.description }}
1010+1111+## Initialising with Git & `npins`
1212+1313+First, lets create an adhoc shell to bring these two tools into our $PATH.
1414+1515+```sh
1616+$ nix-shell -p git npins
1717+[nix-shell]$ git --version
1818+git version 2.51.0
1919+[nix-shell]$ npins --version
2020+npins 0.3.1
2121+```
2222+2323+Great! Now lets use Git & `npins` to create a new Git repo and initialise it.
2424+`npins init` may take a while to download `nixpkgs`.
2525+2626+```sh
2727+[nix-shell]$ git init wire-tutorial
2828+Initialized empty Git repository in /home/.../wire-tutorial/.git/
2929+[nix-shell]$ cd wire-tutorial/
3030+[nix-shell]$ npins init
3131+[INFO ] Welcome to npins!
3232+[INFO ] Creating `npins` directory
3333+[INFO ] Writing default.nix
3434+[INFO ] Writing initial lock file with nixpkgs entry (need to fetch latest commit first)
3535+[INFO ] Successfully written initial files to 'npins/sources.json'.
3636+```
3737+3838+This has created a pinned version of `nixpkgs` for us to use in our Wire hive.
3939+4040+## Adding wire as a dependency
4141+4242+We can now need to tell `npins` to use `wires-org/wire` as a dependency.
4343+4444+```sh
4545+[nix-shell]$ npins add github wires-org wire
4646+[INFO ] Adding 'wire' …
4747+ repository: https://github.com/wires-org/wire.git
4848+ pre_releases: false
4949+ submodules: false
5050+ version: v0.4.0
5151+ revision: f33d80c15b17c85d557d533441609a59a2210941
5252+ hash: 0wgah341hvjpvppkgwjrj50rvzf56ccmjz720xsl3mw38h9nn6sr
5353+ frozen: false
5454+```
5555+5656+Great, now lets confirm the two dependencies we have added to this `npins`
5757+project:
5858+5959+```sh
6060+[nix-shell]$ npins show
6161+nixpkgs: (Nix channel)
6262+ name: nixpkgs-unstable
6363+ url: https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre861972.88cef159e47c/nixexprs.tar.xz
6464+ hash: 0zscvr0qa3capyzhmp798hgncz2qy8ggm843y10wk35jk7p0174f
6565+ frozen: false
6666+6767+wire: (git release tag)
6868+ repository: https://github.com/wires-org/wire.git
6969+ pre_releases: false
7070+ submodules: false
7171+ version: v0.4.0
7272+ revision: f33d80c15b17c85d557d533441609a59a2210941
7373+ hash: 0wgah341hvjpvppkgwjrj50rvzf56ccmjz720xsl3mw38h9nn6sr
7474+ frozen: false
7575+```
7676+7777+## Creating a `shell.nix`
7878+7979+Open a text editor to edit `shell.nix` in the `wire-tutorial` directory.
8080+8181+```nix:line-numbers [shell.nix]
8282+let
8383+ sources = import ./npins;
8484+ pkgs = import sources.nixpkgs { };
8585+ wire = import sources.wire;
8686+in
8787+pkgs.mkShell {
8888+ packages = [
8989+ wire.packages.x86_64-linux.wire-small
9090+ pkgs.npins
9191+ pkgs.git
9292+ ];
9393+9494+ NIX_PATH = "nixpkgs=${sources.nixpkgs.outPath}";
9595+}
9696+```
9797+9898+You should now `exit` to quit the old shell, and
9999+enter a new shell with `nix-shell`. Since we added wire as a package, our new
100100+shell should have wire in the $PATH:
101101+102102+```sh
103103+[nix-shell]$ exit
104104+exit
105105+$ nix-shell
106106+[nix-shell]$ wire --version
107107+wire 0.5.0
108108+Debug: Hive::SCHEMA_VERSION 0
109109+110110+```
+132
doc/tutorial/part-one/vm-setup.md
···11+---
22+comment: true
33+title: Creating a Virtual Machine
44+description: Creating a NixOS virtual machine to use as a deployment target.
55+---
66+77+# {{ $frontmatter.title }}
88+99+{{ $frontmatter.description }}
1010+1111+## Creating a `vm.nix`
1212+1313+Open a text editor and edit `vm.nix`. Place in it this basic NixOS
1414+virtual machine configuration, which enables openssh and forwards it's 22 port:
1515+1616+```nix:line-numbers [vm.nix]
1717+let
1818+ sources = import ./npins;
1919+in
2020+{
2121+ imports = [ "${sources.nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix" ];
2222+2323+ networking.hostName = "wire-tutorial";
2424+2525+ boot = {
2626+ loader = {
2727+ systemd-boot.enable = true;
2828+ efi.canTouchEfiVariables = true;
2929+ };
3030+3131+ kernelParams = [ "console=ttyS0" ];
3232+ };
3333+3434+ # enable openssh
3535+ services = {
3636+ openssh = {
3737+ enable = true;
3838+ settings.PermitRootLogin = "yes";
3939+ };
4040+4141+ getty.autologinUser = "root";
4242+ };
4343+4444+ virtualisation = {
4545+ graphics = false;
4646+ useBootLoader = true;
4747+4848+ # forward `openssh` port 22 to localhost:2222.
4949+ forwardPorts = [
5050+ {
5151+ from = "host";
5252+ host.port = 2222;
5353+ guest.port = 22;
5454+ }
5555+ ];
5656+ };
5757+5858+ users.users.root.initialPassword = "root";
5959+6060+ system.stateVersion = "23.11";
6161+}
6262+```
6363+6464+If you like, you may take a moment to understand each line of this
6565+configuration.
6666+6767+## Building & Running the virtual machine
6868+6969+Open a seperate Terminal tab/window/instance, ensuring you enter the development
7070+shell with `nix-shell`.
7171+Then, build the virtual machine with a bootloader,
7272+taking our `vm.nix` as the nixos configuration.
7373+7474+```sh
7575+$ nix-shell
7676+[nix-shell]$ nix-build '<nixpkgs/nixos>' -A vmWithBootLoader -I nixos-config=./vm.nix
7777+```
7878+7979+Building the virtual machine can take some time, but once it completes, start it
8080+by running:
8181+8282+```sh
8383+[nix-shell]$ ./result/bin/run-wire-tutorial-vm
8484+```
8585+8686+You will see boot-up logs fly across the screen and eventually you will be placed
8787+into shell inside the virtual machine.
8888+8989+```sh [Virtual Machine]
9090+running activation script...
9191+setting up /etc...
9292+9393+Welcome to NixOS 25.11 (Xantusia)!
9494+9595+[ OK ] Created slice Slice /system/getty.
9696+[ OK ] Created slice Slice /system/modprobe.
9797+...
9898+<<< Welcome to NixOS 25.11pre861972.88cef159e47c (x86_64) - hvc0 >>>
9999+100100+Run 'nixos-help' for the NixOS manual.
101101+102102+wire-tutorial login: root (automatic login)
103103+104104+[root@wire-tutorial:~]#
105105+106106+```
107107+108108+::: details
109109+Further details on how the above commands work can be found at
110110+[nix.dev](https://nix.dev/tutorials/nixos/nixos-configuration-on-vm.html#creating-a-qemu-based-virtual-machine-from-a-nixos-configuration)
111111+:::
112112+113113+## Summary
114114+115115+Congratulations, you created a virtual machine in your terminal.
116116+We'll be deploying to this virtual machine, so keep the
117117+terminal instance open.
118118+119119+::: info
120120+From now on, commands ran inside the virtual machine will be lead with the
121121+following prompt:
122122+123123+```sh [Virtual Machine]
124124+[root@wire-tutorial:~]#
125125+126126+```
127127+128128+:::
129129+130130+::: tip
131131+If you ever want to quit the virtual machine, run the command `poweroff`.
132132+:::
+142
doc/tutorial/part-two/basic-keys.md
···11+---
22+comment: true
33+title: Deployment Keys Basics
44+description: Deploy some basic secrets with Wire tool.
55+---
66+77+# {{ $frontmatter.title }}
88+99+{{ $frontmatter.description }}
1010+1111+## Creating a `secrets.nix`
1212+1313+Lets create a NixOS module that will contain our secret keys, and import it:
1414+1515+```nix:line-numbers [hive.nix]
1616+let
1717+ sources = import ./npins;
1818+ wire = import sources.wire;
1919+in
2020+wire.makeHive {
2121+ meta.nixpkgs = import sources.nixpkgs { };
2222+2323+ virtual-machine = {
2424+ deployment.target = {
2525+ port = 2222;
2626+ hosts = [ "localhost" ];
2727+ };
2828+2929+ imports = [
3030+ ./vm.nix
3131+ ./secrets.nix # [!code ++]
3232+ ];
3333+3434+ environment.systemPackages = [ pkgs.vim ];
3535+3636+ nixpkgs.hostPlatform = "x86_64-linux";
3737+ };
3838+}
3939+```
4040+4141+```nix:line-numbers [secrets.nix]
4242+{
4343+ deployment.keys = {
4444+ # the key's unique name is `"basic.txt"`.
4545+ "basic.txt" = {
4646+ # In this key's case, the source is a literal string:
4747+ source = ''
4848+ Hello World
4949+ '';
5050+ };
5151+ };
5252+}
5353+```
5454+5555+::: details
5656+Further details on the `deployment.keys` options can be found
5757+[in the reference](/reference/module.html#deployment-keys)
5858+:::
5959+6060+Once we deploy this new configuration to the virtul machine,
6161+`/run/keys/basic.txt` will be created with the contents of the key.
6262+6363+```sh
6464+[nix-shell]$ wire apply keys
6565+ WARN lib::nix_log: Store URL: ssh://root@localhost
6666+(root@localhost) Password:
6767+6868+```
6969+7070+```sh [Virtual Machine]
7171+[root@wire-tutorial:~]# cat /run/keys/basic.txt
7272+Hello World
7373+7474+```
7575+7676+You successfully deployed your first, albeit not-so-secret, secret key! Let's
7777+move on from literal-text keys and use something a bit more powerful.
7878+7979+## File-sourced keys <Badge type="info">Optional</Badge>
8080+8181+This section is optional to try, but you can also pass `deployment.keys.<name>.source`
8282+a file path. It's contents is read and treated as literal text.
8383+8484+```sh
8585+$ echo hello world > very-important-secret.txt
8686+```
8787+8888+```nix:line-numbers [secrets.nix]
8989+{
9090+ deployment.keys = {
9191+ # ...
9292+9393+ "very-important-secret.txt" = { # [!code ++]
9494+ source = ./very-important-secret.txt; # [!code ++]
9595+ }; # [!code ++]
9696+ };
9797+}
9898+```
9999+100100+```sh [Virtual Machine]
101101+[root@wire-tutorial:~]# cat /run/keys/very-important-secret.txt
102102+hello world
103103+104104+```
105105+106106+## Command-sourced keys
107107+108108+Command-sourced keys are where the real power of wire keys lie. By passing a
109109+list of strings, wire will execute them as a command and create a key out of it's `stdout`.
110110+111111+Because the command's output is never written to the nix store, these can be
112112+considered real secrets.
113113+114114+To create a basic example, update your `secrets.nix` to include a secret that
115115+echos "hello world":
116116+117117+```nix:line-numbers [secrets.nix]
118118+{
119119+ deployment.keys = {
120120+ # ...
121121+122122+ "command.txt" = { # [!code ++]
123123+ source = [ # [!code ++]
124124+ "echo" # [!code ++]
125125+ "hello world" # [!code ++]
126126+ ]; # [!code ++]
127127+ }; # [!code ++]
128128+ };
129129+}
130130+```
131131+132132+After a quick `wire deploy secrets`, the `/run/keys/command.txt` file is
133133+created:
134134+135135+```sh [Virtual Machine]
136136+[root@wire-tutorial:~]# cat /run/keys/command.txt
137137+hello world
138138+139139+```
140140+141141+Hopefully you can see the potential of command-sourced keys, as these are the
142142+basic building block of how we achieve encrypted secrets with wire.
+105
doc/tutorial/part-two/encryption.md
···11+---
22+comment: true
33+title: Deployment Keys Basics
44+description: Deploy a age-encrypted secret with Wire tool.
55+---
66+77+# {{ $frontmatter.title }}
88+99+{{ $frontmatter.description }}
1010+1111+::: tip
1212+For this tutorial we will be using [`age`](https://github.com/FiloSottile/age),
1313+but other encryption cli tools work just as well such as GnuPG.
1414+:::
1515+1616+## Installing age
1717+1818+Alter your shell.nix to include age:
1919+2020+```nix:line-numbers [shell.nix]
2121+let
2222+ sources = import ./npins;
2323+ pkgs = import sources.nixpkgs { };
2424+ wire = import sources.wire;
2525+in
2626+pkgs.mkShell {
2727+ packages = [
2828+ wire.packages.x86_64-linux.wire-small
2929+ pkgs.npins
3030+ pkgs.git
3131+ pkgs.age # [!code ++]
3232+ ];
3333+3434+ NIX_PATH = "nixpkgs=${sources.nixpkgs.outPath}";
3535+}
3636+```
3737+3838+Quit and re-open your shell, and confirm age is now available:
3939+4040+```sh
4141+[nix-shell]$ exit
4242+exit
4343+$ nix-shell
4444+[nix-shell]$ age --version
4545+1.2.1
4646+4747+```
4848+4949+## Encrypting a secret
5050+5151+First create an age private key:
5252+5353+```sh
5454+[nix-shell]$ age-keygen -o key.txt
5555+Public key: age1j08s3kmr8zw4w8k99vs4nut5mg03dm8nfuaajuekdyzlujxply5qwsv4g0
5656+5757+```
5858+5959+::: details
6060+Further details on how age works can be found on in the
6161+[age manual](https://man.archlinux.org/man/age.1.en.txt).
6262+:::
6363+6464+Now, lets encrypt the words `"!! encrypted string !!"` with age and save it to the
6565+file `top-secret.age`.
6666+6767+We will use a pipeline to echo the encrypted string into
6868+age, and use `age-keygent -y` to give age the public key we generated, then we
6969+use the redirection operator to save the encrypted data to `top-secret.age`.
7070+7171+```sh
7272+[nix-shell]$ echo "!! encrypted string !!" | age --encrypt --recipient $(age-keygen -y key.txt) > top-secret.age
7373+```
7474+7575+## Adding an age-encrypted key
7676+7777+Now, lets combine our previous command-sourced key with `age`. Pass the
7878+arguments `age --decrypt --identity key.txt ./age-secret.age` to wire:
7979+8080+```nix:line-numbers [secrets.nix]
8181+{
8282+ deployment.keys = {
8383+ # ...
8484+8585+ "age-secret" = { # [!code ++]
8686+ source = [ # [!code ++]
8787+ "age" # [!code ++]
8888+ "--decrypt" # [!code ++]
8989+ "--identity" # [!code ++]
9090+ "key.txt" # [!code ++]
9191+ "${./age-secret.age}" # [!code ++]
9292+ ]; # [!code ++]
9393+ }; # [!code ++]
9494+ };
9595+}
9696+```
9797+9898+One `wire apply keys` later, and you have successfully deployed an encrypted
9999+key:
100100+101101+```sh [Virtual Machine]
102102+[root@wire-tutorial:~]# cat /run/keys/age-secret
103103+!! encrypted string !!
104104+105105+```