15 KiB
Install NixOS
There are several ways to install NixOS. You can choose between a virtual machine or installing on dedicated hardware. Installing NixOS in a virtual machine is a great way to try it out, and the reproducibility of Nix means that we can easily copy a working configuration from our VM to dedicated hardware later on. We will cover how to install the NixOS image in a VM using VirtualBox, but if you are following along with dedicated hardware, the rest of the guide is essentially the same.
VirtualBox
Download the ISO file of your choice from the official source. We will use the recommended GNOME version, but it makes no difference if you choose Plasma instead.
You can follow this guide on how to install NixOS in a VirtualBox VM. Below is a summary of the steps:
-
Open VirtualBox
-
Click on
Newin the menu bar -
Name your VM
-
Choose the ISO image you've just downloaded
-
Select
Linuxas the type of ISO -
Choose
Other Linux (64-bit)for version -
Click
next -
(Recommended) Choose at least 4GB of RAM
-
(Recommended) Choose at least 2-4 processor cores
-
(Recommended) Choose at least 30GB for this install
-
If everything looks good, click
Finishand VirtualBox will create a NixOS virtual machine for you. -
Go through the graphical installer with your preferred settings.
-
At the
Installstage, it might appear to be stuck at 46%. Don't worry, let the installer do its thing and check back later. -
At the last step upon completing the installer, do not reboot but turn off the VM. Otherwise it will load the installer again!
-
To power off the VM, select the
Closeoption from the File menu and selectPower off the machine -
Change the boot order in VirtualBox
- To change the boot order in the NixOS VM, open the settings for that VM
- In settings, select
Systemand there you will find the boot order - Here, select
Hard Diskand use the up arrow icon next to the options to make it the first boot option - Press
OKto save the changes you'e made. - Alternatively, you can remove the ISO image that we added to start the installation
First look at NixOS
First let's take a look around our newly installed environment and familiarise ourselves with it.
Open up a console and navigate to the /etc/nixos directory and see what's there
cd /etc/nixos
ls
You should see a file called configuration.nix and a hardware-configuration.nix file. The hardware-configuration.nix is tailored to your specific system is probably not something we want to be messing with, so we will mostly ignore it in the rest of this guide.
On the other hand, configuration.nix defines our system thus far, let's take a look at the auto-generated configuration.nix.
sudo nano configuration.nix
Here we can see some things that we can change, like the hostname.
We also see that packages installed are defined in two places. One for the user, and the other for system-wide packages.
# configuration.nix
# user packages
users.users.username = {
isNormalUser = true;
description = "main user";
extraGroups = [ "networkmanager" "wheel" ];
packages = with pkgs; [
# thunderbird
];
};
# system-wide packages
environment.systemPackages = with pkgs; [
vim
wget
git
];
Note: change username to your username instead.
Hint: to find packages to install, a good resource is mynixos.com
As an example, let's add vim, wget and git, to the system packages.
# configuration.nix
environment.systemPackages = with pkgs; [
vim
wget
git
];
Once we have some packages in our user packages block and/or the system packages block, we can synchronise the system state with the state of the configuration file.
To do this, save the file
and then run the following command
sudo nixos-rebuild switch
The nixos-rebuild part tells NixOS to rebuild with our new packages installed. The switch part tells NixOS to "switch" to the newly built system.
You might notice that there are a bunch of references in the command output to something called /nix/store. This is basically where all the programmes that you have installed will live.
Try editing a file with vim and it should now be installed.
Channels -> Flakes
So far we have been using channels to install our packages. But most people in the Nix community are using something called flakes.
Flakes have a few advantages that make things a lot easier.
Channels and flakes both manage the packages installed on a system. The difference is that in the flake approach, there is a file called flake.lock that keeps track of the exact versions of all packages explicitly. This means that if we keep track of flake.lock using a version manager like git, then we can have a literal time machine of what goes on in the system. In case something breaks on the system, we can revert to an earlier version at a moment's notice, simply by reverting our git repo to that earlier version.
So flakes are very cool. The first step to start using flakes is to enable the ability to use flakes in our configuration.nix file.
sudo nano configuration.nix
Go to the bottom of the file and before the closing curly brace, add this following line to your configuration.
# configuration.nix
nix.settings.experimental-features = [ "nix-command" "flakes" ];
Save your configuration file and rebuild again with sudo nixos-rebuild switch.
Using flakes
We prefer to create new directory in the user's home directory called .dotfiles but you can choose to call it whatever you want.
mkdir ~/.dotfiles
cd ~/.dotfiles
The first thing we are going to do before we initialise our flake is to copy the configuration.nix and hardware-configuration.nix from /etc/nixos.
cp /etc/nixos/configuration.nix .
cp /etc/nixos/hardware-configuration.nix .
Then we will create our flake.nix file using our favourite text editor.
vim flake.nix
A basic flake.nix file has three parts. The description, inputs, and outputs.
# flake.nix
{
description = "my nix flake";
inputs = {};
outputs = {};
}
The inputs contain some git repos, for example nixpkgs or nix-bitcoin.
The outputs contain your built and working system configuration.
Inputs
To add nixpkgs as an input to our flake, we just need to tell Nix the url of where to find it.
# flake.nix
{
#...
inputs = {
nixpkgs = {
url = "github:NixOS/nixpkgs/nixos-unstable";
};
};
# ...
}
There is also a shorthand way to rewrite the above, which gives us functionally the same result. Since nixpkgs is a special repo in NixOS, we don't need to specify github in front of it.
# flake.nix
{
# ...
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
};
# ...
}
Outputs
Now that we have added some inputs, we can make use of them in our outputs.
Let's create our NixOS configuration in our outputs using the inputs we've added earlier.
# flake.nix
{
# ...
outputs = { self, nixpkgs, ... }:
let
lib = nixpkgs.lib;
in {
nixosConfigurations = {
hostname = lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
};
};
}
Note: make sure to change hostname to your own hostname.
Now we can rebuild our system using our newly created flake. Save flake.nix and exit. Run the following command to tell nixos-rebuild to use the flake in the current directory.
sudo nixos-rebuild switch --flake .
It will probably take a while to run the first time, this is because NixOS is pulling down the nixpkgs repo. It will run much faster in the future.
After the rebuild has completed, take a look inside your .dotfiles directory again. You should see a new file added called flake.lock. This file keeps track of the exact versions of the packages that get installed.
nix-bitcoin
flake.nix
Now that we have a basic NixOS configuration working, we can now add nix-bitcoin to our configuration using the flake approach.
Let's take a look at the example flake in the nix-bitcoin repo.
So we first need to add nix-bitcoin to our flake inputs.
# flake.nix
{
# ...
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
nix-bitcoin.url = "github:fort-nix/nix-bitcoin/release";
};
# ...
}
Then we can include it in our outputs.
# flake.nix
{
# ...
outputs = {
self,
nixpkgs,
nix-bitcoin,
... }:
let
lib = nixpkgs.lib;
in {
nixosConfigurations = {
hostname = lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
nix-bitcoin.nixosModules.default
# Optionally enable the secure-node preset
# to enhance security and privacy.
(nix-bitcoin + "/modules/presets/secure-node.nix")
{
# Automatically generate all secrets required by services.
# The secrets are stored in /etc/nix-bitcoin-secrets
nix-bitcoin.generateSecrets = true;
# When using nix-bitcoin as part of a larger NixOS
# configuration, setting the follow enables interactive
# access to nix-bitcoin features (like bitcoin-cli) for
# your system's main user
nix-bitcoin.operator = {
enable = true;
name = "FIXME";
};
}
];
};
};
};
}
Note: change nix-bitcoin.operator.name to your actual username.
Rebuild again with sudo nixos-rebuild switch --flake .
Note: since we've enabled the secure node preset, we have disabled sudo. Use doas instead of sudo from now on. doas is a more secure alternative to sudo. See more
Adding services
Now that our NixOS system knows where to grab its nix-bitcoin packages, let's start adding some services.
Hint: you can see a list of example services in the examples provided by nix-bitcoin.
There are several different ways to do this. For example, you can add them directly in the flake, or you can add them to your configuration.nix file. We are going to take a modularised approach instead. This means that we will make a separate configuration file for each services and import them individually into our configuration.nix file. There are several advantages to using a modularised approach. By separating our configuration by individual services, we prevent the main configuration from becoming overcrowded and hard to read. It also makes it easier to troubleshoot the individual configurations without touching other services, as we can simply disable a service if it starts having problems without affecting other services.
To start, let's create as new directory inside our .dotfiles directory called system/bitcoin where we will keep our bitcoin-related nix files. You can call this whatever you like, just make sure you import the correct file path later on.
mkdir system
mkdir system/bitcoin
cd system/bitcoin
Now let's write our bitcoind.nix file to configure bitcoind.
vim bitcoind.nix
# bitcoind.nix
{config, ...}: {
services.bitcoind = {
enable = true;
prune = 0;
txindex = true;
zmqpubrawtx = "tcp://127.0.0.1:28333";
zmqpubrawblock = "tcp://127.0.0.1:28332";
listen = true;
address = "0.0.0.0";
# Listen to RPC connections on all interfaces
rpc.address = "0.0.0.0";
# Allow RPC connections from external addresses
rpc.allowip = [
"10.10.0.0/24" # Allow a subnet
"10.50.0.3" # Allow a specific address
"0.0.0.0/0" # Allow all addresses
];
};
networking.firewall.allowedTCPPorts = [
config.services.bitcoind.port
config.services.bitcoind.rpc.port
];
# Set this to announce the onion service address to peers.
# The onion service allows accepting incoming connections via Tor.
nix-bitcoin.onionServices.bitcoind.public = true;
}
Note: change rpc.allowip to your specific network
And now import it into our configuration.nix
# configuration.nix
{ pkgs, ... }: {
imports = [
./hardware-configuration.nix
./system/bitcoin/bitcoind.nix
];
# ...
}
Rebuild the system. Remember we now use doas instead of sudo.
doas nixos-rebuild switch --flake .
After the rebuild, we should have a bitcoind service running. Let's check it by running
doas systemctl status bitcoind.service
Let's also check if our user has interactive access to commands like bitcoin-cli.
bitcoind --version
bitcoin-cli getblockchaininfo
To follow the live logs, use the following command
doas journalctl -fu bitcoind.service
To stop the service, run
doas systemctl stop bitcoind.service
To start it again, run
doas systemctl start bitcoind.service
The data directory of bitcoind is installed to /var/lib/bitcoind by nix-bitcoin. Let's take a look inside this directory. Since it is outside the home directory of our regular user, we first need to become root.
doas su
cd /var/lib/bitcoind
ls -al
Notice that these files are owned by the bitcoin user.
Try taking a look at our bitcoin.conf file.
cat bitcoin.conf
It reflects the configuration we've set up in bitcoind.nix. Nice.
Lastly, let's take a look at where nix-bitcoin is storing our secrets, like our rpc password. Still as the super user, navigate to /etc/nix-bitcoin-secrets
cd /etc/nix-bitcoin-secrets
ls -al
We can see that nix-bitcoin has automatically generated a bunch of password files for us, just like we told it to in our flake.nix.
Bonus: migrate from existing node
You might already have a bitcoind instance with a fully synced blockchain and don't want to sync the chain all over again. The good news is that you simply copy the blockchain from the existing node.
- Stop
bitcoindon both nodes
doas systemctl stop bitcoind.service
- Copy the data directory to the nix-bitcoin node
# Important: Add a trailing slash to the source path
rsync root@existing-bitcoin-node:/path/to/existing/bitcoind-datadir/ /var/lib/bitcoind
- Fix permissions on the nix-bitcoin node
doas chown -R bitcoin: /var/lib/bitcoind
- Start
bitcoind
doas systemctl start bitcoind.service
You can use the same workflow for other services. See source for more services.