2023-07-04 06:18:46 +02:00
# Enabling NixOS with Flakes
2023-06-23 14:29:12 +02:00
2023-06-30 11:00:03 +02:00
## Enabling Flakes Support
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
Flakes provide improved reproducibility and a more organized package structure, making it easier to maintain NixOS configurations compared to the traditional approach. Therefore, it is recommended to manage NixOS using Flakes.
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
However, as Flakes is still an experimental feature, it is not enabled by default. To enable Flakes, you need to modify the `/etc/nixos/configuration.nix` file as follows:
2023-06-23 14:29:12 +02:00
2023-07-08 07:34:48 +02:00
```nix{15,18-19}
2023-06-23 14:29:12 +02:00
# Edit this configuration file to define what should be installed on
2023-07-04 06:18:46 +02:00
# your system. Help is available in the configuration.nix(5) man page
2023-06-23 14:29:12 +02:00
# and in the NixOS manual (accessible by running 'nixos-help').
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];
2023-07-04 06:18:46 +02:00
# Omit the previous configuration...
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
# Enable Flakes and the new command-line tool
2023-07-08 06:42:00 +02:00
nix.settings.experimental-features = [ "nix-command" "flakes" ];
2023-06-23 14:29:12 +02:00
environment.systemPackages = with pkgs; [
2023-10-09 18:46:31 +02:00
# Flakes use Git to pull dependencies from data sources
2023-06-23 14:29:12 +02:00
git
vim
wget
curl
];
2023-08-13 06:37:28 +02:00
# Set default editor to vim
environment.variables.EDITOR = "vim";
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
# Omit the rest of the configuration...
2023-06-23 14:29:12 +02:00
}
```
2023-07-04 06:18:46 +02:00
To apply the changes, run `sudo nixos-rebuild switch` . After that, you can start writing the configuration for NixOS using Flakes.
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
## Switching to `flake.nix` for System Configuration
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
After enabling `flakes` , whenever you run `sudo nixos-rebuild switch` , it will first attempt to read the `/etc/nixos/flake.nix` file. If the file is not found, it will fallback to `/etc/nixos/configuration.nix` .
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
To learn how to write a Flakes configuration, you can refer to the official Flakes templates provided by Nix. To check the available templates, run the following command:
2023-06-23 14:29:12 +02:00
```bash
nix flake show templates
```
2023-07-04 06:18:46 +02:00
The `templates#full` template contains examples covering various use cases. Let's take a look at them:
2023-06-23 14:29:12 +02:00
```bash
nix flake init -t templates#full
cat flake.nix
```
2023-07-04 06:18:46 +02:00
After reviewing the example, create a file named `/etc/nixos/flake.nix` and copy the content of the example into it. From now on, all system modifications will be managed by Flakes using `/etc/nixos/flake.nix` .
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
Note that the copied template cannot be used directly. You need to modify it to make it work. Here's an example of `/etc/nixos/flake.nix` :
2023-06-23 14:29:12 +02:00
```nix
{
description = "Ryan's NixOS Flake";
2023-07-08 12:07:25 +02:00
# This is the standard format for flake.nix.
# `inputs` are the dependencies of the flake,
2023-06-23 14:29:12 +02:00
# and `outputs` function will return all the build results of the flake.
2023-07-08 12:07:25 +02:00
# Each item in `inputs` will be passed as a parameter to
# the `outputs` function after being pulled and built.
2023-06-23 14:29:12 +02:00
inputs = {
2023-07-08 12:07:25 +02:00
# There are many ways to reference flake inputs.
# The most widely used is `github:owner/name/reference` ,
2023-06-23 14:29:12 +02:00
# which represents the GitHub repository URL + branch/commit-id/tag.
# Official NixOS package source, using nixos-unstable branch here
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# home-manager, used for managing user configuration
home-manager = {
2023-07-08 05:44:49 +02:00
url = "github:nix-community/home-manager/release-23.05";
2023-06-23 14:29:12 +02:00
# The `follows` keyword in inputs is used for inheritance.
2023-07-08 12:07:25 +02:00
# Here, `inputs.nixpkgs` of home-manager is kept consistent with
# the `inputs.nixpkgs` of the current flake,
2023-06-23 14:29:12 +02:00
# to avoid problems caused by different versions of nixpkgs.
inputs.nixpkgs.follows = "nixpkgs";
};
};
# `outputs` are all the build result of the flake.
2023-07-19 04:35:14 +02:00
#
2023-06-23 14:29:12 +02:00
# A flake can have many use cases and different types of outputs.
2023-07-19 04:35:14 +02:00
#
# parameters in function `outputs` are defined in `inputs` and
2023-07-08 12:07:25 +02:00
# can be referenced by their names. However, `self` is an exception,
# this special parameter points to the `outputs` itself(self-reference)
2023-07-19 04:35:14 +02:00
#
2023-07-08 12:07:25 +02:00
# The `@` syntax here is used to alias the attribute set of the
# inputs's parameter, making it convenient to use inside the function.
2023-06-23 14:29:12 +02:00
outputs = { self, nixpkgs, ... }@inputs: {
nixosConfigurations = {
2023-07-08 12:07:25 +02:00
# By default, NixOS will try to refer the nixosConfiguration with
# its hostname, so the system named `nixos-test` will use this one.
# However, the configuration name can also be specified using:
# sudo nixos-rebuild switch --flake /path/to/flakes/directory#< name >
#
# The `nixpkgs.lib.nixosSystem` function is used to build this
# configuration, the following attribute set is its parameter.
#
# Run the following command in the flake's directory to
# deploy this configuration on any NixOS system:
# sudo nixos-rebuild switch --flake .#nixos-test
2023-06-23 14:29:12 +02:00
"nixos-test" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
2023-07-08 12:07:25 +02:00
# The Nix module system can modularize configuration,
# improving the maintainability of configuration.
2023-06-23 14:29:12 +02:00
#
2023-07-08 12:07:25 +02:00
# Each parameter in the `modules` is a Nix Module, and
# there is a partial introduction to it in the nixpkgs manual:
2023-06-23 14:29:12 +02:00
# < https: / / nixos . org / manual / nixpkgs / unstable / # module-system-introduction >
2023-07-08 12:07:25 +02:00
# It is said to be partial because the documentation is not
# complete, only some simple introductions.
# such is the current state of Nix documentation...
2023-06-23 14:29:12 +02:00
#
2023-07-08 12:07:25 +02:00
# A Nix Module can be an attribute set, or a function that
# returns an attribute set. By default, if a Nix Module is a
2023-10-04 09:00:55 +02:00
# function, this function have the following default parameters:
2023-07-08 12:07:25 +02:00
#
# lib: the nixpkgs function library, which provides many
# useful functions for operating Nix expressions:
# https://nixos.org/manual/nixpkgs/stable/#id-1.4
2023-07-19 04:58:23 +02:00
# config: all config options of the current flake, every useful
2023-07-08 12:07:25 +02:00
# options: all options defined in all NixOS Modules
# in the current flake
2023-07-19 04:58:23 +02:00
# pkgs: a collection of all packages defined in nixpkgs,
# plus a set of functions related to packaging.
2023-07-08 12:07:25 +02:00
# you can assume its default value is
# `nixpkgs.legacyPackages."${system}"` for now.
# can be customed by `nixpkgs.pkgs` option
# modulesPath: the default path of nixpkgs's modules folder,
2023-06-23 14:29:12 +02:00
# used to import some extra modules from nixpkgs.
2023-07-08 12:07:25 +02:00
# this parameter is rarely used,
# you can ignore it for now.
2023-06-23 14:29:12 +02:00
#
2023-10-09 18:46:31 +02:00
# The default parameters mentioned above are automatically
# generated by Nixpkgs.
# However, if you need to pass other non-default parameters
# to the submodules,
# you'll have to manually configure these parameters using
# `specialArgs` .
2023-07-08 12:07:25 +02:00
# you must use `specialArgs` by uncomment the following line:
#
2023-10-04 09:00:55 +02:00
# specialArgs = {...}; # pass custom arguments into all sub module.
2023-06-23 14:29:12 +02:00
modules = [
2023-07-08 12:07:25 +02:00
# Import the configuration.nix here, so that the
# old configuration file can still take effect.
# Note: configuration.nix itself is also a Nix Module,
2023-06-23 14:29:12 +02:00
./configuration.nix
];
};
};
};
}
```
2023-06-28 10:53:32 +02:00
We defined a NixOS system called `nixos-test` with a configuration file at `./configuration.nix` , which is the classic configuration we modified before. Therefore, we can still make use of it.
2023-06-23 14:29:12 +02:00
2023-09-04 10:15:08 +02:00
To apply the configuration to a system with hostname `nixos-test` , run `sudo nixos-rebuild switch --flake /etc/nixos#nixos-test` . No changes will be made to the system because we imported the old configuration file in `/etc/nixos/flake.nix` , so the actual state we declared remains unchanged.
2023-06-23 14:29:12 +02:00
2023-10-04 09:00:55 +02:00
The comments in the above code are already quite detailed, but let's emphasize a few points here:
1. Default parameters like `lib` , `pkgs` , `config` , and others are automatically generated by Nixpkgs and can be automatically injected into submodules without the need for additional declarations here.
2. In `specialArgs = {...};` , the content of the attribute set is omitted here. Its contents are automatically injected into submodules through name matching.
1. A common usage, for instance, is to directly write `specialArgs = inputs;` , enabling all data sources from the `inputs` attribute set to be used in the submodules.
2023-07-04 06:18:46 +02:00
## Managing System Packages with Flakes
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
After the switch, we can manage the system using Flakes. One common requirement is installing packages. We have previously seen how to install packages using `environment.systemPackages` from the official `nixpkgs` repository.
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
Now let's learn how to install packages from other sources using Flakes. This provides greater flexibility, particularly when it comes to specifying software versions. Let's use [Helix ](https://github.com/helix-editor/helix ) editor as an example.
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
First, we need to add Helix as an input in `flake.nix` :
2023-06-23 14:29:12 +02:00
2023-07-08 07:36:47 +02:00
```nix{10,20}
2023-06-23 14:29:12 +02:00
{
description = "NixOS configuration of Ryan Yin";
2023-07-04 06:18:46 +02:00
# ...
2023-06-23 14:29:12 +02:00
inputs = {
2023-07-04 06:18:46 +02:00
# ...
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
# Helix editor, using version 23.05
2023-06-23 14:29:12 +02:00
helix.url = "github:helix-editor/helix/23.05";
};
outputs = inputs@{ self, nixpkgs, ... }: {
nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
2023-07-04 06:18:46 +02:00
# Set all input parameters as specialArgs of all sub-modules
2023-10-09 18:46:31 +02:00
# so that we can use the `helix` (an attribute in inputs) in
# sub-modules directly.
2023-06-23 14:29:12 +02:00
specialArgs = inputs;
modules = [
./configuration.nix
];
};
};
};
}
```
2023-07-04 06:18:46 +02:00
Next, update `configuration.nix` to install `helix` from the `helix` input:
2023-06-23 14:29:12 +02:00
2023-07-08 07:32:05 +02:00
```nix{3,14-15}
2023-06-23 14:29:12 +02:00
# Nix will automatically inject `helix` from specialArgs
# into the third parameter of this function through name matching
{ config, pkgs, helix, ... }:
{
2023-07-04 06:18:46 +02:00
# Omit other configurations...
2023-06-23 14:29:12 +02:00
environment.systemPackages = with pkgs; [
git
vim
wget
curl
2023-07-04 06:18:46 +02:00
# Install Helix from the `helix` input
2023-06-23 14:29:12 +02:00
helix.packages."${pkgs.system}".helix
];
2023-07-04 06:18:46 +02:00
# Omit other configurations...
2023-06-23 14:29:12 +02:00
}
```
2023-07-04 06:18:46 +02:00
To deploy the changes, run `sudo nixos-rebuild switch` . After that, you can start the Helix editor by running the `hx` command.
2023-06-23 14:29:12 +02:00
2023-10-07 09:41:22 +02:00
> If your system's hostname is not `nixos-test`, you need to modify the name of `nixosConfigurations` in `flake.nix`, or use `--flake /etc/nixos#nixos-test` to specify the configuration name.
2023-07-04 06:18:46 +02:00
## Adding Custom Cache Mirrors
2023-06-23 14:29:12 +02:00
2023-06-28 10:53:32 +02:00
> If you don't need to customize the cache mirror, you can safely skip this section.
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
To accelerate package building, Nix provides < https: / / cache . nixos . org > to cache build results and avoid rebuilding packages locally.
2023-06-23 14:29:12 +02:00
2023-07-08 06:52:49 +02:00
With the classic configuration method in NixOS, additional cache sources can be added using `nix-channel` . However, Nix Flakes strives to avoid using any system-level configurations or environment variables as much as possible, ensuring that its build results are not affected by the environment. Therefore, after switching to Flakes, the `nix-channel` command becomes ineffective.
2023-06-23 14:29:12 +02:00
2023-07-04 06:18:46 +02:00
To customize the cache source, we must add the related configuration in `flake.nix` using the `nixConfig` parameter. Here's an example:
2023-06-23 14:29:12 +02:00
2023-07-08 07:32:05 +02:00
```nix{4-19}
2023-06-23 14:29:12 +02:00
{
description = "NixOS configuration of Ryan Yin";
nixConfig = {
experimental-features = [ "nix-command" "flakes" ];
substituters = [
2023-07-04 06:18:46 +02:00
# Replace the official cache with a mirror located in China
2023-07-16 07:35:45 +02:00
"https://mirrors.ustc.edu.cn/nix-channels/store"
2023-06-23 14:29:12 +02:00
"https://cache.nixos.org/"
];
2023-07-06 05:04:52 +02:00
extra-substituters = [
2023-07-04 06:18:46 +02:00
# Nix community's cache server
2023-06-23 14:29:12 +02:00
"https://nix-community.cachix.org"
];
extra-trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
};
inputs = {
2023-07-04 06:18:46 +02:00
# Omit some configurations...
2023-06-23 14:29:12 +02:00
};
outputs = {
2023-07-04 06:18:46 +02:00
# Omit some configurations...
2023-06-23 14:29:12 +02:00
};
}
```
2023-08-03 05:06:57 +02:00
After adding the new substituters, it still won't take effect. In this case, when directly deploying the configuration, you'll encounter the following warnings:
2023-08-03 05:05:21 +02:00
```
...
warning: ignoring untrusted substituter 'https://mirrors.ustc.edu.cn/nix-channels/store', you are not a trusted user.
...
```
This is a security limitation of Nix, where only trusted users can properly use the set substituters. Therefore, we need to add our own user to the trusted list. Add the following configuration to any NixOS module:
2023-10-09 18:50:11 +02:00
```nix{4-5}
2023-08-03 05:05:21 +02:00
{
# ... (other configurations omitted)
2023-10-09 18:46:31 +02:00
# Add your own username to the trusted list
nix.settings.trusted-users = [ "ryan" ];
2023-08-03 05:05:21 +02:00
# ... (other configurations omitted)
}
```
Now, to apply the configuration and make it effective, use `sudo nixos-rebuild switch` .
Nix will prioritize searching for cached packages from the domestic mirror source after the switch.
2023-10-07 09:41:22 +02:00
> If your system's hostname is not `nixos-test`, you need to modify the name of `nixosConfigurations` in `flake.nix`, or use `--flake /etc/nixos#nixos-test` to specify the configuration name.