diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index e3874e0..e26834b 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -37,6 +37,43 @@ export default defineConfig({ text: "The Nix Language", items: [{ text: "Basics", link: "/the-nix-language/index.md" }], }, + { + text: "NixOS with Flakes", + items: [ + { + text: "Get Started with NixOS", + link: "/nixos-with-flakes/get-started-with-nixos.md", + }, + { + text: "Introduction to Flakes", + link: "/nixos-with-flakes/introduction-to-flakes.md", + }, + { + text: "NixOS with Flakes enabled", + link: "/nixos-with-flakes/get-started-with-flakes.md", + }, + { + text: "Started using Home Manager", + link: "/nixos-with-flakes/start-using-home-manager.md", + }, + { + text: "Modularize the Configuration", + link: "/nixos-with-flakes/modularize-the-configuration.md", + }, + { + text: "Update the System", + link: "/nixos-with-flakes/update-the-system.md", + }, + { + text: "Upgrade or Downgrade Packages", + link: "/nixos-with-flakes/upgrade-or-downgrade-packages.md", + }, + { + text: "Other useful Tips", + link: "/nixos-with-flakes/other-useful-tips.md", + }, + ], + }, ], socialLinks: [ @@ -79,7 +116,63 @@ export default defineConfig({ }, { text: "Nix 语言", - items: [{ text: "快速入门", link: "/zh/the-nix-language/index.md" }], + items: [ + { text: "快速入门", link: "/zh/the-nix-language/index.md" }, + ], + }, + + { + text: "NixOS 与 Flakes", + items: [ + { + text: "开始使用 NixOS", + link: "/nixos-with-flakes/get-started-with-nixos.md", + }, + { + text: "Flakes 简介", + link: "/nixos-with-flakes/introduction-to-flakes.md", + }, + { + text: "使用 Flakes 管理 NixOS", + link: "/nixos-with-flakes/get-started-with-flakes.md", + }, + { + text: "开始使用 Home Manager", + link: "/nixos-with-flakes/start-using-home-manager.md", + }, + { + text: "模块化系统配置", + link: "/nixos-with-flakes/modularize-the-configuration.md", + }, + { + text: "更新系统", + link: "/nixos-with-flakes/update-the-system.md", + }, + { + text: "升级或降级软件包", + link: "/nixos-with-flakes/upgrade-or-downgrade-packages.md", + }, + { + text: "其他杂七杂八的内容", + link: "/nixos-with-flakes/other-useful-tips.md", + }, + ], + }, + { + text: "Nixpkgs 高级用法", + items: [{ text: "快速入门", link: "/zh/nixpkgs/index.md" }], + }, + { + text: "NixOS 最佳实践", + items: [{ text: "快速入门", link: "/zh/best-practices/index.md" }], + }, + { + text: "Flakes 的其他玩法", + items: [{ text: "快速入门", link: "/zh/nixpkgs/index.md" }], + }, + { + text: "其他进阶话题", + items: [{ text: "快速入门", link: "/zh/nixpkgs/index.md" }], }, ], diff --git a/docs/advantage-usage/index.md b/docs/advantage-topics/index.md similarity index 100% rename from docs/advantage-usage/index.md rename to docs/advantage-topics/index.md diff --git a/docs/nix-flakes/introduction.md b/docs/flakes/index.md similarity index 100% rename from docs/nix-flakes/introduction.md rename to docs/flakes/index.md diff --git a/docs/nix-flakes/adventages-and-disadvantages.md b/docs/nix-flakes/adventages-and-disadvantages.md deleted file mode 100644 index 37cf4a4..0000000 --- a/docs/nix-flakes/adventages-and-disadvantages.md +++ /dev/null @@ -1,28 +0,0 @@ - -### Advantages of Nix Flakes - -- **Declarative configuration, Environment as Code, can be managed with Git** - - As long as the configuration files are not lost, the system can be restored to any historical state at any time(except the state that are NOT managed by NixOS, such as docker containers, postgresql data, etc...) - - Nix Flakes lock dependences's version through a lock file named `flake.lock`, to ensure that the system is reproducible, this idea actually borrows from some package managers such as npm, cargo, etc. - - Compared with Docker, Nix Flakes provides a much stronger guarantee for the reproducibility of build results, because Dockerfile is actually an imperative configuration and there is no such thing as `flake.lock` in Docker, Docker's reproducibility relies on sharing the build result(which is MUCH MORE LARGER than Dockerfile itself) through image registry(e.g. DockerHub). -- **Highly convenient system customization capability** - - By changing a few lines of configuration, various components of NixOS can be easily customized. This is because Nix encapsulates all the underlying complex operations in nix packages and only exports concise and necessary declarative parameters. - - Moreover, this modification is very safe. An example is that one NixOS user on the V2EX forum stated that "[**on NixOS, switching between different desktop environments is very simple and clean, and it is very safe. I often switch between gnome/kde/sway.**](https://www.v2ex.com/t/938569#r_13053251)" -- **Rollback**: The system can be rolled back to any historical environment at any time, and NixOS even adds all old versions to the boot options by default to ensure that the system can be rolled back at any time even though it crashes. Therefore, NixOS is also considered one of the most stable Linux Systems. -- **No dependency conflicts**: Because each software package in Nix has a unique hash, its installation path also includes this hash value, so multiple versions can coexist. -- **The community is very active, and there are quite a few third-party projects**. The official package repository, nixpkgs, has many contributors, and many people share their Nix configuration on Github/Gitlab. After browsing through it, the entire ecosystem gives me a sense of excitement in discovering a new continent. - -{{< figure src="nixos-bootloader.avif" caption="All historical versions are listed in the boot options of NixOS. Image from [NixOS Discourse - 10074](https://discourse.nixos.org/t/how-to-make-uefis-grub2-menu-the-same-as-bioss-one/10074)" >}} - -### Disadvantages of Nix Flakes - -- **Relatively high learning curve:**: If you want the system to be completely reproducible and avoid pitfalls caused by improper use, you need to learn about the entire design of Nix and manage the system in a declarative manner. You cannot blindly use `nix-env -i` (which is similar to `apt-get install`). -- **Chaotic documentation**: Flakes is still an experimental feature, and there are currently few documents introducing it, Most of the Nix community's documentation only introduces the old cli such as `nix-env`/`nix-channel`. If you want to start learning Nix directly from Flakes, you need to refer to a large number of old documents and extract what you need from them. In addition, some of Nix's current core functions are not well-documented (such as `imports` and Nix Module System), to figure out what it does, it is best to look at the source code... -- ~~Relatively few packages~~: Retract this one. The official claim is that nixpkgs has [80000+](https://search.nixos.org/packages) packages, and indeed, most packages can be found in nixpkgs. -- **Relatively high disk space usage**: To ensure that the system can be rolled back at any time, Nix preserves all historical environments by default, which can take up a lot of disk space. Although you can manually clean up old historical environments periodically with `nix-collect-garbage`, it is still recommended to buy a larger hard drive. - -### Summary - -Generally speaking, I think NixOS is suitable for developers who have some experience in using Linux and programming and want to have more control over their systems. - -I don't recommend you getting started with NixOS if you are new to Linux, it can be a very painful journey. diff --git a/docs/nixos-with-flakes/get-started-with-flakes.md b/docs/nixos-with-flakes/get-started-with-flakes.md new file mode 100644 index 0000000..6896aac --- /dev/null +++ b/docs/nixos-with-flakes/get-started-with-flakes.md @@ -0,0 +1,251 @@ + +## Enabling Flakes Support + +Compared to the default configuration approach of NixOS, Flakes provide better reproducibility and a clearer package structure that is easier to maintain. Therefore, it is recommended to manage NixOS with Flakes. + +However, as Flakes is still an experimental feature currently, it's not enabled by default yet, we need to enable it manually by modifying `/etc/nixos/configuration.nix`, example as follows: + +```nix +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running 'nixos-help'). +{ config, pkgs, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # omit the previous configuration....... + + # enable Flakes and the new command line tool + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + environment.systemPackages = with pkgs; [ + # Flakes uses git to pull dependencies from data sources, so git must be installed first + git + vim + wget + curl + + ]; + + # omit the rest of the configuration....... +} +``` + +Now run `sudo nixos-rebuild switch` to apply the changes, and then you can write the configuration for NixOS with Flakes. + +## Switching System Configuration to `flake.nix` + +After enabling `flakes`, `sudo nixos-rebuild switch` will try to read`/etc/nixos/flake.nix` first every time you run it, if not found, it will fallback to `/etc/nixos/configuration.nix`. + +Now to learn how to write a flake, let's take a look at the official flake templates provided by Nix. First, check which templates are available: + +```bash +nix flake show templates +``` + +The templates `templates#full` contains all possible usecases, let's take a look at it: + +```bash +nix flake init -t templates#full +cat flake.nix +``` + +After reading this example, let's create a file `/etc/nixos/flake.nix` and copy the content of the example into it. +With `/etc/nixos/flake.nix`, all system modifications will be taken over by Flakes from now on. + +The template we copied CAN NOT be used directly, we need to modify it to make it work, an example of `/etc/nixos/flake.nix` is as follows: + +```nix +{ + description = "Ryan's NixOS Flake"; + + # This is the standard format for flake.nix. `inputs` are the dependencies of the flake, + # and `outputs` function will return all the build results of the flake. + # Each item in `inputs` will be passed as a parameter to the `outputs` function after being pulled and built. + inputs = { + # There are many ways to reference flake inputs. The most widely used is github:owner/name/reference, + # 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 = { + url = "github:nix-community/home-manager/release-22.11"; + # The `follows` keyword in inputs is used for inheritance. + # Here, `inputs.nixpkgs` of home-manager is kept consistent with the `inputs.nixpkgs` of the current flake, + # to avoid problems caused by different versions of nixpkgs. + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + # `outputs` are all the build result of the flake. + # A flake can have many use cases and different types of outputs. + # parameters in `outputs` are defined in `inputs` and can be referenced by their names. + # However, `self` is an exception, This special parameter points to the `outputs` itself (self-reference) + # The `@` syntax here is used to alias the attribute set of the inputs's parameter, making it convenient to use inside the function. + outputs = { self, nixpkgs, ... }@inputs: { + nixosConfigurations = { + # By default, NixOS will try to refer the nixosConfiguration with its hostname. + # so the system named `nixos-test` will use this configuration. + # However, the configuration name can also be specified using `sudo nixos-rebuild switch --flake /path/to/flakes/directory#`. + # The `nixpkgs.lib.nixosSystem` function is used to build this configuration, the following attribute set is its parameter. + # Run `sudo nixos-rebuild switch --flake .#nixos-test` in the flake's directory to deploy this configuration on any NixOS system + "nixos-test" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + # The Nix module system can modularize configuration, improving the maintainability of configuration. + # + # Each parameter in the `modules` is a Nix Module, and there is a partial introduction to it in the nixpkgs manual: + # + # It is said to be partial because the documentation is not complete, only some simple introductions + # (such is the current state of Nix documentation...) + # A Nix Module can be an attribute set, or a function that returns an attribute set. + # If a Module is a function, this function can only have the following parameters: + # + # lib: the nixpkgs function library, which provides many useful functions for operating Nix expressions + # https://nixos.org/manual/nixpkgs/stable/#id-1.4 + # config: all config options of the current flake + # options: all options defined in all NixOS Modules in the current flake + # pkgs: a collection of all packages defined in nixpkgs. + # 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 builtin modules folder, + # used to import some extra modules from nixpkgs. + # this parameter is rarely used, you can ignore it for now. + # + # Only these parameters can be passed by default. + # If you need to pass other parameters, you must use `specialArgs` by uncomment the following line + # specialArgs = {...} # pass custom arguments into sub module. + modules = [ + # Import the configuration.nix we used before, so that the old configuration file can still take effect. + # Note: /etc/nixos/configuration.nix itself is also a Nix Module, so you can import it directly here + ./configuration.nix + ]; + }; + }; + }; +} +``` + +Here we defined a NixOS system called `nixos-test`, whose configuration file is `./configuration.nix`, which is the classic configuration we modified before, so we can still make use of it. + +Now run `sudo nixos-rebuild switch` to apply the configuration, and 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. + + + + +## Manage system software through Flakes + +After the switch, we can now manage the system through Flakes. The most common requirement for managing a system is to install softwares. We have seen how to install packages through `environment.systemPackages` before, and these packages are all from the official nixpkgs repository. + +Now let's learn how to install packages from other sources through Flakes. This is much more flexible than installing from nixpkgs directly. The most obvious benefit is that you can easily set the version of the software. + +Use [helix](https://github.com/helix-editor/helix) editor as an example, first we need to add the helix as an input into `flake.nix`: + +```nix +{ + description = "NixOS configuration of Ryan Yin"; + + # ...... + + inputs = { + # ...... + + # helix editor, use the tag 23.05 + helix.url = "github:helix-editor/helix/23.05"; + }; + + outputs = inputs@{ self, nixpkgs, ... }: { + nixosConfigurations = { + nixos-test = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + # set all inputs parameters as specialArgs of all sub module + # so that we can use `helix` input in sub modules + specialArgs = inputs; + modules = [ + ./configuration.nix + ]; + }; + }; + }; +} +``` + +Then udpate `configuration.nix` to install `helix` from the input `helix`: + +```nix +# Nix will automatically inject `helix` from specialArgs +# into the third parameter of this function through name matching +{ config, pkgs, helix, ... }: + +{ + # omit other configuration...... + + environment.systemPackages = with pkgs; [ + git + vim + wget + curl + + # install helix from the input `helix` + helix.packages."${pkgs.system}".helix + ]; + + # omit other configuration...... +} +``` + +Now deploy the changes by `sudo nixos-rebuild switch`, and then we can start the helix editor by `helix` command. + +## Add Custom Cache Mirror + +> You can skip this section if you don't need to customize the cache mirror. + +To speed up package building, Nix provides to cache build results to avoid build every packages locally. + +With the NixOS's classic configuration method, other cache sources can be added by using `nix-channel`, but Flakes avoids using any system-level configuration and environment variables to ensure that its build results are not affected by the environment(so the build results are reproducible). + +Therefore, to customize the cache source, we must add the related configuration in `flake.nix` by using the parameter `nixConfig`. An example is as follows: + +```nix +{ + description = "NixOS configuration of Ryan Yin"; + + # 1. To ensure purity, Flakes does not rely on the system's `/etc/nix/nix.conf`, so we have to set related configuration here. + # 2. To ensure security, flake allows only a few nixConfig parameters to be set directly by default. + # you need to add `--accept-flake-config` when executing the nix command, + # otherwise all other parameters will be ignored, and an warning will printed by nix. + nixConfig = { + experimental-features = [ "nix-command" "flakes" ]; + substituters = [ + # replace official cache with a mirror located in China + "https://mirrors.bfsu.edu.cn/nix-channels/store" + "https://cache.nixos.org/" + ]; + + extra-substituters = [ + # nix community's cache server + "https://nix-community.cachix.org" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]; + }; + + inputs = { + # omit some configuration... + }; + + outputs = { + # omit some configuration... + }; +} + +``` + +After the modification, run `sudo nixos-rebuild switch` to apply the updates. diff --git a/docs/nixos-with-flakes/get-started-with-nixos.md b/docs/nixos-with-flakes/get-started-with-nixos.md new file mode 100644 index 0000000..c607bff --- /dev/null +++ b/docs/nixos-with-flakes/get-started-with-nixos.md @@ -0,0 +1,74 @@ + +After learning the basics of the Nix language, we can start using it to configure our NixOS. The default configuration for NixOS is located at `/etc/nixos/configuration.nix`, which contains all the declarative configuration for the system, such as time zone, language, keyboard layout, network, users, file system, boot options, etc. + +If we want to modify the system state in a reproducible way (**which is also the most recommended way**), we need to manually edit `/etc/nixos/configuration.nix`, and then execute `sudo nixos-rebuild switch` to apply the modified configuration, it will generate a new system environment based on the configuration file we modified, sets the new environment as the default one, and also preserves & added the previous environment into the boot options of grub/sytemd-boot. This ensures we can always roll back to the old environment(even if the new environment fails to start). + +`/etc/nixos/configuration.nix` is the classic method to configure NixOS, which relies on data sources configured by `nix-channel` and has no version-locking mechanism, making it difficult to ensure the reproducibility of the system. **A better approach is to use Flakes**, which can ensure the reproducibility of the system and make it easy to manage the configuration. + +Now first, let's learn how to manage NixOS through the classic method, `/etc/nixos/configuration.nix`, and then migrate to the more advanced Flakes. + +## Configuring the system using `/etc/nixos/configuration.nix` + +As I mentioned earlier, this is the classic method to configured NixOS, and also the default method currently used by NixOS. It relies on data sources configured by `nix-channel` and has no version-locking mechanism, making it difficult to ensure the reproducibility of the system. + +For example, to enable ssh and add a user "ryan", simply add the following content into `/etc/nixos/configuration.nix`: + +```nix +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running 'nixos-help'). +{ config, pkgs, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # Omit the previous configuration....... + + # add user ryan + users.users.ryan = { + isNormalUser = true; + description = "ryan"; + extraGroups = [ "networkmanager" "wheel" ]; + openssh.authorizedKeys.keys = [ + # replace with your own public key + "ssh-ed25519 ryan@ryan-pc" + ]; + packages = with pkgs; [ + firefox + # thunderbird + ]; + }; + + # enable openssh-server + services.openssh = { + enable = true; + permitRootLogin = "no"; # disable root login + passwordAuthentication = false; # disable password login + openFirewall = true; + forwardX11 = true; # enable X11 forwarding + }; + + # omit the rest of the configuration....... +} +``` + +In this configuration, we declared that we want to enable the openssh service, add an ssh public key for the user ryan, and disable password login. + +Now, let's run `sudo nixos-rebuild switch` to deploy the modified configuration, and then we can login to the system using ssh with the ssh keys we configured. + +Any reproducible changes to the system can be made by modifying `/etc/nixos/configuration.nix` and deploying the changes by running `sudo nixos-rebuild switch`. + +All configuration options in `/etc/nixos/configuration.nix` can be found in the following places: + +- By searching on Google, such as `Chrome NixOS`, which will provide NixOS informations related to Chrome. Generally, the NixOS Wiki and the source code of Nixpkgs will be among the top results. +- By searching for keywords in [NixOS Options Search](https://search.nixos.org/options). +- For system-level configuration, relevant documentation can be found in [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration). +- By searching for keywords directly in the source code of [nixpkgs](https://github.com/NixOS/nixpkgs) on GitHub. + + +## References + +- [Overview of the NixOS Linux distribution]( https://nixos.wiki/wiki/Overview_of_the_NixOS_Linux_distribution) diff --git a/docs/nix-flakes/index.md b/docs/nixos-with-flakes/introduction-to-flakes.md similarity index 91% rename from docs/nix-flakes/index.md rename to docs/nixos-with-flakes/introduction-to-flakes.md index 26a7f2b..330de01 100644 --- a/docs/nix-flakes/index.md +++ b/docs/nixos-with-flakes/introduction-to-flakes.md @@ -1,19 +1,19 @@ - -## Warning about Flakes - The flakes experimental feature is a major development for Nix, it introduces a policy for managing dependencies between Nix expressions, it improves reproducibility, composability and usability in the Nix ecosystem. Although it's still an experimental feature, flakes have been widely used by the Nix community.[^1] It's Flakes is one of the most significant changes the nix project has ever seen.[^2] + +## Warning about Flakes + The benefits of Flakes are obvious, and the entire NixOS community likes it very much. Currently, more than half of the users are using Flakes[^3], so we're pretty sure that Flakes will never be deprecated. :warning: But **Flakes is still an experimental feature**, there are still many problems with it, and it is likely to introduce some breaking changes in the process of stablizing it, and it’s uncertain how greatly the breaking changes will be. -So overall, I still recommend everyone to use Flakes, but be prepared for the problems that may be caused by the upcomming breaking changes. +So overall, I still recommend everyone to use Flakes, this book is also written around NixOS and Flakes, but please be prepared for the problems that may be caused by the upcomming breaking changes. -## III. Nix Flakes and the classic Nix +## Nix Flakes and the classic Nix As `nix-command` & `flakes` are still experimental features, the official documentation does not cover them in detail, and the community's documentation about them is also very scattered. However, from the perspective of reproducibility and ease of management and maintenance, the classic Nix package structure and cli are no longer recommended for use. @@ -34,7 +34,6 @@ Here are the classic Nix commands and related concepts that are no longer needed > maybe `nix-env -qa` is still useful some times, which returns all packages installed in the System. - ## IX. When will flakes stablized {#when-will-flakes-stablized} I dived into some details about flakes: @@ -47,24 +46,6 @@ I dived into some details about flakes: After reading all of these, I feel like that flakes will eventually be stabilized in one or two years, maybe with some breaking changes. - [^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes) [^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/) [^3]: [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9) - - - - - - - - - - - - - - - -[^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes) -[^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/) diff --git a/docs/nixos-with-flakes/modularize-the-configuration.md b/docs/nixos-with-flakes/modularize-the-configuration.md new file mode 100644 index 0000000..1fe7b5e --- /dev/null +++ b/docs/nixos-with-flakes/modularize-the-configuration.md @@ -0,0 +1,248 @@ + +## Modularize your NixOS configuration + +At this point, the skeleton of the entire system is basically configured. The current configuration structure in `/etc/nixos` should be as follows: + +``` +$ tree +. +├── flake.lock +├── flake.nix +├── home.nix +└── configuration.nix +``` + +The functions of these four files are explained below: + +- `flake.lock`: An automatically generated version-lock file, which records all input sources, hash values, and version numbers of the entire flake to ensure that the system is reproducible. +- `flake.nix`: The entry file, which will be recognized and deployed when executing `sudo nixos-rebuild switch`. + - See [Flakes - NixOS Wiki](https://nixos.wiki/wiki/Flakes) for all options of flake.nix. +- `configuration.nix`: Imported as a nix module in flake.nix, all system-level configuration are currently written here. + - See [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) for all options of configuration.nix. +- `home.nix`: Imported by home-manager as the configuration of the user `ryan` in flake.nix, that is, it contains all the configuration of `ryan`, and is responsible for managing `ryan`'s home folder. + - See [Appendix A. Configuration Options - home Manager](https://nix-community.github.io/home-manager/options.html) for all options of home.nix. + +By modifying these files, you can change the status of the system and the home directory declaratively. + +As the configuration increases, it will be difficult to maintain the configuration by relying solely on `configuration.nix` and `home.nix`. Therefore, a better solution is to use the nix module system to split the configuration into multiple modules and write them in a classified manner. + +nix module system provide a paramter, `imports`, which accept a list of `.nix` files, and merge all the configuration defined in these files into the current nix module. Note that the word used here is "**merge**", which means that `imports` will **NOT** simply overwrite the duplicate configuration, but handle them more reasonably. For example, if I define `program.packages = [...]` in multiple modules, then `imports` will merge all `program.packages` defined in all nix modules into one list. Not only lists can be merged correctly, but attribute sets can also be merged correctly. The specific behavior can be explored by yourself. + +> I only found a description of `imports` in [nixpkgs-unstable official manual - evalModules parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters): `A list of modules. These are merged together to form the final configuration.`, it's a bit ambiguous... + +With the help of `imports`, we can split `home.nix` and `configuration.nix` into multiple nix modules defined in diffrent `.nix` files. + +Use [ryan4yin/nix-config/v0.0.2](https://github.com/ryan4yin/nix-config/tree/v0.0.2) as an example, which is the configuration of my previous NixOS system with i3 window manager. The structure of it is as follows: + +```shell +├── flake.lock +├── flake.nix +├── home +│ ├── default.nix # here we import all submodules by imports = [...] +│ ├── fcitx5 # fcitx5 input method's configuration +│ │ ├── default.nix +│ │ └── rime-data-flypy +│ ├── i3 # i3 window manager's configuration +│ │ ├── config +│ │ ├── default.nix +│ │ ├── i3blocks.conf +│ │ ├── keybindings +│ │ └── scripts +│ ├── programs +│ │ ├── browsers.nix +│ │ ├── common.nix +│ │ ├── default.nix # here we import all modules in programs folder by imports = [...] +│ │ ├── git.nix +│ │ ├── media.nix +│ │ ├── vscode.nix +│ │ └── xdg.nix +│ ├── rofi # rofi launcher's configuration +│ │ ├── configs +│ │ │ ├── arc_dark_colors.rasi +│ │ │ ├── arc_dark_transparent_colors.rasi +│ │ │ ├── power-profiles.rasi +│ │ │ ├── powermenu.rasi +│ │ │ ├── rofidmenu.rasi +│ │ │ └── rofikeyhint.rasi +│ │ └── default.nix +│ └── shell # shell/terminal related configuration +│ ├── common.nix +│ ├── default.nix +│ ├── nushell +│ │ ├── config.nu +│ │ ├── default.nix +│ │ └── env.nu +│ ├── starship.nix +│ └── terminals.nix +├── hosts +│ ├── msi-rtx4090 # My main machine's configuration +│ │ ├── default.nix # This is the old configuration.nix, but most of the content has been split out to modules. +│ │ └── hardware-configuration.nix # hardware & disk related configuration, autogenerated by nixos +│ └── nixos-test # my test machine's configuration +│ ├── default.nix +│ └── hardware-configuration.nix +├── modules # some common NixOS modules that can be reused +│ ├── i3.nix +│ └── system.nix +└── wallpaper.jpg # wallpaper +``` + +For more details, see [ryan4yin/nix-config/v0.0.2](https://github.com/ryan4yin/nix-config/tree/v0.0.2). + +## `mkOverride`, `lib.mkDefault` and `lib.mkForce` + +You may found some people use `lib.mkDefault` `lib.mkForce` to define values in Nix files, as their names suggest, `lib.mkDefault` and `lib.mkForce` are used to set default values or force values of options. + +You can read the source code of `lib.mkDefault` and `lib.mkForce` to understand them by running `nix repl -f ''` and then enter `:e lib.mkDefault`(To learn the basic usage of `nix repl`, just type `:?` to see the help information). + +its source code is as follows: + +```nix + # ...... + + mkOverride = priority: content: + { _type = "override"; + inherit priority content; + }; + + mkOptionDefault = mkOverride 1500; # priority of option defaults + mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default + mkImageMediaOverride = mkOverride 60; # image media profiles can be derived by inclusion into host config, hence needing to override host config, but do allow user to mkForce + mkForce = mkOverride 50; + mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’ + + # ...... +``` + +So `lib.mkDefault` is used to set default values of options, it has a priority of 1000 internally, +and `lib.mkForce` is used to force values of options, it has a priority of 50 internally. +If you just set a value of an option directly, it will be set with a default priority of 1000(the same as `lib.mkDefault`). + +the lower the `priority`'s value is, the higher the actual priority is, so `lib.mkForce` has a higher priority than `lib.mkDefault`. +If you defined multiple values with the same priority, Nix will throw an error. + +They are useful to modularize the configuration, as you can set default values in a low-level module(base module), and force values in a high-level module. + +For example, I defined some default values in : + +```nix +{ lib, pkgs, ... }: + +{ + # ...... + + nixpkgs.config.allowUnfree = lib.mkDefault false; + + # ...... +} +``` + +And for my dekstop machine, I force the values to another value in : + +```nix +{ lib, pkgs, ... }: + +{ + # import the base module + imports = [ + ./core-server.nix + ]; + + # override the default value defined in the base module + nixpkgs.config.allowUnfree = lib.mkForce true; + + # ...... +} +``` + +## `lib.mkOrder`, `lib.mkBefore` and `lib.mkAfter` + +`lib.mkBefore` and `lib.mkAfter` are used to set the merge order of **list-type options**, just like `lib.mkDefault` and `lib.mkForce`, they're also useful to modularize the configuration. + +I said before that if you defined multiple values with the same **override priority**, Nix will throw an error. +But with `lib.mkOrder`, `lib.mkBefore` or `lib.mkAfter`, you can define multiple values with the same override priority, they will be merged in the order you defined. + +Let's running `nix repl -f ''` and then enter `:e lib.mkBefore` to take a look at its source code(To learn the basic usage of `nix repl`, just type `:?` to see the help information): + +```nix + # ...... + + mkOrder = priority: content: + { _type = "order"; + inherit priority content; + }; + + mkBefore = mkOrder 500; + mkAfter = mkOrder 1500; + + # The default priority for things that don't have a priority specified. + defaultPriority = 100; + + # ...... +``` + +So `lib.mkBefore` is a shortcut for `lib.mkOrder 500`, and `lib.mkAfter` is a shortcut for `lib.mkOrder 1500`. + +To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Flake project: + +```shell +# create flake.nix with the following content +› cat < :lf . +Added 9 variables. + +# check the order of systemPackages +nix-repl> outputs.nixosConfigurations.nixos-test.config.environment.systemPackages +[ «derivation /nix/store/0xvn7ssrwa0ax646gl4hwn8cpi05zl9j-git-2.40.1.drv» + «derivation /nix/store/7x8qmbvfai68sf73zq9szs5q78mc0kny-curl-8.1.1.drv» + «derivation /nix/store/bly81l03kh0dfly9ix2ysps6kyn1hrjl-nixos-container.drv» + ...... + ...... + «derivation /nix/store/qpmpvq5azka70lvamsca4g4sf55j8994-vim-9.0.1441.drv» ] +``` + +So we can see that the order of `systemPackages` is `git -> curl -> default packages -> vim`, which is the same as the order we defined in `flake.nix`. + +> Though it's useless to adjust the order of `systemPackages`, it may be helpful at some other places... diff --git a/docs/nixos-with-flakes/other-useful-tips.md b/docs/nixos-with-flakes/other-useful-tips.md new file mode 100644 index 0000000..f79d8a0 --- /dev/null +++ b/docs/nixos-with-flakes/other-useful-tips.md @@ -0,0 +1,65 @@ + +## Manage the configuration with Git + +NixOS configuration is just a set of text files, it is very suitable to be managed with Git, and thus we can easily rollback to a previous version when we encounter some problems. + +However, NixOS places the configuration in `/etc/nixos` by default, which requires root permissions to modify, which is not convenient for daily use. +Luckily, Flakes can solve this problem, you can place your flake anywhere you like. + +For example, my usage is to place my flake in `~/nixos-config`, and then create a soft link in `/etc/nixos`: + +```shell +sudo mv /etc/nixos /etc/nixos.bak # backup the original configuration +sudo ln -s ~/nixos-config/ /etc/nixos + +# deploy the flake.nix located at the default location(/etc/nixos) +sudo nixos-rebuild switch +``` + +And then you can use Git to manage the configuration in `~/nixos-config`. The configuration can be used with ordinary user-level permissions, and it is not required to be owned by root. + +Another method is jsut to delete `/etc/nixos` directly, and specify the configuration file path each time you deploy it: + +```shell +sudo mv /etc/nixos /etc/nixos.bak +cd ~/nixos-config + +# `--flake .#nixos-test` means deploy the flake.nix located in the current directory, and the nixosConfiguration's name is `nixos-test` +sudo nixos-rebuild switch --flake .#nixos-test +``` + +Choose whichever you like. After that, system rollback will become very simple, just switch to the previous commit and then deploy it: + +```shell +cd ~/nixos-config +# switch to the previous commit +git checkout HEAD^1 +# deploy the flake.nix located in the current directory, and the nixosConfiguration's name is `nixos-test` +sudo nixos-rebuild switch --flake .#nixos-test +``` + +More operations on Git are not described here. Generally speaking, rollback can be done directly through Git. Only when the system crashes completely, you will need to restart into bootloader and boot the system from the previous historical version. + +## View and delete history data {#view-and-delete-history} + +As we mentioned before, each deployment of NixOS will generate a new version, and all versions will be added to the system boot options. In addition to restarting the computer, we can also query all available historical versions through the following command: + +```shell +nix profile history --profile /nix/var/nix/profiles/system +``` + +The command to clean up historical versions to release storage space: + +```shell +# delete all historical versions older than 7 days +sudo nix profile wipe-history --profile /nix/var/nix/profiles/system --older-than 7d + +# we need to collect garbages after wipe-history +sudo nix store gc --debug +``` + +Another command returns all packages installed in the system: + +```shell +nix-env -qa +``` diff --git a/docs/nixos-with-flakes/start-using-home-manager.md b/docs/nixos-with-flakes/start-using-home-manager.md new file mode 100644 index 0000000..39484a6 --- /dev/null +++ b/docs/nixos-with-flakes/start-using-home-manager.md @@ -0,0 +1,218 @@ + +## Start using home-manager + +As I mentioned earlier, NixOS can only manage system-level configuration, to manage the Home directory(user-level configuration), we need to install home-manager. + +According to the official document [Home Manager Manual](https://nix-community.github.io/home-manager/index.htm), in order to install home-manager as a module of NixOS, we need to create `/etc/nixos/home.nix` first, an example content shown below: + +```nix +{ config, pkgs, ... }: + +{ + # TODO please change the username & home direcotry to your own + home.username = "ryan"; + home.homeDirectory = "/home/ryan"; + + # link the configuration file in current directory to the specified location in home directory + # home.file.".config/i3/wallpaper.jpg".source = ./wallpaper.jpg; + + # link all files in `./scripts` to `~/.config/i3/scripts` + # home.file.".config/i3/scripts" = { + # source = ./scripts; + # recursive = true; # link recursively + # executable = true; # make all files executable + # }; + + # encode the file content in nix configuration file directly + # home.file.".xxx".text = '' + # xxx + # ''; + + # set cursor size and dpi for 4k monitor + xresources.properties = { + "Xcursor.size" = 16; + "Xft.dpi" = 172; + }; + + # basic configuration of git, please change to your own + programs.git = { + enable = true; + userName = "Ryan Yin"; + userEmail = "xiaoyin_c@qq.com"; + }; + + # Packages that should be installed to the user profile. + home.packages = [ + # here is some command line tools I use frequently + # feel free to add your own or remove some of them + + neofetch + nnn # terminal file manager + + # archives + zip + xz + unzip + p7zip + + # utils + ripgrep # recursively searches directories for a regex pattern + jq # A lightweight and flexible command-line JSON processor + yq-go # yaml processer https://github.com/mikefarah/yq + exa # A modern replacement for ‘ls’ + fzf # A command-line fuzzy finder + + # networking tools + mtr # A network diagnostic tool + iperf3 + dnsutils # `dig` + `nslookup` + ldns # replacement of `dig`, it provide the command `drill` + aria2 # A lightweight multi-protocol & multi-source command-line download utility + socat # replacement of openbsd-netcat + nmap # A utility for network discovery and security auditing + ipcalc # it is a calculator for the IPv4/v6 addresses + + # misc + cowsay + file + which + tree + gnused + gnutar + gawk + zstd + gnupg + + # nix related + # + # it provides the command `nom` works just like `nix + # with more details log output + nix-output-monitor + + # productivity + hugo # static site generator + glow # markdown previewer in terminal + + btop # replacement of htop/nmon + iotop # io monitoring + iftop # network monitoring + + # system call monitoring + strace # system call monitoring + ltrace # library call monitoring + lsof # list open files + + # system tools + sysstat + lm_sensors # for `sensors` command + ethtool + pciutils # lspci + usbutils # lsusb + ]; + + # starship - an customizable prompt for any shell + programs.starship = { + enable = true; + settings = { + add_newline = false; + aws.disabled = true; + gcloud.disabled = true; + line_break.disabled = true; + }; + }; + + # alacritty - a cross-platform, GPU-accelerated terminal emulator + programs.alacritty = { + enable = true; + env.TERM = "xterm-256color"; + font = { + size = 12; + draw_bold_text_with_bright_colors = true; + }; + scrolling.multiplier = 5; + selection.save_to_clipboard = true; + }; + + programs.bash = { + enable = true; + enableCompletion = true; + bashrcExtra = '' + export PATH="$PATH:$HOME/bin:$HOME/.local/bin:$HOME/go/bin" + ''; + + # set some aliases, feel free to add more or remove some + shellAliases = { + urldecode = "python3 -c 'import sys, urllib.parse as ul; print(ul.unquote_plus(sys.stdin.read()))'"; + urlencode = "python3 -c 'import sys, urllib.parse as ul; print(ul.quote_plus(sys.stdin.read()))'"; + httpproxy = "export https_proxy=http://127.0.0.1:7890; export http_proxy=http://127.0.0.1:7890;"; + }; + }; + + # This value determines the home Manager release that your + # configuration is compatible with. This helps avoid breakage + # when a new home Manager release introduces backwards + # incompatible changes. + # + # You can update home Manager without changing this value. See + # the home Manager release notes for a list of state version + # changes in each release. + home.stateVersion = "22.11"; + + # Let home Manager install and manage itself. + programs.home-manager.enable = true; +} +``` + +After adding `/etc/nixos/home.nix`, you need to import this new configuration file in `/etc/nixos/flake.nix` to make use of it, use the following command to generate an example in the current folder for reference: + +```shell +nix flake new example -t github:nix-community/home-manager#nixos +``` + +After adjusting the parameters, the content of `/etc/nixos/flake.nix` is as follows: + +```nix +{ + description = "NixOS configuration"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + home-manager.url = "github:nix-community/home-manager"; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = inputs@{ nixpkgs, home-manager, ... }: { + nixosConfigurations = { + # TODO please change the hostname to your own + nixos-test = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./configuration.nix + + # make home-manager as a module of nixos + # so that home-manager configuration will be deployed automatically when executing `nixos-rebuild switch` + home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + + # TODO replace ryan with your own username + home-manager.users.ryan = import ./home.nix; + + # Optionally, use home-manager.extraSpecialArgs to pass arguments to home.nix + } + ]; + }; + }; + }; +} +``` + +Then run `sudo nixos-rebuild switch` to apply the configuration, and home-manager will be installed automatically. + +After the installation, all user-level packages and configuration can be managed through `/etc/nixos/home.nix`. When running `sudo nixos-rebuild switch`, the configuration of home-manager will be applied automatically. (**It's not necessary to run `home-manager switch` manually**!) + +To find the options we can use in `home.nix`, referring to the following documents: + +- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.html): A list of all options, it is recommended to search for keywords in it. +- [home-manager](https://github.com/nix-community/home-manager): Some options are not listed in the official documentation, or the documentation is not clear enough, you can directly search and read the corresponding source code in this home-manager repo. diff --git a/docs/nixos-with-flakes/update-the-system.md b/docs/nixos-with-flakes/update-the-system.md new file mode 100644 index 0000000..1e921c0 --- /dev/null +++ b/docs/nixos-with-flakes/update-the-system.md @@ -0,0 +1,13 @@ + +## Update the system + +With Flakes, it is also very simple to update the system. Just run the following commands in `/etc/nixos`: + +```shell +# update flake.lock +nix flake update +# apply the updates +sudo nixos-rebuild switch +``` + +Sometimes you may encounter some error of sha256 mismatch when running `nixos-rebuild switch`, which may be solved by updating `flake.lock` through `nix flake update`. diff --git a/docs/nixos-with-flakes/upgrade-or-downgrade-packages.md b/docs/nixos-with-flakes/upgrade-or-downgrade-packages.md new file mode 100644 index 0000000..269eeee --- /dev/null +++ b/docs/nixos-with-flakes/upgrade-or-downgrade-packages.md @@ -0,0 +1,91 @@ + +## Downgrade or upgrade some packages + +After using Flakes, most people are currently using the `nixos-unstable` branch of nixpkgs. Sometimes you will encounter some bugs, such as the [chrome/vscode crash problem](https://github.com/swaywm/sway/issues/7562) + +To resolve problems, we may need to downgrade or upgrade some packages. In Flakes, all package versions and hash values are one-to-one corresponding to the git commit of their flake input. +Therefore, to downgrade or upgrade a package, we need to lock the git commit of its flake input. + +For exmaple, let's add multiple nixpkgs, each using a different git commit or branch: + +```nix +{ + description = "NixOS configuration of Ryan Yin" + + inputs = { + # default to nixos-unstable branch + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + # the latest stable branch of nixpkgs, used to rollback the version of some packages + # the current latest version is 22.11 + nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-22.11"; + + # we can also use git commit hash to lock the version + nixpkgs-fd40cef8d.url = "github:nixos/nixpkgs/fd40cef8d797670e203a27a91e4b8e6decf0b90c"; + outputs = inputs@{ + self, + nixpkgs, + nixpkgs-stable, + nixpkgs-fd40cef8d, + ... + }: { + nixosConfigurations = { + nixos-test = nixpkgs.lib.nixosSystem rec { + system = "x86_64-linux"; + + # The core parameter, which passes the non-default nixpkgs instances to other nix modules + specialArgs = { + # To use packages from nixpkgs-stable, we need to configure some parameters for it first + pkgs-stable = import nixpkgs-stable { + system = system; # refer the `system` parameter form outer scope recursively + # To use chrome, we need to allow the installation of non-free software + config.allowUnfree = true; + }; + pkgs-fd40cef8d = import nixpkgs-fd40cef8d { + system = system; + config.allowUnfree = true; + }; + }; + modules = [ + ./hosts/nixos-test + + # omit other configuration... + ]; + }; + }; + }; +} +``` + +And then refer the packages from `pkgs-stable` or `pkgs-fd40cef8d` in your sub module, a home manager's sub module as an example: + +```nix +{ + pkgs, + config, + # nix will search and jnject this parameter from specialArgs in flake.nix + pkgs-stable, + # pkgs-fd40cef8d, + ... +}: + +{ + # refer packages from pkgs-stable instead of pkgs + home.packages = with pkgs-stable; [ + firefox-wayland + + # chrome wayland support was broken on nixos-unstable branch, so fallback to stable branch for now + # https://github.com/swaywm/sway/issues/7562 + google-chrome + ]; + + programs.vscode = { + enable = true; + package = pkgs-stable.vscode; # refer vscode from pkgs-stable instead of pkgs + }; +} +``` + +After adjusted the configuration, deploy it with `sudo nixos-rebuild switch`, then your firefox/chrome/vscode will be downgraded to the version corresponding to `nixpkgs-stable` or `nixpkgs-fd40cef8d`. + +> according to [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347), it's not a good practice to use `import` in sub modules to customize `nixpkgs`, because each `import` will create a new instance of nixpkgs, which will increase the build time and memory usage as the configuration grows. So here we create all nixpkgs instances in `flake.nix` to avoid this problem. diff --git a/docs/nixos/index.md b/docs/nixos/index.md deleted file mode 100644 index 4fe9c19..0000000 --- a/docs/nixos/index.md +++ /dev/null @@ -1,956 +0,0 @@ - -## VI. Managing the system declaratively - -> https://nixos.wiki/wiki/Overview_of_the_NixOS_Linux_distribution - -After learning the basics of the Nix language, we can start using it to configure our NixOS. The default configuration for NixOS is located at `/etc/nixos/configuration.nix`, which contains all the declarative configuration for the system, such as time zone, language, keyboard layout, network, users, file system, boot options, etc. - -If we want to modify the system state in a reproducible way (**which is also the most recommended way**), we need to manually edit `/etc/nixos/configuration.nix`, and then execute `sudo nixos-rebuild switch` to apply the modified configuration, it will generate a new system environment based on the configuration file we modified, sets the new environment as the default one, and also preserves & added the previous environment into the boot options of grub/sytemd-boot. This ensures we can always roll back to the old environment(even if the new environment fails to start). - -`/etc/nixos/configuration.nix` is the classic method to configure NixOS, which relies on data sources configured by `nix-channel` and has no version-locking mechanism, making it difficult to ensure the reproducibility of the system. **A better approach is to use Flakes**, which can ensure the reproducibility of the system and make it easy to manage the configuration. - -Now first, let's learn how to manage NixOS through the classic method, `/etc/nixos/configuration.nix`, and then migrate to the more advanced Flakes. - -### 1. Configuring the system using `/etc/nixos/configuration.nix` - -As I mentioned earlier, this is the classic method to configured NixOS, and also the default method currently used by NixOS. It relies on data sources configured by `nix-channel` and has no version-locking mechanism, making it difficult to ensure the reproducibility of the system. - -For example, to enable ssh and add a user "ryan", simply add the following content into `/etc/nixos/configuration.nix`: - -```nix -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running 'nixos-help'). -{ config, pkgs, ... }: - -{ - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - - # Omit the previous configuration....... - - # add user ryan - users.users.ryan = { - isNormalUser = true; - description = "ryan"; - extraGroups = [ "networkmanager" "wheel" ]; - openssh.authorizedKeys.keys = [ - # replace with your own public key - "ssh-ed25519 ryan@ryan-pc" - ]; - packages = with pkgs; [ - firefox - # thunderbird - ]; - }; - - # enable openssh-server - services.openssh = { - enable = true; - permitRootLogin = "no"; # disable root login - passwordAuthentication = false; # disable password login - openFirewall = true; - forwardX11 = true; # enable X11 forwarding - }; - - # omit the rest of the configuration....... -} -``` - -In this configuration, we declared that we want to enable the openssh service, add an ssh public key for the user ryan, and disable password login. - -Now, let's run `sudo nixos-rebuild switch` to deploy the modified configuration, and then we can login to the system using ssh with the ssh keys we configured. - -Any reproducible changes to the system can be made by modifying `/etc/nixos/configuration.nix` and deploying the changes by running `sudo nixos-rebuild switch`. - -All configuration options in `/etc/nixos/configuration.nix` can be found in the following places: - -- By searching on Google, such as `Chrome NixOS`, which will provide NixOS informations related to Chrome. Generally, the NixOS Wiki and the source code of Nixpkgs will be among the top results. -- By searching for keywords in [NixOS Options Search](https://search.nixos.org/options). -- For system-level configuration, relevant documentation can be found in [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration). -- By searching for keywords directly in the source code of [nixpkgs](https://github.com/NixOS/nixpkgs) on GitHub. - -### 2. Enabling NixOS Flakes Support - -Compared to the default configuration approach of NixOS, Flakes provide better reproducibility and a clearer package structure that is easier to maintain. Therefore, it is recommended to manage NixOS with Flakes. - -However, as Flakes is still an experimental feature currently, it's not enabled by default yet, we need to enable it manually by modifying `/etc/nixos/configuration.nix`, example as follows: - -```nix -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running 'nixos-help'). -{ config, pkgs, ... }: - -{ - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - - # omit the previous configuration....... - - # enable Flakes and the new command line tool - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - - environment.systemPackages = with pkgs; [ - # Flakes uses git to pull dependencies from data sources, so git must be installed first - git - vim - wget - curl - - ]; - - # omit the rest of the configuration....... -} -``` - -Now run `sudo nixos-rebuild switch` to apply the changes, and then you can write the configuration for NixOS with Flakes. - -### 3. Switching System Configuration to `flake.nix` - -After enabling `flakes`, `sudo nixos-rebuild switch` will try to read`/etc/nixos/flake.nix` first every time you run it, if not found, it will fallback to `/etc/nixos/configuration.nix`. - -Now to learn how to write a flake, let's take a look at the official flake templates provided by Nix. First, check which templates are available: - -```bash -nix flake show templates -``` - -The templates `templates#full` contains all possible usecases, let's take a look at it: - -```bash -nix flake init -t templates#full -cat flake.nix -``` - -After reading this example, let's create a file `/etc/nixos/flake.nix` and copy the content of the example into it. -With `/etc/nixos/flake.nix`, all system modifications will be taken over by Flakes from now on. - -The template we copied CAN NOT be used directly, we need to modify it to make it work, an example of `/etc/nixos/flake.nix` is as follows: - -```nix -{ - description = "Ryan's NixOS Flake"; - - # This is the standard format for flake.nix. `inputs` are the dependencies of the flake, - # and `outputs` function will return all the build results of the flake. - # Each item in `inputs` will be passed as a parameter to the `outputs` function after being pulled and built. - inputs = { - # There are many ways to reference flake inputs. The most widely used is github:owner/name/reference, - # 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 = { - url = "github:nix-community/home-manager/release-22.11"; - # The `follows` keyword in inputs is used for inheritance. - # Here, `inputs.nixpkgs` of home-manager is kept consistent with the `inputs.nixpkgs` of the current flake, - # to avoid problems caused by different versions of nixpkgs. - inputs.nixpkgs.follows = "nixpkgs"; - }; - }; - - # `outputs` are all the build result of the flake. - # A flake can have many use cases and different types of outputs. - # parameters in `outputs` are defined in `inputs` and can be referenced by their names. - # However, `self` is an exception, This special parameter points to the `outputs` itself (self-reference) - # The `@` syntax here is used to alias the attribute set of the inputs's parameter, making it convenient to use inside the function. - outputs = { self, nixpkgs, ... }@inputs: { - nixosConfigurations = { - # By default, NixOS will try to refer the nixosConfiguration with its hostname. - # so the system named `nixos-test` will use this configuration. - # However, the configuration name can also be specified using `sudo nixos-rebuild switch --flake /path/to/flakes/directory#`. - # The `nixpkgs.lib.nixosSystem` function is used to build this configuration, the following attribute set is its parameter. - # Run `sudo nixos-rebuild switch --flake .#nixos-test` in the flake's directory to deploy this configuration on any NixOS system - "nixos-test" = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - - # The Nix module system can modularize configuration, improving the maintainability of configuration. - # - # Each parameter in the `modules` is a Nix Module, and there is a partial introduction to it in the nixpkgs manual: - # - # It is said to be partial because the documentation is not complete, only some simple introductions - # (such is the current state of Nix documentation...) - # A Nix Module can be an attribute set, or a function that returns an attribute set. - # If a Module is a function, this function can only have the following parameters: - # - # lib: the nixpkgs function library, which provides many useful functions for operating Nix expressions - # https://nixos.org/manual/nixpkgs/stable/#id-1.4 - # config: all config options of the current flake - # options: all options defined in all NixOS Modules in the current flake - # pkgs: a collection of all packages defined in nixpkgs. - # 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 builtin modules folder, - # used to import some extra modules from nixpkgs. - # this parameter is rarely used, you can ignore it for now. - # - # Only these parameters can be passed by default. - # If you need to pass other parameters, you must use `specialArgs` by uncomment the following line - # specialArgs = {...} # pass custom arguments into sub module. - modules = [ - # Import the configuration.nix we used before, so that the old configuration file can still take effect. - # Note: /etc/nixos/configuration.nix itself is also a Nix Module, so you can import it directly here - ./configuration.nix - ]; - }; - }; - }; -} -``` - -Here we defined a NixOS system called `nixos-test`, whose configuration file is `./configuration.nix`, which is the classic configuration we modified before, so we can still make use of it. - -Now run `sudo nixos-rebuild switch` to apply the configuration, and 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. - -### 4. Manage system software through Flakes - -After the switch, we can now manage the system through Flakes. The most common requirement for managing a system is to install softwares. We have seen how to install packages through `environment.systemPackages` before, and these packages are all from the official nixpkgs repository. - -Now let's learn how to install packages from other sources through Flakes. This is much more flexible than installing from nixpkgs directly. The most obvious benefit is that you can easily set the version of the software. - -Use [helix](https://github.com/helix-editor/helix) editor as an example, first we need to add the helix as an input into `flake.nix`: - -```nix -{ - description = "NixOS configuration of Ryan Yin"; - - # ...... - - inputs = { - # ...... - - # helix editor, use the tag 23.05 - helix.url = "github:helix-editor/helix/23.05"; - }; - - outputs = inputs@{ self, nixpkgs, ... }: { - nixosConfigurations = { - nixos-test = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - - # set all inputs parameters as specialArgs of all sub module - # so that we can use `helix` input in sub modules - specialArgs = inputs; - modules = [ - ./configuration.nix - ]; - }; - }; - }; -} -``` - -Then udpate `configuration.nix` to install `helix` from the input `helix`: - -```nix -# Nix will automatically inject `helix` from specialArgs -# into the third parameter of this function through name matching -{ config, pkgs, helix, ... }: - -{ - # omit other configuration...... - - environment.systemPackages = with pkgs; [ - git - vim - wget - curl - - # install helix from the input `helix` - helix.packages."${pkgs.system}".helix - ]; - - # omit other configuration...... -} -``` - -Now deploy the changes by `sudo nixos-rebuild switch`, and then we can start the helix editor by `helix` command. - -### 5. Add Custom Cache Mirror - -> You can skip this section if you don't need to customize the cache mirror. - -To speed up package building, Nix provides to cache build results to avoid build every packages locally. - -With the NixOS's classic configuration method, other cache sources can be added by using `nix-channel`, but Flakes avoids using any system-level configuration and environment variables to ensure that its build results are not affected by the environment(so the build results are reproducible). - -Therefore, to customize the cache source, we must add the related configuration in `flake.nix` by using the parameter `nixConfig`. An example is as follows: - -```nix -{ - description = "NixOS configuration of Ryan Yin"; - - # 1. To ensure purity, Flakes does not rely on the system's `/etc/nix/nix.conf`, so we have to set related configuration here. - # 2. To ensure security, flake allows only a few nixConfig parameters to be set directly by default. - # you need to add `--accept-flake-config` when executing the nix command, - # otherwise all other parameters will be ignored, and an warning will printed by nix. - nixConfig = { - experimental-features = [ "nix-command" "flakes" ]; - substituters = [ - # replace official cache with a mirror located in China - "https://mirrors.bfsu.edu.cn/nix-channels/store" - "https://cache.nixos.org/" - ]; - - extra-substituters = [ - # nix community's cache server - "https://nix-community.cachix.org" - ]; - extra-trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - ]; - }; - - inputs = { - # omit some configuration... - }; - - outputs = { - # omit some configuration... - }; -} - -``` - -After the modification, run `sudo nixos-rebuild switch` to apply the updates. - -### 6. Install home-manager - -As I mentioned earlier, NixOS can only manage system-level configuration, to manage the Home directory(user-level configuration), we need to install home-manager. - -According to the official document [Home Manager Manual](https://nix-community.github.io/home-manager/index.htm), in order to install home-manager as a module of NixOS, we need to create `/etc/nixos/home.nix` first, an example content shown below: - -```nix -{ config, pkgs, ... }: - -{ - # TODO please change the username & home direcotry to your own - home.username = "ryan"; - home.homeDirectory = "/home/ryan"; - - # link the configuration file in current directory to the specified location in home directory - # home.file.".config/i3/wallpaper.jpg".source = ./wallpaper.jpg; - - # link all files in `./scripts` to `~/.config/i3/scripts` - # home.file.".config/i3/scripts" = { - # source = ./scripts; - # recursive = true; # link recursively - # executable = true; # make all files executable - # }; - - # encode the file content in nix configuration file directly - # home.file.".xxx".text = '' - # xxx - # ''; - - # set cursor size and dpi for 4k monitor - xresources.properties = { - "Xcursor.size" = 16; - "Xft.dpi" = 172; - }; - - # basic configuration of git, please change to your own - programs.git = { - enable = true; - userName = "Ryan Yin"; - userEmail = "xiaoyin_c@qq.com"; - }; - - # Packages that should be installed to the user profile. - home.packages = [ - # here is some command line tools I use frequently - # feel free to add your own or remove some of them - - neofetch - nnn # terminal file manager - - # archives - zip - xz - unzip - p7zip - - # utils - ripgrep # recursively searches directories for a regex pattern - jq # A lightweight and flexible command-line JSON processor - yq-go # yaml processer https://github.com/mikefarah/yq - exa # A modern replacement for ‘ls’ - fzf # A command-line fuzzy finder - - # networking tools - mtr # A network diagnostic tool - iperf3 - dnsutils # `dig` + `nslookup` - ldns # replacement of `dig`, it provide the command `drill` - aria2 # A lightweight multi-protocol & multi-source command-line download utility - socat # replacement of openbsd-netcat - nmap # A utility for network discovery and security auditing - ipcalc # it is a calculator for the IPv4/v6 addresses - - # misc - cowsay - file - which - tree - gnused - gnutar - gawk - zstd - gnupg - - # nix related - # - # it provides the command `nom` works just like `nix - # with more details log output - nix-output-monitor - - # productivity - hugo # static site generator - glow # markdown previewer in terminal - - btop # replacement of htop/nmon - iotop # io monitoring - iftop # network monitoring - - # system call monitoring - strace # system call monitoring - ltrace # library call monitoring - lsof # list open files - - # system tools - sysstat - lm_sensors # for `sensors` command - ethtool - pciutils # lspci - usbutils # lsusb - ]; - - # starship - an customizable prompt for any shell - programs.starship = { - enable = true; - settings = { - add_newline = false; - aws.disabled = true; - gcloud.disabled = true; - line_break.disabled = true; - }; - }; - - # alacritty - a cross-platform, GPU-accelerated terminal emulator - programs.alacritty = { - enable = true; - env.TERM = "xterm-256color"; - font = { - size = 12; - draw_bold_text_with_bright_colors = true; - }; - scrolling.multiplier = 5; - selection.save_to_clipboard = true; - }; - - programs.bash = { - enable = true; - enableCompletion = true; - bashrcExtra = '' - export PATH="$PATH:$HOME/bin:$HOME/.local/bin:$HOME/go/bin" - ''; - - # set some aliases, feel free to add more or remove some - shellAliases = { - urldecode = "python3 -c 'import sys, urllib.parse as ul; print(ul.unquote_plus(sys.stdin.read()))'"; - urlencode = "python3 -c 'import sys, urllib.parse as ul; print(ul.quote_plus(sys.stdin.read()))'"; - httpproxy = "export https_proxy=http://127.0.0.1:7890; export http_proxy=http://127.0.0.1:7890;"; - }; - }; - - # This value determines the home Manager release that your - # configuration is compatible with. This helps avoid breakage - # when a new home Manager release introduces backwards - # incompatible changes. - # - # You can update home Manager without changing this value. See - # the home Manager release notes for a list of state version - # changes in each release. - home.stateVersion = "22.11"; - - # Let home Manager install and manage itself. - programs.home-manager.enable = true; -} -``` - -After adding `/etc/nixos/home.nix`, you need to import this new configuration file in `/etc/nixos/flake.nix` to make use of it, use the following command to generate an example in the current folder for reference: - -```shell -nix flake new example -t github:nix-community/home-manager#nixos -``` - -After adjusting the parameters, the content of `/etc/nixos/flake.nix` is as follows: - -```nix -{ - description = "NixOS configuration"; - - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - home-manager.url = "github:nix-community/home-manager"; - home-manager.inputs.nixpkgs.follows = "nixpkgs"; - }; - - outputs = inputs@{ nixpkgs, home-manager, ... }: { - nixosConfigurations = { - # TODO please change the hostname to your own - nixos-test = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - ./configuration.nix - - # make home-manager as a module of nixos - # so that home-manager configuration will be deployed automatically when executing `nixos-rebuild switch` - home-manager.nixosModules.home-manager - { - home-manager.useGlobalPkgs = true; - home-manager.useUserPackages = true; - - # TODO replace ryan with your own username - home-manager.users.ryan = import ./home.nix; - - # Optionally, use home-manager.extraSpecialArgs to pass arguments to home.nix - } - ]; - }; - }; - }; -} -``` - -Then run `sudo nixos-rebuild switch` to apply the configuration, and home-manager will be installed automatically. - -After the installation, all user-level packages and configuration can be managed through `/etc/nixos/home.nix`. When running `sudo nixos-rebuild switch`, the configuration of home-manager will be applied automatically. (**It's not necessary to run `home-manager switch` manually**!) - -To find the options we can use in `home.nix`, referring to the following documents: - -- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.html): A list of all options, it is recommended to search for keywords in it. -- [home-manager](https://github.com/nix-community/home-manager): Some options are not listed in the official documentation, or the documentation is not clear enough, you can directly search and read the corresponding source code in this home-manager repo. - -### 7. Modular NixOS configuration - -At this point, the skeleton of the entire system is basically configured. The current configuration structure in `/etc/nixos` should be as follows: - -``` -$ tree -. -├── flake.lock -├── flake.nix -├── home.nix -└── configuration.nix -``` - -The functions of these four files are explained below: - -- `flake.lock`: An automatically generated version-lock file, which records all input sources, hash values, and version numbers of the entire flake to ensure that the system is reproducible. -- `flake.nix`: The entry file, which will be recognized and deployed when executing `sudo nixos-rebuild switch`. - - See [Flakes - NixOS Wiki](https://nixos.wiki/wiki/Flakes) for all options of flake.nix. -- `configuration.nix`: Imported as a nix module in flake.nix, all system-level configuration are currently written here. - - See [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) for all options of configuration.nix. -- `home.nix`: Imported by home-manager as the configuration of the user `ryan` in flake.nix, that is, it contains all the configuration of `ryan`, and is responsible for managing `ryan`'s home folder. - - See [Appendix A. Configuration Options - home Manager](https://nix-community.github.io/home-manager/options.html) for all options of home.nix. - -By modifying these files, you can change the status of the system and the home directory declaratively. - -As the configuration increases, it will be difficult to maintain the configuration by relying solely on `configuration.nix` and `home.nix`. Therefore, a better solution is to use the nix module system to split the configuration into multiple modules and write them in a classified manner. - -nix module system provide a paramter, `imports`, which accept a list of `.nix` files, and merge all the configuration defined in these files into the current nix module. Note that the word used here is "**merge**", which means that `imports` will **NOT** simply overwrite the duplicate configuration, but handle them more reasonably. For example, if I define `program.packages = [...]` in multiple modules, then `imports` will merge all `program.packages` defined in all nix modules into one list. Not only lists can be merged correctly, but attribute sets can also be merged correctly. The specific behavior can be explored by yourself. - -> I only found a description of `imports` in [nixpkgs-unstable official manual - evalModules parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters): `A list of modules. These are merged together to form the final configuration.`, it's a bit ambiguous... - -With the help of `imports`, we can split `home.nix` and `configuration.nix` into multiple nix modules defined in diffrent `.nix` files. - -Use [ryan4yin/nix-config/v0.0.2](https://github.com/ryan4yin/nix-config/tree/v0.0.2) as an example, which is the configuration of my previous NixOS system with i3 window manager. The structure of it is as follows: - -```shell -├── flake.lock -├── flake.nix -├── home -│ ├── default.nix # here we import all submodules by imports = [...] -│ ├── fcitx5 # fcitx5 input method's configuration -│ │ ├── default.nix -│ │ └── rime-data-flypy -│ ├── i3 # i3 window manager's configuration -│ │ ├── config -│ │ ├── default.nix -│ │ ├── i3blocks.conf -│ │ ├── keybindings -│ │ └── scripts -│ ├── programs -│ │ ├── browsers.nix -│ │ ├── common.nix -│ │ ├── default.nix # here we import all modules in programs folder by imports = [...] -│ │ ├── git.nix -│ │ ├── media.nix -│ │ ├── vscode.nix -│ │ └── xdg.nix -│ ├── rofi # rofi launcher's configuration -│ │ ├── configs -│ │ │ ├── arc_dark_colors.rasi -│ │ │ ├── arc_dark_transparent_colors.rasi -│ │ │ ├── power-profiles.rasi -│ │ │ ├── powermenu.rasi -│ │ │ ├── rofidmenu.rasi -│ │ │ └── rofikeyhint.rasi -│ │ └── default.nix -│ └── shell # shell/terminal related configuration -│ ├── common.nix -│ ├── default.nix -│ ├── nushell -│ │ ├── config.nu -│ │ ├── default.nix -│ │ └── env.nu -│ ├── starship.nix -│ └── terminals.nix -├── hosts -│ ├── msi-rtx4090 # My main machine's configuration -│ │ ├── default.nix # This is the old configuration.nix, but most of the content has been split out to modules. -│ │ └── hardware-configuration.nix # hardware & disk related configuration, autogenerated by nixos -│ └── nixos-test # my test machine's configuration -│ ├── default.nix -│ └── hardware-configuration.nix -├── modules # some common NixOS modules that can be reused -│ ├── i3.nix -│ └── system.nix -└── wallpaper.jpg # wallpaper -``` - -For more details, see [ryan4yin/nix-config/v0.0.2](https://github.com/ryan4yin/nix-config/tree/v0.0.2). - -#### 7.1. `mkOverride`, `lib.mkDefault` and `lib.mkForce` - -You may found some people use `lib.mkDefault` `lib.mkForce` to define values in Nix files, as their names suggest, `lib.mkDefault` and `lib.mkForce` are used to set default values or force values of options. - -You can read the source code of `lib.mkDefault` and `lib.mkForce` to understand them by running `nix repl -f ''` and then enter `:e lib.mkDefault`(To learn the basic usage of `nix repl`, just type `:?` to see the help information). - -its source code is as follows: - -```nix - # ...... - - mkOverride = priority: content: - { _type = "override"; - inherit priority content; - }; - - mkOptionDefault = mkOverride 1500; # priority of option defaults - mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default - mkImageMediaOverride = mkOverride 60; # image media profiles can be derived by inclusion into host config, hence needing to override host config, but do allow user to mkForce - mkForce = mkOverride 50; - mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’ - - # ...... -``` - -So `lib.mkDefault` is used to set default values of options, it has a priority of 1000 internally, -and `lib.mkForce` is used to force values of options, it has a priority of 50 internally. -If you just set a value of an option directly, it will be set with a default priority of 1000(the same as `lib.mkDefault`). - -the lower the `priority`'s value is, the higher the actual priority is, so `lib.mkForce` has a higher priority than `lib.mkDefault`. -If you defined multiple values with the same priority, Nix will throw an error. - -They are useful to modularize the configuration, as you can set default values in a low-level module(base module), and force values in a high-level module. - -For example, I defined some default values in : - -```nix -{ lib, pkgs, ... }: - -{ - # ...... - - nixpkgs.config.allowUnfree = lib.mkDefault false; - - # ...... -} -``` - -And for my dekstop machine, I force the values to another value in : - -```nix -{ lib, pkgs, ... }: - -{ - # import the base module - imports = [ - ./core-server.nix - ]; - - # override the default value defined in the base module - nixpkgs.config.allowUnfree = lib.mkForce true; - - # ...... -} -``` - -#### 7.2 `lib.mkOrder`, `lib.mkBefore` and `lib.mkAfter` - -`lib.mkBefore` and `lib.mkAfter` are used to set the merge order of **list-type options**, just like `lib.mkDefault` and `lib.mkForce`, they're also useful to modularize the configuration. - -I said before that if you defined multiple values with the same **override priority**, Nix will throw an error. -But with `lib.mkOrder`, `lib.mkBefore` or `lib.mkAfter`, you can define multiple values with the same override priority, they will be merged in the order you defined. - -Let's running `nix repl -f ''` and then enter `:e lib.mkBefore` to take a look at its source code(To learn the basic usage of `nix repl`, just type `:?` to see the help information): - -```nix - # ...... - - mkOrder = priority: content: - { _type = "order"; - inherit priority content; - }; - - mkBefore = mkOrder 500; - mkAfter = mkOrder 1500; - - # The default priority for things that don't have a priority specified. - defaultPriority = 100; - - # ...... -``` - -So `lib.mkBefore` is a shortcut for `lib.mkOrder 500`, and `lib.mkAfter` is a shortcut for `lib.mkOrder 1500`. - -To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Flake project: - -```shell -# create flake.nix with the following content -› cat < :lf . -Added 9 variables. - -# check the order of systemPackages -nix-repl> outputs.nixosConfigurations.nixos-test.config.environment.systemPackages -[ «derivation /nix/store/0xvn7ssrwa0ax646gl4hwn8cpi05zl9j-git-2.40.1.drv» - «derivation /nix/store/7x8qmbvfai68sf73zq9szs5q78mc0kny-curl-8.1.1.drv» - «derivation /nix/store/bly81l03kh0dfly9ix2ysps6kyn1hrjl-nixos-container.drv» - ...... - ...... - «derivation /nix/store/qpmpvq5azka70lvamsca4g4sf55j8994-vim-9.0.1441.drv» ] -``` - -So we can see that the order of `systemPackages` is `git -> curl -> default packages -> vim`, which is the same as the order we defined in `flake.nix`. - -> Though it's useless to adjust the order of `systemPackages`, it may be helpful at some other places... - -### 8. Update the system - -With Flakes, it is also very simple to update the system. Just run the following commands in `/etc/nixos`: - -```shell -# update flake.lock -nix flake update -# apply the updates -sudo nixos-rebuild switch -``` - -Sometimes you may encounter some error of sha256 mismatch when running `nixos-rebuild switch`, which may be solved by updating `flake.lock` through `nix flake update`. - -### 9. Downgrade or upgrade some packages - -After using Flakes, most people are currently using the `nixos-unstable` branch of nixpkgs. Sometimes you will encounter some bugs, such as the [chrome/vscode crash problem](https://github.com/swaywm/sway/issues/7562) - -To resolve problems, we may need to downgrade or upgrade some packages. In Flakes, all package versions and hash values are one-to-one corresponding to the git commit of their flake input. -Therefore, to downgrade or upgrade a package, we need to lock the git commit of its flake input. - -For exmaple, let's add multiple nixpkgs, each using a different git commit or branch: - -```nix -{ - description = "NixOS configuration of Ryan Yin" - - inputs = { - # default to nixos-unstable branch - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - - # the latest stable branch of nixpkgs, used to rollback the version of some packages - # the current latest version is 22.11 - nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-22.11"; - - # we can also use git commit hash to lock the version - nixpkgs-fd40cef8d.url = "github:nixos/nixpkgs/fd40cef8d797670e203a27a91e4b8e6decf0b90c"; - outputs = inputs@{ - self, - nixpkgs, - nixpkgs-stable, - nixpkgs-fd40cef8d, - ... - }: { - nixosConfigurations = { - nixos-test = nixpkgs.lib.nixosSystem rec { - system = "x86_64-linux"; - - # The core parameter, which passes the non-default nixpkgs instances to other nix modules - specialArgs = { - # To use packages from nixpkgs-stable, we need to configure some parameters for it first - pkgs-stable = import nixpkgs-stable { - system = system; # refer the `system` parameter form outer scope recursively - # To use chrome, we need to allow the installation of non-free software - config.allowUnfree = true; - }; - pkgs-fd40cef8d = import nixpkgs-fd40cef8d { - system = system; - config.allowUnfree = true; - }; - }; - modules = [ - ./hosts/nixos-test - - # omit other configuration... - ]; - }; - }; - }; -} -``` - -And then refer the packages from `pkgs-stable` or `pkgs-fd40cef8d` in your sub module, a home manager's sub module as an example: - -```nix -{ - pkgs, - config, - # nix will search and jnject this parameter from specialArgs in flake.nix - pkgs-stable, - # pkgs-fd40cef8d, - ... -}: - -{ - # refer packages from pkgs-stable instead of pkgs - home.packages = with pkgs-stable; [ - firefox-wayland - - # chrome wayland support was broken on nixos-unstable branch, so fallback to stable branch for now - # https://github.com/swaywm/sway/issues/7562 - google-chrome - ]; - - programs.vscode = { - enable = true; - package = pkgs-stable.vscode; # refer vscode from pkgs-stable instead of pkgs - }; -} -``` - -After adjusted the configuration, deploy it with `sudo nixos-rebuild switch`, then your firefox/chrome/vscode will be downgraded to the version corresponding to `nixpkgs-stable` or `nixpkgs-fd40cef8d`. - -> according to [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347), it's not a good practice to use `import` in sub modules to customize `nixpkgs`, because each `import` will create a new instance of nixpkgs, which will increase the build time and memory usage as the configuration grows. So here we create all nixpkgs instances in `flake.nix` to avoid this problem. - -### 10. Manage the configuration with Git - -NixOS configuration is just a set of text files, it is very suitable to be managed with Git, and thus we can easily rollback to a previous version when we encounter some problems. - -However, NixOS places the configuration in `/etc/nixos` by default, which requires root permissions to modify, which is not convenient for daily use. -Luckily, Flakes can solve this problem, you can place your flake anywhere you like. - -For example, my usage is to place my flake in `~/nixos-config`, and then create a soft link in `/etc/nixos`: - -```shell -sudo mv /etc/nixos /etc/nixos.bak # backup the original configuration -sudo ln -s ~/nixos-config/ /etc/nixos - -# deploy the flake.nix located at the default location(/etc/nixos) -sudo nixos-rebuild switch -``` - -And then you can use Git to manage the configuration in `~/nixos-config`. The configuration can be used with ordinary user-level permissions, and it is not required to be owned by root. - -Another method is jsut to delete `/etc/nixos` directly, and specify the configuration file path each time you deploy it: - -```shell -sudo mv /etc/nixos /etc/nixos.bak -cd ~/nixos-config - -# `--flake .#nixos-test` means deploy the flake.nix located in the current directory, and the nixosConfiguration's name is `nixos-test` -sudo nixos-rebuild switch --flake .#nixos-test -``` - -Choose whichever you like. After that, system rollback will become very simple, just switch to the previous commit and then deploy it: - -```shell -cd ~/nixos-config -# switch to the previous commit -git checkout HEAD^1 -# deploy the flake.nix located in the current directory, and the nixosConfiguration's name is `nixos-test` -sudo nixos-rebuild switch --flake .#nixos-test -``` - -More operations on Git are not described here. Generally speaking, rollback can be done directly through Git. Only when the system crashes completely, you will need to restart into bootloader and boot the system from the previous historical version. - -### 11. View and delete history data {#view-and-delete-history} - -As we mentioned before, each deployment of NixOS will generate a new version, and all versions will be added to the system boot options. In addition to restarting the computer, we can also query all available historical versions through the following command: - -```shell -nix profile history --profile /nix/var/nix/profiles/system -``` - -The command to clean up historical versions to release storage space: - -```shell -# delete all historical versions older than 7 days -sudo nix profile wipe-history --profile /nix/var/nix/profiles/system --older-than 7d - -# we need to collect garbages after wipe-history -sudo nix store gc --debug -``` - -Another command returns all packages installed in the system: - -```shell -nix-env -qa -``` diff --git a/docs/zh/advantage-tiopics/index.md b/docs/zh/advantage-tiopics/index.md new file mode 100644 index 0000000..2e0cdec --- /dev/null +++ b/docs/zh/advantage-tiopics/index.md @@ -0,0 +1,26 @@ + +## 十、进阶玩法 {#advanced-topics} + +逐渐熟悉 Nix 这一套工具链后,可以进一步读一读 Nix 的三本手册,挖掘更多的玩法: + +- [Nix Reference Manual](https://nixos.org/manual/nix/stable/package-management/profiles.html): Nix 包管理器使用手册,主要包含 Nix 包管理器的设计、命令行使用说明。 +- [nixpkgs Manual](https://nixos.org/manual/nixpkgs/unstable/): 主要介绍 Nixpkgs 的参数、Nix 包的使用、修改、打包方法。 +- [NixOS Manual](https://nixos.org/manual/nixos/unstable/): NixOS 系统使用手册,主要包含 Wayland/X11, GPU 等系统级别的配置说明。 +- [nix-pills](https://nixos.org/guides/nix-pills): Nix Pills 对如何使用 Nix 构建软件包进行了深入的阐述,写得比官方文档清晰易懂,而且也足够深入,值得一读。 + +在对 Nix Flakes 熟悉到一定程度后,你可以尝试一些 Flakes 的进阶玩法,如下是一些比较流行的社区项目,可以试用: + +- [flake-parts](https://github.com/hercules-ci/flake-parts): 通过 Module 模块系统简化配置的编写与维护。 +- [flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus):同样是用于简化 Flake 配置的第三方包,不过貌似更强大些 +- [digga][digga]: 一个大而全的 Flake 模板,揉合了各种实用 Nix 工具包的功能,不过结构比较复杂,需要一定经验才能玩得转。 +- ...... + +以及其他许多实用的社区项目可探索,我比较关注的有这几个: + +- [dev-templates](https://github.com/the-nix-way/dev-templates): 原汁原味的 devShell 模板,可以用于快速搭建开发环境。 +- [devenv](https://github.com/cachix/devenv): 开发环境管理 +- [agenix](https://github.com/ryantm/agenix): secrets 管理 +- [nixos-generator](https://github.com/nix-community/nixos-generators): 镜像生成工具,从 nixos 配置生成 iso/qcow2 等格式的镜像 +- [lanzaboote](https://github.com/nix-community/lanzaboote): 启用 secure boot +- [impermanence](https://github.com/nix-community/impermanence): 用于配置无状态系统。可用它持久化你指定的文件或文件夹,同时再将 /home 目录挂载为 tmpfs 或者每次启动时用工具擦除一遍。这样所有不受 impermanence 管理的数据都将成为临时数据,如果它们导致了任何问题,重启下系统这些数据就全部还原到初始状态了! +- [colmena](https://github.com/zhaofengli/colmena): NixOS 主机部署工具 diff --git a/docs/zh/advantage-usage/index.md b/docs/zh/advantage-usage/index.md deleted file mode 100644 index 36041d8..0000000 --- a/docs/zh/advantage-usage/index.md +++ /dev/null @@ -1,24 +0,0 @@ - -After becoming familiar with the NixOS, you can further explore Nix's three manuals and other docs to discover more ways to use it: - -- [Nix Reference Manual](https://nixos.org/manual/nix/stable/package-management/profiles.html): A guide to the Nix package manager, which mainly covers the design of the package manager and instructions for using it from the command line. -- [nixpkgs Manual](https://nixos.org/manual/nixpkgs/unstable/): A manual that introduces parameters of Nixpkgs, how to use, modify, and package Nix packages. -- [NixOS Manual](https://nixos.org/manual/nixos/unstable/): A user manual for NixOS, mainly including configuration instructions for system-level components such as Wayland/X11 and GPU. -- [nix-pills](https://nixos.org/guides/nix-pills): Nix Pills provides an in-depth explanation of how to use Nix to build software packages. It is written in a clear and understandable way and is worth reading, as it is also sufficiently in-depth. - -After becoming familiar with Flakes, you may want to try some advanced techniques. Here are some popular community projects to try: - -- [flake-parts](https://github.com/hercules-ci/flake-parts): Simplify the writing and maintenance of configuration through the Module module system. -- [flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus): A third-party package for simplifying Flake configuration, which is apparently more powerful. -- [digga][digga]: A large and comprehensive Flake template that combines the functionality of various useful Nix toolkits, but has a complex structure and requires some experience to navigate. -- etc. - -And many other useful community projects to explore, here are some of them: - -- [dev-templates](https://github.com/the-nix-way/dev-templates): Dev environments for numerous languages based on Nix flakes. -- [devenv](https://github.com/cachix/devenv): development environment management -- [agenix](https://github.com/ryantm/agenix): secrets management -- [colmena](https://github.com/zhaofengli/colmena): NixOS deployment tools -- [nixos-generator](https://github.com/nix-community/nixos-generators): generate iso/qcow2/... from nixos configuration -- [lanzaboote](https://github.com/nix-community/lanzaboote): enable secure boot for NixOS -- [impermanence](https://github.com/nix-community/impermanence): used to make NixOS stateless, to imporve the reproduciability of NixOS system. diff --git a/docs/zh/best-practices/index.md b/docs/zh/best-practices/index.md index 4a979b2..98c7580 100644 --- a/docs/zh/best-practices/index.md +++ b/docs/zh/best-practices/index.md @@ -1,39 +1,41 @@ -Nix is powerful and flexible, it provides a lot of ways to do things, making it difficult to find the most suitable way to do your job. -Here are some best practices that I've learned from the community, hope it can help you. +## 十一、最佳实践 {#best-practices} -## 1. Run downloaded binaries on NixOS +> [Tips&Tricks for NixOS Desktop - NixOS Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse] -NixOS does not follow the FHS standard, so the binaries you download from the Internet will not likely work on NixOS. But there are some ways to make it work. +Nix 非常强大且灵活,做一件事有非常多的方法,这就导致了很难找到最合适的方法来做你的工作。 +这里记录了一些我在使用 NixOS 中学习到的最佳实践,希望能帮到你。 -Here is a detailed guide which provides 10 ways to run downloaded binaries on NixOS: [Different methods to run a non-nixos executable on Nixos](https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos), I recommend you to read it. +### 1. 运行非 NixOS 的二进制文件 {#run-non-nixos-binaries} -Among these methods, I prefer creating a FHS environment to run the binary, which is very convenient and easy to use. +NixOS 不遵循 FHS 标准,因此你从网上下载的二进制程序在 NixOS 上大概率是跑不了的。 +为了在 NixOS 上跑这些非 NixOS 的二进制程序,需要做一些骚操作。有位老兄在这里总结了 10 种实现此目的的方法:[Different methods to run a non-nixos executable on Nixos](https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos),推荐一读。 -To create such an environment, add the following code to one of your nix modules: +我个人用的比较多的方法是,直接创建一个 FHS 环境来运行二进制程序,这种方法非常方便易用。 + +大概玩法是这样的,首先在你的 `environment.systemPackages` 中添加这个包: ```nix { config, pkgs, lib, ... }: { - # ......omit many configurations + # ...... environment.systemPackages = with pkgs; [ - # ......omit many packages + # ......o # create a fhs environment by command `fhs`, so we can run non-nixos packages in nixos! (pkgs.buildFHSUserEnv (base // { name = "fhs"; targetPkgs = pkgs: ( - # pkgs.buildFHSUserEnv provides only a minimal fhs environment, - # it lacks many basic packages needed by most softwares. - # so we need to add them manually. + # pkgs.buildFHSUserEnv 只提供一个最小的 FHS 环境,缺少很多常用软件所必须的基础包 + # 所以直接使用它很可能会报错 # - # pkgs.appimageTools provides basic packages needed by most softwares. + # pkgs.appimageTools 提供了大多数程序常用的基础包,所以我们可以直接用它来补充 (pkgs.appimageTools.defaultFhsEnvArgs.targetPkgs pkgs) ++ with pkgs; [ pkg-config ncurses - # feel free to add more packages here, if you need + # 如果你的 FHS 程序还有其他依赖,把它们添加在这里 ] ); profile = "export FHS=1"; @@ -42,26 +44,26 @@ To create such an environment, add the following code to one of your nix modules })) ]; - # ......omit many configurations + # ...... } ``` -after applying the updated configuration, you can run `fhs` to enter the FHS environment, and then run the binary you downloaded, e.g. +部署好上面的配置后,你就能用 `fhs` 命令进入我们定义好的 FHS 环境了,然后就可以运行你下载的二进制程序了,比如: ```shell -# Activating FHS drops me in a shell which looks like a "normal" Linux +# 进入我们定义好的 fhs 环境,它就跟其他 Linux 发行版一样了 $ fhs -# check what we have in /usr/bin +# 看看我们的 /usr/bin 里是不是多了很多东西 (fhs) $ ls /usr/bin -# try to run a non-nixos binary downloaded from the Internet +# 尝试下跑一个非 nixos 的二进制程序 (fhs) $ ./bin/code ``` -## 2. check the source code and debug with `nix repl` +### 2. 通过 `nix repl` 查看源码、调试配置 {#view-source-code-via-nix-repl} -We've used `nix repl ''` many times to check the source code in this guide, it's really a powerful tool to help us understand how things work in Nix. +前面我们已经使用 `nix repl ''` 看过很多次源码了,这是一个非常强大的工具,可以帮助我们理解 Nix 的工作原理。 -Better take a look at the help message of `nix repl`: +要学会用 `nix repl`,最好先看看它的 help 信息: ``` › nix repl -f '' @@ -92,23 +94,24 @@ The following commands are available: :te [bool] Enable, disable or toggle showing traces for errors ``` -Some expressions that I use frequently: `:lf `, `:e `. +我最常用的命令是 `:lf ` 跟 `:e `. -`:e ` is very intuitive, so I won't repeat it. let's take a look at `:lf `: +`:e ` 非常直观,所以这里不再赘述,我们来看看 `:lf `: ```nix -# cd into my nix-config repo(you should replace it with your own nix-config repo) +# 进入我的 nix 配置目录(建议替换成你自己的配置目录) › cd ~/nix-config/ -# enter nix repl +# 进入 nix repl 解释器 › nix repl Welcome to Nix 2.13.3. Type :? for help. -# load my nix flake and add it to scope +# 将我的 nix 配置作为一个 flake 加载到当前作用域中 nix-repl> :lf . Added 16 variables. -# press to see what we have in scope +# 按 看看当前作用域中有哪些变量,果然 nixosConfigurations inputs outputs 跟 packages 都在里面 +# 这意味着我们可以很方便地检查这些配置的内部状态 nix-repl> # ......omit some outputs __isInt nixosConfigurations @@ -118,8 +121,7 @@ __isString outputs __langVersion packages # ......omit some outputs - -# check what's in inputs +# 看看 inputs 里都有些啥 nix-repl> inputs. inputs.agenix inputs.nixpkgs inputs.darwin inputs.nixpkgs-darwin @@ -128,20 +130,21 @@ inputs.hyprland inputs.nixpkgs-wayland inputs.nil inputs.nixos-generators -# check what's in inputs.nil +# 看看 inputs.nil.packages 里都有些啥 nix-repl> inputs.nil.packages. inputs.nil.packages.aarch64-darwin inputs.nil.packages.aarch64-linux inputs.nil.packages.x86_64-darwin inputs.nil.packages.x86_64-linux -# check the outputs of my nix flake +# 看看 outputs 里都有些啥 nix-repl> outputs.nixosConfigurations. outputs.nixosConfigurations.ai outputs.nixosConfigurations.aquamarine outputs.nixosConfigurations.kana outputs.nixosConfigurations.ruby +# 看看 ai 的配置都有些啥 nix-repl> outputs.nixosConfigurations.ai. outputs.nixosConfigurations.ai._module outputs.nixosConfigurations.ai._type @@ -186,12 +189,12 @@ outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.sessionVariab outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.sessionVariables.TERM # ......omit other outputs -# check the value of `TERM` +# 看看 `TERM` 这个环境变量的值是啥 nix-repl> outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.sessionVariables.TERM "xterm-256color" -# check all files defined by `home.file` +# 看下我使用 `home.file` 定义的所有文件 nix-repl> outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.file. outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.file..bash_profile outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.file..bashrc @@ -207,39 +210,41 @@ outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.file..config/ #...... ``` -As you can see, we can check every attribute of my flake in the REPL after loading it, which is very convenient for debugging. +能看到,通过 `nix repl` 加载好我的 flake 配置后,就能很方便地检查所有的配置项了,这对于调试非常有用。 -## 3. Remote deployment +### 3. 远程部署 -Some tools like [NixOps](https://github.com/NixOS/nixops), [deploy-rs](https://github.com/serokell/deploy-rs), and [colmena](https://github.com/zhaofengli/colmena) can all be used to deploy NixOS configuration to remote hosts, but they are all too complicated for me, so skip them all. +社区的一些工具,比如 [NixOps](https://github.com/NixOS/nixops), [deploy-rs](https://github.com/serokell/deploy-rs), 跟 [colmena](https://github.com/zhaofengli/colmena),都可以用来部署 NixOS 配置到远程主机,但是都太复杂了,所以先全部跳过。 -`nixos-rebuild`, the tool we use to deploy NixOS configuration, also supports remote deployment through ssh protocol, which is very convenient and simple. +实际上我们前面使用了多次的 NixOS 本机部署命令 `nixos-rebuild`,这个工具也支持通过 ssh 协议进行远程部署,非常方便。 -But `nixos-rebuild` does not support deploying with password authentication, so to use it for remote deployment, we need to: +美中不足的是,`nixos-rebuild` 不支持使用密码认证进行部署,所以要想使用它进行远程部署,我们需要: -1. Configure ssh public key authentication for the remote hosts. -2. To avoid sudo password verification failures, we need to use the `root` user to deploy, or grant the user sudo permission without password verification. - 1. related issue: +1. 为远程主机配置 ssh 公钥认证。 +2. 为了避免 sudo 密码认证失败,需要使用 `root` 用户进行部署,或者给用户授予 sudo 权限不需要密码认证。 + 1. 相关 issue: -After the above configuration is completed, we can deploy the configuration to the server through the following command: +在搞定上面两点后,我们就可以使用 `nixos-rebuild` 进行远程部署了: ```bash -# 1. add the ssh key to ssh-agent first +# 1. 首先将本地的 ssh 私钥加载到 ssh-agent 中,以便后续使用 ssh-add ~/.ssh/ai-idols -# 2. deploy the configuration to the remote host, using the ssh key we added in step 1 -# and the username defaults to `$USER`, it's `ryan` in my case. +# 2. 将 NixOS 配置部署到远程主机,使用第一步添加的 ssh key 进行认证,用户名默认为 `$USER` nixos-rebuild --flake .#aquamarine --target-host 192.168.4.1 --build-host 192.168.4.1 switch --use-remote-sudo --verbose ``` -The commands above will build & deploy the configuration to aquamarine, the build process will be executed on aquamarine too, -and the `--use-remote-sudo` option indicates that we need to use sudo permission on the remote server to deploy the configuration. +上面的命令会将 NixOS 配置部署到 `aquamarine` 这台主机上,参数解释如下: -If you want to build the configuration locally and deploy it to the remote server, just replace `--build-host aquamarinr` with `--build-host localhost`. +1. `--target-host`: 设置远程主机的 ip 地址 +2. `--build-host` 指定了构建 NixOS 配置的主机,这里设置为跟 `--target-host` 相同,表示在远程主机上构建配置。 +3. `--use-remote-sudo` 表示部署需要用到远程主机的 sudo 权限,如果不设置这个参数,部署会失败。 -Instead of use ip address directly, we can also define some host aliases in `~/.ssh/config` or `/etc/ssh/ssh_config`, for example: +如果你希望在本地构建配置,然后再部署到远程主机,可以命令中的 `--build-host aquamarinr` 替换为 `--build-host localhost`。 -> ssh's config can be generated completely through Nix configuration, and this task is left to you. +另外如果你不想直接使用 ip 地址,可以在 `~/.ssh/config` 或者 `/etc/ssh/ssh_config` 中定义一些主机别名,比如: + +> 当然如下这份配置也完全可以通过 Nix 来管理,这个就留给读者自己去实现了。 ```bash › cat ~/.ssh/config @@ -263,27 +268,23 @@ Host kana Port 22 ``` -Then we can use the host alias to deploy the configuration: +这样我们就可以使用主机别名进行部署了: ```bash nixos-rebuild --flake .#aquamarine --target-host aquamarine --build-host aquamarine switch --use-remote-sudo --verbose ``` -## 4. Work with Makefile +### 4. 使用 Makefile 简化命令 -> NOTE: Makefile's target name should not be the same as one of the file or directory in the current directory, otherwise the target will not be executed! +> 注意: Makefile 的 target 名称不能与当前目录下的文件或者目录重名,否则 target 将不会被执行! -I use Makefile to manage the commands of my flake, which is very convenient. +在使用 NixOS 的过程中,我们会经常使用 `nixos-rebuild` 命令,经常需要输入一大堆参数,比较繁琐。 -For example, my Makefile looks like this: +所以我使用 Makefile 来管理我的 flake 配置相关的命令,简化使用。 + +我的 Makefile 大概内容截取如下: ```makefile -# -# NOTE: Makefile's target name should not be the same as one of the file or directory in the current directory, -# otherwise the target will not be executed! -# - - ############################################################################ # # Nix commands related to the local machine @@ -341,11 +342,5 @@ idols: aqua ruby kana idols-debug: aqua-debug ruby-debug kana-debug ``` -Save the above Makefile to the root directory of the flake, and then we can use `make deploy` to deploy the configuration to the local machine, and use `make idols` to deploy the configuration to all my remote servers. - - -## References - -- [Tips&Tricks for NixOS Desktop - NixOS Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse] - -[Tips&Tricks for NixOS Desktop - NixOS Discourse]: https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488 +将上述 Makefile 放到 NixOS 配置的根目录下,然后我们就可以使用 `make` 命令来执行相关的命令了。 +比如说我这里 `make deploy` 就是部署 NixOS 配置到本地主机,`make idols` 就是部署到我的远程主机集群。 \ No newline at end of file diff --git a/docs/zh/flakes/index.md b/docs/zh/flakes/index.md new file mode 100644 index 0000000..7aada71 --- /dev/null +++ b/docs/zh/flakes/index.md @@ -0,0 +1,151 @@ + +## 七、Nix Flakes 的使用 {#nix-flakes-usage} + +到这里我们已经写了不少 Nix Flakes 配置来管理 NixOS 系统了,这里再简单介绍下 Nix Flakes 更细节的内容,以及常用的 nix flake 命令。 + +### 1. Flake 的 inputs {#flake-inputs} + +`flake.nix` 中的 `inputs` 是一个 attribute set,用来指定当前 Flake 的依赖,inputs 有很多种类型,举例如下: + +```nix +{ + inputs = { + # 以 GitHub 仓库为数据源,指定使用 master 分支,这是最常见的 input 格式 + nixpkgs.url = "github:Mic92/nixpkgs/master"; + # Git URL,可用于任何基于 https/ssh 协议的 Git 仓库 + git-example.url = "git+https://git.somehost.tld/user/path?ref=branch&rev=fdc8ef970de2b4634e1b3dca296e1ed918459a9e"; + # 上面的例子会复制 .git 到本地, 如果数据量较大,建议使用 shallow=1 参数避免复制 .git + git-directory-example.url = "git+file:/path/to/repo?shallow=1"; + # 本地文件夹 (如果使用绝对路径,可省略掉前缀 'path:') + directory-example.url = "path:/path/to/repo"; + # 如果数据源不是一个 flake,则需要设置 flake=false + bar = { + url = "github:foo/bar/branch"; + flake = false; + }; + + sops-nix = { + url = "github:Mic92/sops-nix"; + # `follows` 是 inputs 中的继承语法 + # 这里使 sops-nix 的 `inputs.nixpkgs` 与当前 flake 的 inputs.nixpkgs 保持一致, + # 避免依赖的 nixpkgs 版本不一致导致问题 + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # 将 flake 锁定在某个 commit 上 + nix-doom-emacs = { + url = "github:vlaci/nix-doom-emacs?rev=238b18d7b2c8239f676358634bfb32693d3706f3"; + flake = false; + }; + + # 使用 `dir` 参数指定某个子目录 + nixpkgs.url = "github:foo/bar?dir=shu"; + } +} +``` + +### 2. Flake 的 outputs {#flake-outputs} + +`flake.nix` 中的 `outputs` 是一个 attribute set,是整个 Flake 的构建结果,每个 Flake 都可以有许多不同的 outputs。 + +一些特定名称的 outputs 有特殊用途,会被某些 Nix 命令识别处理,比如: + +- Nix packages: 名称为 `apps..`, `packages..` 或 `legacyPackages..` 的 outputs,都是 Nix 包,通常都是一个个应用程序。 + - 可以通过 `nix build .#name` 来构建某个 nix 包 +- Nix Helper Functions: 名称为 `lib` 的 outputs 是 Flake 函数库,可以被其他 Flake 作为 inputs 导入使用。 +- Nix development environments: 名称为 `devShells` 的 outputs 是 Nix 开发环境 + - 可以通过 `nix develop` 命令来使用该 Output 创建开发环境 +- NixOS configurations: 名称为 `nixosConfigurations.` 的 outputs,是 NixOS 的系统配置。 + - `nixos-rebuild switch .#` 可以使用该 Output 来部署 NixOS 系统 +- Nix templates: 名称为 `templates` 的 outputs 是 flake 模板 + - 可以通过执行命令 `nix flake init --template ` 使用模板初始化一个 Flake 包 +- 其他用户自定义的 outputs,可能被其他 Nix 相关的工具使用 + +NixOS Wiki 中给出的使用案例: + +```nix +{ self, ... }@inputs: +{ + # Executed by `nix flake check` + checks.""."" = derivation; + # Executed by `nix build .#` + packages.""."" = derivation; + # Executed by `nix build .` + packages."".default = derivation; + # Executed by `nix run .#` + apps.""."" = { + type = "app"; + program = ""; + }; + # Executed by `nix run . -- ` + apps."".default = { type = "app"; program = "..."; }; + + # Formatter (alejandra, nixfmt or nixpkgs-fmt) + formatter."" = derivation; + # Used for nixpkgs packages, also accessible via `nix build .#` + legacyPackages.""."" = derivation; + # Overlay, consumed by other flakes + overlays."" = final: prev: { }; + # Default overlay + overlays.default = {}; + # Nixos module, consumed by other flakes + nixosModules."" = { config }: { options = {}; config = {}; }; + # Default module + nixosModules.default = {}; + # Used with `nixos-rebuild --flake .#` + # nixosConfigurations."".config.system.build.toplevel must be a derivation + nixosConfigurations."" = {}; + # Used by `nix develop .#` + devShells.""."" = derivation; + # Used by `nix develop` + devShells."".default = derivation; + # Hydra build jobs + hydraJobs.""."" = derivation; + # Used by `nix flake init -t #` + templates."" = { + path = ""; + description = "template description goes here?"; + }; + # Used by `nix flake init -t ` + templates.default = { path = ""; description = ""; }; +} +``` + +### 3. Flake 命令行的使用 {#flake-commands-usage} + +在启用了 `nix-command` & `flakes` 功能后,我们就可以使用 Nix 提供的新一代 Nix 命令行工具 [New Nix Commands][New Nix Commands] 了,下面列举下其中常用命令的用法: + +```bash +# 解释下这条指令涉及的参数: +# `nixpkgs#ponysay` 意思是 `nixpkgs` 这个 flake 中的 `ponysay` 包。 +# `nixpkgs` 是一个 flakeregistry ida, +# nix 会从 中 +# 找到这个 id 对应的 github 仓库地址 +# 所以这个命令的意思是创建一个新环境,安装并运行 `nixpkgs` 这个 flake 提供的 `ponysay` 包。 +# 注:前面已经介绍过了,nix 包 是 flake outputs 中的一种。 +echo "Hello Nix" | nix run "nixpkgs#ponysay" + +# 这条命令和上面的命令作用是一样的,只是使用了完整的 flake URI,而不是 flakeregistry id。 +echo "Hello Nix" | nix run "github:NixOS/nixpkgs/nixos-unstable#ponysay" + +# 这条命令的作用是使用 zero-to-nix 这个 flake 中名 `devShells.example` 的 outptus 来创建一个开发环境, +# 然后在这个环境中打开一个 bash shell。 +nix develop "github:DeterminateSystems/zero-to-nix#example" + +# 除了使用远程 flake uri 之外,你也可以使用当前目录下的 flake 来创建一个开发环境。 +mkdir my-flake && cd my-flake +## 通过模板初始化一个 flake +nix flake init --template "github:DeterminateSystems/zero-to-nix#javascript-dev" +## 使用当前目录下的 flake 创建一个开发环境,并打开一个 bash shell +nix develop +# 或者如果你的 flake 有多个 devShell 输出,你可以指定使用名为 example 的那个 +nix develop .#example + +# 构建 `nixpkgs` flake 中的 `bat` 这个包 +# 并在当前目录下创建一个名为 `result` 的符号链接,链接到该构建结果文件夹。 +mkdir build-nix-package && cd build-nix-package +nix build "nixpkgs#bat" +# 构建一个本地 flake 和 nix develop 是一样的,不再赘述 +``` + +此外 [Zero to Nix - Determinate Systems][Zero to Nix - Determinate Systems] 是一份全新的 Nix & Flake 新手入门文档,写得比较浅显易懂,适合新手用来入门。 diff --git a/docs/zh/nix-flakes/adventages-and-disadvantages.md b/docs/zh/nix-flakes/adventages-and-disadvantages.md deleted file mode 100644 index 37cf4a4..0000000 --- a/docs/zh/nix-flakes/adventages-and-disadvantages.md +++ /dev/null @@ -1,28 +0,0 @@ - -### Advantages of Nix Flakes - -- **Declarative configuration, Environment as Code, can be managed with Git** - - As long as the configuration files are not lost, the system can be restored to any historical state at any time(except the state that are NOT managed by NixOS, such as docker containers, postgresql data, etc...) - - Nix Flakes lock dependences's version through a lock file named `flake.lock`, to ensure that the system is reproducible, this idea actually borrows from some package managers such as npm, cargo, etc. - - Compared with Docker, Nix Flakes provides a much stronger guarantee for the reproducibility of build results, because Dockerfile is actually an imperative configuration and there is no such thing as `flake.lock` in Docker, Docker's reproducibility relies on sharing the build result(which is MUCH MORE LARGER than Dockerfile itself) through image registry(e.g. DockerHub). -- **Highly convenient system customization capability** - - By changing a few lines of configuration, various components of NixOS can be easily customized. This is because Nix encapsulates all the underlying complex operations in nix packages and only exports concise and necessary declarative parameters. - - Moreover, this modification is very safe. An example is that one NixOS user on the V2EX forum stated that "[**on NixOS, switching between different desktop environments is very simple and clean, and it is very safe. I often switch between gnome/kde/sway.**](https://www.v2ex.com/t/938569#r_13053251)" -- **Rollback**: The system can be rolled back to any historical environment at any time, and NixOS even adds all old versions to the boot options by default to ensure that the system can be rolled back at any time even though it crashes. Therefore, NixOS is also considered one of the most stable Linux Systems. -- **No dependency conflicts**: Because each software package in Nix has a unique hash, its installation path also includes this hash value, so multiple versions can coexist. -- **The community is very active, and there are quite a few third-party projects**. The official package repository, nixpkgs, has many contributors, and many people share their Nix configuration on Github/Gitlab. After browsing through it, the entire ecosystem gives me a sense of excitement in discovering a new continent. - -{{< figure src="nixos-bootloader.avif" caption="All historical versions are listed in the boot options of NixOS. Image from [NixOS Discourse - 10074](https://discourse.nixos.org/t/how-to-make-uefis-grub2-menu-the-same-as-bioss-one/10074)" >}} - -### Disadvantages of Nix Flakes - -- **Relatively high learning curve:**: If you want the system to be completely reproducible and avoid pitfalls caused by improper use, you need to learn about the entire design of Nix and manage the system in a declarative manner. You cannot blindly use `nix-env -i` (which is similar to `apt-get install`). -- **Chaotic documentation**: Flakes is still an experimental feature, and there are currently few documents introducing it, Most of the Nix community's documentation only introduces the old cli such as `nix-env`/`nix-channel`. If you want to start learning Nix directly from Flakes, you need to refer to a large number of old documents and extract what you need from them. In addition, some of Nix's current core functions are not well-documented (such as `imports` and Nix Module System), to figure out what it does, it is best to look at the source code... -- ~~Relatively few packages~~: Retract this one. The official claim is that nixpkgs has [80000+](https://search.nixos.org/packages) packages, and indeed, most packages can be found in nixpkgs. -- **Relatively high disk space usage**: To ensure that the system can be rolled back at any time, Nix preserves all historical environments by default, which can take up a lot of disk space. Although you can manually clean up old historical environments periodically with `nix-collect-garbage`, it is still recommended to buy a larger hard drive. - -### Summary - -Generally speaking, I think NixOS is suitable for developers who have some experience in using Linux and programming and want to have more control over their systems. - -I don't recommend you getting started with NixOS if you are new to Linux, it can be a very painful journey. diff --git a/docs/zh/nix-flakes/index.md b/docs/zh/nix-flakes/index.md deleted file mode 100644 index 26a7f2b..0000000 --- a/docs/zh/nix-flakes/index.md +++ /dev/null @@ -1,70 +0,0 @@ - -## Warning about Flakes - -The flakes experimental feature is a major development for Nix, it introduces a policy for managing dependencies between Nix expressions, it improves reproducibility, composability and usability in the Nix ecosystem. Although it's still an experimental feature, flakes have been widely used by the Nix community.[^1] - -It's Flakes is one of the most significant changes the nix project has ever seen.[^2] - -The benefits of Flakes are obvious, and the entire NixOS community likes it very much. Currently, more than half of the users are using Flakes[^3], so we're pretty sure that Flakes will never be deprecated. - -:warning: But **Flakes is still an experimental feature**, there are still many problems with it, and it is likely to introduce some breaking changes in the process of stablizing it, and it’s uncertain how greatly the breaking changes will be. - -So overall, I still recommend everyone to use Flakes, but be prepared for the problems that may be caused by the upcomming breaking changes. - - - -## III. Nix Flakes and the classic Nix - -As `nix-command` & `flakes` are still experimental features, the official documentation does not cover them in detail, and the community's documentation about them is also very scattered. -However, from the perspective of reproducibility and ease of management and maintenance, the classic Nix package structure and cli are no longer recommended for use. -So I will not introduce the usage of the classic Nix. It's recommended that beginners just start with `nix-command` & `flakes` and ignore all the contents about the classic Nix. - -Here are the classic Nix commands and related concepts that are no longer needed after you enabling `nix-command` and `flakes`, when searching for information, you can safely ignore them: - -1. `nix-channel`: `nix-channel` is similar to other package management tools such as apt/yum/pacman, managing software package versions through stable/unstable/test channels. - 1. In Flakes, the functionality of `nix-channel` is completely replaced by `inputs` in `flake.nix`. -2. `nix-env`: `nix-env` is a core command-line tool for classic Nix used to manage software packages in the user environment. It installs packages from the data sources added by `nix-channel`, so the installed package's version are influenced by the channel. Packages installed with `nix-env` are not automatically recorded in Nix's declarative configuration and are entirely outside of its control, making them difficult to reproduce on other machines. Therefore, it is not recommended to use this tool. - 1. The corresponding command in Flakes is `nix profile`, it's not recommended to use it either. -3. `nix-shell`: `nix-shell` is used to create a temporary shell environment, which is useful for development and testing. - 1. In Flakes, it is replaced by `nix develop` and `nix shell`. -4. `nix-build`: `nix-build` is used to build Nix packages, and it places the build results in `/nix/store`, but it does not record them in Nix's declarative configuration. - 1. In Flakes, `nix-build` is replaced by `nix build`. -5. ... - -> maybe `nix-env -qa` is still useful some times, which returns all packages installed in the System. - - - -## IX. When will flakes stablized {#when-will-flakes-stablized} - -I dived into some details about flakes: - -- https://github.com/NixOS/rfcs/pull/136: A plan to stabilize Flakes and the new CLI incrementally, still WIP. -- https://discourse.nixos.org/t/why-are-flakes-still-experimental/29317: A post, Why are flakes still experimental? -- https://grahamc.com/blog/flakes-are-an-obviously-good-thing/: Flakes are such an obviously good thing... but the design and development process should be better. -- [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9): A roadmap of nixos fundation, which includes plan about the stabilization of flakes. - -After reading all of these, I feel like that flakes will eventually be stabilized in one or two years, maybe with some breaking changes. - - - -[^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes) -[^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/) -[^3]: [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9) - - - - - - - - - - - - - - - -[^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes) -[^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/) diff --git a/docs/zh/nix-flakes/introduction.md b/docs/zh/nix-flakes/introduction.md deleted file mode 100644 index 2781a71..0000000 --- a/docs/zh/nix-flakes/introduction.md +++ /dev/null @@ -1,148 +0,0 @@ - -## VII. Usage of Nix Flakes - -Up to now, we have written a lot of configuration with Flakes to manage NixOS. Here is a brief introduction to the more detailed content of the Flakes, as well as the new command lines commonly used with flakes. - -### 1. Flake inputs {#flake-inputs} - -The `inputs` in `flake.nix` is a attribute set, used to specify the dependencies of the current flake, there are many types of `inputs`, for example: - -```nix -{ - inputs = { - # use master branch of the GitHub repository as input, this is the most common input format - nixpkgs.url = "github:Mic92/nixpkgs/master"; - # Git URL, can be used for any Git repository based on https/ssh protocol - git-example.url = "git+https://git.somehost.tld/user/path?ref=branch&rev=fdc8ef970de2b4634e1b3dca296e1ed918459a9e"; - # The above example will also copy .git, use this for (shallow) local Git repos - git-directory-example.url = "git+file:/path/to/repo?shallow=1"; - # Local directories (for absolute paths you can omit 'path:') - directory-example.url = "path:/path/to/repo"; - - bar = { - url = "github:foo/bar/branch"; - # if the input is not a flake, you need to set flake=false - flake = false; - }; - - sops-nix = { - url = "github:Mic92/sops-nix"; - # The `follows` keyword in inputs is used for inheritance. - # Here, `inputs.nixpkgs` of sops-nix is kept consistent with the `inputs.nixpkgs` in - # the current flake, to avoid problems caused by different versions of nixpkgs. - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # Pin flakes to a specific revision - nix-doom-emacs = { - url = "github:vlaci/nix-doom-emacs?rev=238b18d7b2c8239f676358634bfb32693d3706f3"; - flake = false; - }; - - # To use a subdirectory of a repo, pass `dir=xxx` - nixpkgs.url = "github:foo/bar?dir=shu"; - } -} -``` - -### 2. Flake outputs - -the `outputs` in `flake.nix` are what a flake produces as part of its build. Each flake can have many different outputs simultaneously, including but not limited to: - -- Nix packages: named `apps..`, `packages..`, or `legacyPackages..` - - we can build a package by command `nix build .#` -- Nix Helper Functions: named `lib`., which means a library for other flakes. -- Nix development environments: named `devShells` - - `devShells` can be used by command `nix develop`, will be introduced later. -- NixOS configuration: named `nixosConfiguration` - - `nixosConfiguration` will be used by command `nixos-rebuild switch --flake .#` -- Nix templates: named `templates` - - templates can be used by command `nix flake init --template ` -- Other user defined outputs, may be parsed by other nix-related tools. - -An example copy from NixOS Wiki: - -```nix -{ self, ... }@inputs: -{ - # Executed by `nix flake check` - checks.""."" = derivation; - # Executed by `nix build .#` - packages.""."" = derivation; - # Executed by `nix build .` - packages."".default = derivation; - # Executed by `nix run .#` - apps.""."" = { - type = "app"; - program = ""; - }; - # Executed by `nix run . -- ` - apps."".default = { type = "app"; program = "..."; }; - - # Formatter (alejandra, nixfmt or nixpkgs-fmt) - formatter."" = derivation; - # Used for nixpkgs packages, also accessible via `nix build .#` - legacyPackages.""."" = derivation; - # Overlay, consumed by other flakes - overlays."" = final: prev: { }; - # Default overlay - overlays.default = {}; - # Nixos module, consumed by other flakes - nixosModules."" = { config }: { options = {}; config = {}; }; - # Default module - nixosModules.default = {}; - # Used with `nixos-rebuild --flake .#` - # nixosConfigurations."".config.system.build.toplevel must be a derivation - nixosConfigurations."" = {}; - # Used by `nix develop .#` - devShells.""."" = derivation; - # Used by `nix develop` - devShells."".default = derivation; - # Hydra build jobs - hydraJobs.""."" = derivation; - # Used by `nix flake init -t #` - templates."" = { - path = ""; - description = "template description goes here?"; - }; - # Used by `nix flake init -t ` - templates.default = { path = ""; description = ""; }; -} -``` - -### 3. Flake Command Line Usage - -after enabled `nix-command` & `flake`, you can use `nix help` to get all the info of [New Nix Commands][New Nix Commands], some useful examples are listed below: - -```bash -# `nixpkgs#ponysay` means `ponysay` from `nixpkgs` flake. -# [nixpkgs](https://github.com/NixOS/nixpkgs) contains `flake.nix` file, so it's a flake. -# `nixpkgs` is a falkeregistry id for `github:NixOS/nixpkgs/nixos-unstable`. -# you can find all the falkeregistry ids at -# so this command means install and run package `ponysay` in `nixpkgs` flake. -echo "Hello Nix" | nix run "nixpkgs#ponysay" - -# this command is the same as above, but use a full flake URI instead of falkeregistry id. -echo "Hello Nix" | nix run "github:NixOS/nixpkgs/nixos-unstable#ponysay" - -# instead of treat flake package as an application, -# this command use `devShells.example` in flake `zero-to-nix`'s outputs, to setup the development environment, -# and then open a bash shell in that environment. -nix develop "github:DeterminateSystems/zero-to-nix#example" - -# instead of using a remote flake, you can open a bash shell using the flake located in the current directory. -mkdir my-flake && cd my-flake -## init a flake with template -nix flake init --template "github:DeterminateSystems/zero-to-nix#javascript-dev" -# open a bash shell using the flake in current directory -nix develop -# or if your flake has multiple devShell outputs, you can specify which one to use. -nix develop .#example - -# build package `bat` from flake `nixpkgs`, and put a symlink `result` in the current directory. -mkdir build-nix-package && cd build-nix-package -nix build "nixpkgs#bat" -# build a local flake is the same as nix develop, skip it -``` - -[Zero to Nix - Determinate Systems][Zero to Nix - Determinate Systems] is a brand new guide to get started with Nix & Flake, recommended to read for beginners. diff --git a/docs/zh/nixos-with-flakes/get-started-with-flakes.md b/docs/zh/nixos-with-flakes/get-started-with-flakes.md new file mode 100644 index 0000000..7442382 --- /dev/null +++ b/docs/zh/nixos-with-flakes/get-started-with-flakes.md @@ -0,0 +1,248 @@ + +### 2. 启用 NixOS 的 Flakes 支持 {#enable-nix-flakes} + +与 NixOS 默认的配置方式相比,Nix Flakes 提供了更好的可复现性,同时它清晰的包结构定义原生支持了以其他 Git 仓库为依赖,便于代码分享,因此更建议使用 Nix Flakes 来管理系统配置。 + +但是目前 Nix Flakes 作为一个实验性的功能,仍未被默认启用。所以我们需要手动启用它,修改 `/etc/nixos/configuration.nix` 文件,在函数块中启用 flakes 与 nix-command 功能: + +```nix +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). +{ config, pkgs, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # 省略掉前面的配置...... + + # 启用 Nix Flakes 功能,以及配套的新 nix-command 命令行工具 + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + environment.systemPackages = with pkgs; [ + git # Nix Flakes 通过 git 命令从数据源拉取依赖,所以必须先安装好 git + vim + wget + curl + ]; + + # 省略其他配置...... +} +``` + +然后运行 `sudo nixos-rebuild switch` 应用修改后,即可使用 Nix Flakes 来管理系统配置。 + +额外还有个好处就是,现在你可以通过 `nix repl` 打开一个 nix 交互式环境,有兴趣的话,可以使用它复习测试一遍前面学过的所有 Nix 语法。 + +### 3. 将系统配置切换到 flake.nix {#switch-to-flake-nix} + +在启用了 Nix Flakes 特性后,`sudo nixos-rebuild switch` 命令会优先读取 `/etc/nixos/flake.nix` 文件,如果找不到再尝试使用 `/etc/nixos/configuration.nix`。 + +可以首先使用官方提供的模板来学习 flake 的编写,先查下有哪些模板: + +```bash +nix flake show templates +``` + +其中有个 `templates#full` 模板展示了所有可能的用法,可以看看它的内容: + +```bash +nix flake init -t templates#full +cat flake.nix +``` + +我们参照该模板创建文件 `/etc/nixos/flake.nix` 并编写好配置内容,后续系统的所有修改都将全部由 Nix Flakes 接管,示例内容如下: + +```nix +{ + description = "Ryan's NixOS Flake"; + + # 这是 flake.nix 的标准格式,inputs 是 flake 的依赖,outputs 是 flake 的输出 + # inputs 中的每一项依赖都会在被拉取、构建后,作为参数传递给 outputs 函数 + inputs = { + # flake inputs 有很多种引用方式,应用最广泛的是 github:owner/name/reference,即 github 仓库地址 + branch/commit-id/tag + + # NixOS 官方软件源,这里使用 nixos-unstable 分支 + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # home-manager,用于管理用户配置 + home-manager = { + url = "github:nix-community/home-manager/release-22.11"; + # `follows` 是 inputs 中的继承语法 + # 这里使 sops-nix 的 `inputs.nixpkgs` 与当前 flake 的 `inputs.nixpkgs` 保持一致, + # 避免依赖的 nixpkgs 版本不一致导致问题 + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + # outputs 即 flake 的所有输出,其中的 nixosConfigurations 即 NixOS 系统配置 + # 一个 flake 可以有很多用途,也可以有很多种不同的输出,nixosConfigurations 只是其中一种 + # + # outputs 的参数都是 inputs 中定义的依赖项,可以通过它们的名称来引用。 + # 不过 self 是个例外,这个特殊参数指向 outputs 自身(自引用),以及 flake 根目录 + # 这里的 @ 语法将函数的参数 attribute set 取了个别名,方便在内部使用 + outputs = { self, nixpkgs, ... }@inputs: { + # 名为 nixosConfigurations 的 outputs 会在执行 `sudo nixos-rebuild switch` 时被使用 + # 默认情况下上述命令会使用与主机 hostname 同名的 nixosConfigurations + # 但是也可以通过 `--flake /path/to/flake/direcotry#nixos-test` 来指定 + # 在 flakes 配置文件夹中执行 `sudo nixos-rebuild switch --flake .#nixos-test` 即可部署此配置 + # 其中 `.` 表示使用当前文件夹的 Flakes 配置,`#` 后面的内容则是 nixosConfigurations 的名称 + nixosConfigurations = { + # hostname 为 nixos-test 的主机会使用这个配置 + # 这里使用了 nixpkgs.lib.nixosSystem 函数来构建配置,后面的 attributes set 是它的参数 + # 在 nixos 系统上使用如下命令即可部署此配置:`nixos-rebuild switch --flake .#nixos-test` + "nixos-test" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + # Nix 模块系统可将配置模块化,提升配置的可维护性 + # + # modules 中每个参数,都是一个 Nix Module,nixpkgs manual 中有半份介绍它的文档: + # + # 说半份是因为它的文档不全,只有一些简单的介绍(Nix 文档现状...) + # Nix Module 可以是一个 attribute set,也可以是一个返回 attribute set 的函数 + # 如果是函数,那么它的参数就是当前的 NixOS Module 的参数. + # 根据 Nix Wiki 对 Nix modules 的描述,Nix modules 函数的参数可以有这几个: + # + # lib: nixpkgs 自带的函数库,提供了许多操作 Nix 表达式的实用函数 + # 详见 https://nixos.org/manual/nixpkgs/stable/#id-1.4 + # config: 当前 flake 的所有 config 参数的集何 + # options: 当前 flake 中所有 NixOS Modules 中定义的所有参数的集合 + # pkgs: 一个包含所有 nixpkgs 包的集合 + # 入门阶段可以认为它的默认值为 `nixpkgs.legacyPackages."${system}"` + # 可通过 `nixpkgs.pkgs` 这个 option 来自定义 pkgs 的值 + # modulesPath: 默认 nixpkgs 的内置 Modules 文件夹路径,常用于从 nixpkgs 中导入一些额外的模块 + # 这个参数通常都用不到,我只在制作 iso 镜像时用到过 + # + # 默认只能传上面这几个参数,如果需要传其他参数,必须使用 specialArgs,你可以取消注释如下这行来启用该参数 + # specialArgs = inputs # 将 inputs 中的参数传入所有子模块 + modules = [ + # 导入之前我们使用的 configuration.nix,这样旧的配置文件仍然能生效 + # 注: /etc/nixos/configuration.nix 本身也是一个 Nix Module,因此可以直接在这里导入 + ./configuration.nix + ]; + }; + }; + }; +} +``` + +这里我们定义了一个名为 `nixos-test` 的系统,它的配置文件为 `./configuration.nix`,这个文件就是我们之前的配置文件,这样我们仍然可以沿用旧的配置。 + +现在执行 `sudo nixos-rebuild switch` 应用配置,系统应该没有任何变化,因为我们仅仅是切换到了 Nix Flakes,配置内容与之前还是一致的。 + +### 4. 通过 Flakes 来管理系统软件 {#manage-system-software-with-flakes} + +切换完毕后,我们就可以通过 Flakes 来管理系统了。管系统最常见的需求就是装软件,我们在前面已经见识过如何通过 `environment.systemPackages` 来安装 `pkgs` 中的包,这些包都来自官方的 nixpkgs 仓库。 + +现在我们学习下如何通过 Flakes 安装其他来源的软件包,这比直接安装 nixpkgs 要灵活很多,最显而易见的好处是你可以很方便地设定软件的版本。 +以 [helix](https://github.com/helix-editor/helix) 编辑器为例,我们首先需要在 `flake.nix` 中添加 helix 这个 inputs 数据源: + +```nix +{ + description = "NixOS configuration of Ryan Yin"; + + # ...... + + inputs = { + # ...... + + # helix editor, use tag 23.05 + helix.url = "github:helix-editor/helix/23.05"; + }; + + outputs = inputs@{ self, nixpkgs, ... }: { + nixosConfigurations = { + nixos-test = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + # 将所有 inputs 参数设为所有子模块的特殊参数,这样就能在子模块中使用 helix 这个 inputs 了 + specialArgs = inputs; + modules = [ + ./configuration.nix + ]; + }; + }; + }; +} +``` + +接下来在 `configuration.nix` 中就能引用这个 flake input 数据源了: + +```nix +# Nix 会通过名称匹配,自动将 specialArgs 中的 helix 注入到此函数的第三个参数 +{ config, pkgs, helix, ... }: + +{ + # 省略掉前面的配置...... + + environment.systemPackages = with pkgs; [ + git # Nix Flakes 通过 git 命令从数据源拉取依赖,所以必须先安装好 git + vim + wget + curl + + # 这里从 helix 这个 inputs 数据源安装了 helix 程序 + helix.packages."${pkgs.system}".helix + ]; + + # 省略其他配置...... +} +``` + +改好后再 `sudo nixos-rebuild switch` 部署,就能安装好 helix 程序了,可直接在终端使用 `helix` 命令测试验证。 + +### 5. 为 Flake 添加国内 cache 源 {#add-cache-source-for-flake} + +Nix 为了加快包构建速度,提供了 提前缓存构建结果提供给用户,但是在国内访问这个 cache 地址非常地慢,如果没有全局代理的话,基本上是无法使用的。 +另外 Flakes 的数据源基本都是某个 Github 仓库,在国内从 Github 下载 Flakes 数据源也同样非常非常慢。 + +在旧的 NixOS 配置方式中,可以通过 `nix-channel` 命令添加国内的 cache 镜像源以提升下载速度,但是 Nix Flakes 会尽可能地避免使用任何系统级别的配置跟环境变量,以确保其构建结果不受环境的影响,因此在使用了 Flakes 后 `nix-channel` 命令就失效了。 + +为了自定义 cache 镜像源,我们必须在 `flake.nix` 中添加相关配置,这就是 `nixConfig` 参数,示例如下: + +```nix +{ + description = "NixOS configuration of Ryan Yin"; + + # 为了确保够纯,Flake 不依赖系统自身的 /etc/nix/nix.conf,而是在 flake.nix 中通过 nixConfig 设置 + # 但是为了确保安全性,flake 默认仅允许直接设置少数 nixConfig 参数,其他参数都需要在执行 nix 命令时指定 `--accept-flake-config`,否则会被忽略 + # + # 注意:即使添加了国内 cache 镜像,如果有些包国内镜像下载不到,它仍然会走国外。 + # 我的解法是使用 openwrt 旁路由 + openclash 加速下载。 + # 临时修改系统默认网关为我的旁路由 IP: + # sudo ip route add default via 192.168.5.201 + # 还原路由规则: + # sudo ip route del default via 192.168.5.201 + nixConfig = { + experimental-features = [ "nix-command" "flakes" ]; + substituters = [ + # replace official cache with a mirror located in China + "https://mirrors.bfsu.edu.cn/nix-channels/store" + "https://cache.nixos.org/" + ]; + + # nix community's cache server + extra-substituters = [ + "https://nix-community.cachix.org" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]; + }; + + inputs = { + # 省略若干配置... + }; + + outputs = { + # 省略若干配置... + }; +} + +``` + +改完后使用 `sudo nixos-rebuild switch` 应用配置即可生效,后续所有的包都会优先从国内镜像源查找缓存。 + +> 注:上述手段只能加速部分包的下载,许多 inputs 数据源仍然会从 Github 拉取,另外如果找不到缓存,会执行本地构建,这通常仍然需要从国外下载源码与构建依赖,因此仍然会很慢。为了完全解决速度问题,仍然建议使用旁路由等局域网全局代理方案。 \ No newline at end of file diff --git a/docs/zh/nixos-with-flakes/get-started-with-nixos.md b/docs/zh/nixos-with-flakes/get-started-with-nixos.md new file mode 100644 index 0000000..3ca9983 --- /dev/null +++ b/docs/zh/nixos-with-flakes/get-started-with-nixos.md @@ -0,0 +1,79 @@ + +了解了 Nix 语言的基本用法之后,我们就可以开始使用 Nix 语言来配置 NixOS 系统了。 +NixOS 的系统配置路径为 `/etc/nixos/configuration.nix`,它包含系统的所有声明式配置,如时区、语言、键盘布局、网络、用户、文件系统、启动项、桌面环境等等。 + +如果想要以可复现的方式修改系统的状态(这也是最推荐的方式),就需要手工修改 `/etc/nixos/configuration.nix` 文件,然后执行 `sudo nixos-rebuild switch` 命令来应用配置,此命令会根据配置文件生成一个新的系统环境,并将新的环境设为默认环境。 +同时上一个系统环境会被保留,而且会被加入到 grub 的启动项中,这确保了即使新的环境不能启动,也能随时回退到旧环境。 + +另一方面,`/etc/nixos/configuration.nix` 是传统的 Nix 配置方式,它依赖 `nix-channel` 配置的数据源,也没有任何版本锁定机制,实际无法确保系统的可复现性。 +**更推荐使用的是 Nix Flakes**,它可以确保系统的可复现性,同时也可以很方便地管理系统的配置。 + +我们下面首先介绍下通过 NixOS 默认的配置方式来管理系统,然后再过渡到更先进的 Nix Flakes. + +## 使用 `/etc/nixos/configuration.nix` 配置系统 {#configuration-nix} + +前面提过了这是传统的 Nix 配置方式,也是当前 NixOS 默认使用的配置方式,它依赖 `nix-channel` 配置的数据源,也没有任何版本锁定机制,实际无法确保系统的可复现性。 + +简单起见我们先使用这种方式来配置系统,后面会介绍 Flake 的使用。 + +比如要启用 ssh 并添加一个用户 ryan,只需要在 `/etc/nixos/configuration.nix` 中添加如下配置: + +```nix +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). +{ config, pkgs, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # 省略掉前面的配置...... + + # 新增用户 ryan + users.users.ryan = { + isNormalUser = true; + description = "ryan"; + extraGroups = [ "networkmanager" "wheel" ]; + openssh.authorizedKeys.keys = [ + # replace with your own public key + "ssh-ed25519 ryan@ryan-pc" + ]; + packages = with pkgs; [ + firefox + # thunderbird + ]; + }; + + # 启用 OpenSSH 后台服务 + services.openssh = { + enable = true; + permitRootLogin = "no"; # disable root login + passwordAuthentication = false; # disable password login + openFirewall = true; + forwardX11 = true; # enable X11 forwarding + }; + + # 省略其他配置...... +} +``` + +这里我启用了 openssh 服务,为 ryan 用户添加了 ssh 公钥,并禁用了密码登录。 + +现在运行 `sudo nixos-rebuild switch` 部署修改后的配置,之后就可以通过 ssh 密钥远程登录到我的这台主机了。 + +这就是 NixOS 默认的声明式系统配置,要对系统做任何可复现的变更,都只需要修改 `/etc/nixos/configuration.nix` 文件,然后运行 `sudo nixos-rebuild switch` 部署变更即可。 + +`/etc/nixos/configuration.nix` 的所有配置项,可以在这几个地方查到: + +- 直接 Google,比如 `Chrome NixOS` 就能找到 Chrome 相关的配置项,一般 NixOS Wiki 或 nixpkgs 仓库源码的排名会比较靠前。 +- 在 [NixOS Options Search](https://search.nixos.org/options) 中搜索关键字 +- 系统级别的配置,可以考虑在 [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) 找找相关文档 +- 直接在 [nixpkgs](https://github.com/NixOS/nixpkgs) 仓库中搜索关键字,读相关的源码。 + + +## 参考 + +- [Overview of the NixOS Linux distribution]( https://nixos.wiki/wiki/Overview_of_the_NixOS_Linux_distribution) diff --git a/docs/zh/nixos-with-flakes/introduction-to-flakes.md b/docs/zh/nixos-with-flakes/introduction-to-flakes.md new file mode 100644 index 0000000..2b06c49 --- /dev/null +++ b/docs/zh/nixos-with-flakes/introduction-to-flakes.md @@ -0,0 +1,51 @@ + +Flakes 实验特性是 Nix 项目的一项重大进展,它引入了一种管理 Nix 表达式之间的依赖关系的策略,提高了 Nix 生态系统中的可复现性、可组合性和可用性。 +虽然 Flakes 仍然是一个试验性的功能,但已经被 Nix 社区广泛使采用。[^1] + +Flakes 特性是 Nix 项目中最有意义的变化之一。[^2] + +## 注意事项 + +Flakes 带来的好处是显而易见的,整个 NixOS 社区都很喜欢它,目前超过半数的用户已经在大量使用 Flakes[^3],因此我们基本可以确定 Flakes 绝对不会被废弃。 + +但是 Flakes 目前仍然存在许多问题,将它推向稳定的过程中,Nix 很可能会引入一些不兼容的改动,这个改动的大小目前还无法确定。 + +因此总的来说,我仍然推荐大家使用 Flakes,这本书本身也是围绕 NixOS 与 Flakes 编写的,但是也要做好准备——未来可能需要解决一些不兼容变更带来的问题。 + +## Flakes 与传统的 Nix + +Nix 于 2020 年推出了 `nix-command` & `flakes` 两个新特性,它们提供了全新的命令行工具、标准的 Nix 包结构定义、类似 cargo/npm 的 `flake.lock` 版本锁文件等等。这两个特性极大地增强了 Nix 的能力,因此虽然至今(2023/5/5)它们仍然是实验性特性,但是已经被 Nix 社区广泛使用。 + +但由于 `nix-command` & `flakes` 仍然是实验性特性,官方文档基本不包含任何介绍它们的内容,同时社区关于 Flakes 的文档也相当分散且不完整。 +但是从可复现、易于管理维护的角度讲,旧的 Nix 包结构与命令行工具已经不推荐使用了,因此本书也不会介绍旧的 Nix 包结构与命令行工具的使用方法,也建议新手直接忽略掉这些旧的内容,从 `nix-command` & `flakes` 学起。 + +这里列举下在 `nix-command` & `flakes` 中已经不需要用到的旧的 Nix 命令行工具与相关概念,在查找资料时,如果看到它们直接忽略掉就行: + +1. `nix-channel`: 与 apt/yum/pacman 等其他 Linux 发行版的包管理工具类似,传统的 Nix 也以 stable/unstable/test 等 channel 的形式来管理软件包的版本,可通过此命令修改 Nix 的 channel 信息。 + 1. Nix Flakes 在 `flake.nix` 中通过 `inputs` 声明依赖包的数据源,通过 `flake.lock` 锁定依赖版本,完全取代掉了 `nix-channel` 的功能。 +2. `nix-env`: 用于管理用户环境的软件包,是传统 Nix 的核心命令行工具。它从 `nix-channel` 定义的数据源中安装软件包,所以安装的软件包版本受 channel 影响。 + 1. 通过 `nix-env` 安装的包不会被自动记录到 Nix 的声明式配置中,是完全脱离掌控的,无法在其他主机上复现,因此不推荐使用。 + 2. 在 Nix Flakes 中对应的命令为 `nix profile`,此命令也同样不推荐使用。 +3. `nix-shell`: nix-shell 用于创建一个临时的 shell 环境 + 1. 在 Nix Flakes 中它被 `nix develop` 与 `nix shell` 取代了。 +4. `nix-build`: 用于构建 Nix 包,它会将构建结果放到 `/nix/store` 路径下,但是不会记录到 Nix 的声明式配置中。 + 1. 在 Nix Flakes 中对应的命令为 `nix build` +5. ... + +> 可能也就 `nix-env -qa` 这个命令偶尔还会有些用了,它返回当前系统下安装的所有软件包。 + +## Flakes 何时会成为稳定特性? {#when-will-flakes-stablized} + +我深入了解了下 Flakes 现状与未来计划相关的资料,大概有这些: + +- https://github.com/NixOS/rfcs/pull/136: 一份渐进式地将 Flakes 与 new CLI 两个实验性特性推向稳定的 RFC,目前还在讨论中。 +- https://discourse.nixos.org/t/why-are-flakes-still-experimental/29317: 最近的一次关于 Flakes 稳定性的讨论,可以看到大家的疑惑,以及社区对 Flakes 的态度。 +- https://grahamc.com/blog/flakes-are-an-obviously-good-thing/: NixOS 社区成员的文章,记录了他对 Flakes 的看法,以及对社区当初添加 Flakes 特性时的不当举措的懊悔。 +- https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9: NixOS Fundation 的一份 Roadmap,其中提到了 Flakes 的计划:`Stabilize flakes and release Nix 3.0. Flakes are widely used (there are more GitHub repos being created with a flake.nix than a default.nix) but they’re still marked as experimental, which is not a good situation. The same applies to the new nix CLI.` + +读完上述内容后,个人猜测,**Flakes 可能会在未来一两年内成为稳定特性**。 + + +[^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes) +[^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/) +[^3]: [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9) diff --git a/docs/zh/nixos-with-flakes/modularize-the-configuration.md b/docs/zh/nixos-with-flakes/modularize-the-configuration.md new file mode 100644 index 0000000..35587ed --- /dev/null +++ b/docs/zh/nixos-with-flakes/modularize-the-configuration.md @@ -0,0 +1,248 @@ + +### 7. 模块化 NixOS 配置 {#modularize-nixos-configuration} + +到这里整个系统的骨架基本就配置完成了,当前我们 `/etc/nixos` 中的系统配置结构应该如下: + +``` +$ tree +. +├── flake.lock +├── flake.nix +├── home.nix +└── configuration.nix +``` + +下面分别说明下这四个文件的功能: + +- `flake.lock`: 自动生成的版本锁文件,它记录了整个 flake 所有输入的数据源、hash 值、版本号,确保系统可复现。 +- `flake.nix`: 入口文件,执行 `sudo nixos-rebuild switch` 时会识别并部署它。 +- `configuration.nix`: 在 flake.nix 中被作为系统模块导入,目前所有系统级别的配置都写在此文件中。 + - 此配置文件中的所有配置项,参见官方文档 [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) +- `home.nix`: 在 flake.nix 中被 home-manager 作为 ryan 用户的配置导入,也就是说它包含了 ryan 这个用户的所有 Home Manager 配置,负责管理其 Home 文件夹。 + - 此配置文件的所有配置项,参见 [Appendix A. Configuration Options - Home Manager](https://nix-community.github.io/home-manager/options.html) + +通过修改上面几个配置文件就可以实现对系统与 Home 目录状态的修改。 +但是随着配置的增多,单纯依靠 `configuration.nix` 跟 `home.nix` 会导致配置文件臃肿,难以维护,因此更好的解决方案是通过 Nix 的模块机制,将配置文件拆分成多个模块,分门别类地编写维护。 + +在前面的 Nix 语法一节有介绍过:「`import` 的参数如果为文件夹路径,那么会返回该文件夹下的 `default.nix` 文件的执行结果」,实际 Nix 还提供了一个 `imports` 参数,它可以接受一个 `.nix` 文件列表,并将该列表中的所有配置**合并**(Merge)到当前的 attribute set 中。注意这里的用词是「合并」,它表明 `imports` 如果遇到重复的配置项,不会简单地按执行顺序互相覆盖,而是更合理地处理。比如说我在多个 modules 中都定义了 `program.packages = [...]`,那么 `imports` 会将所有 modules 中的 `program.packages` 这个 list 合并。不仅 list 能被正确合并,attribute set 也能被正确合并,具体行为各位看官可以自行探索。 + +> 我只在 [nixpkgs-unstable 官方手册 - evalModules parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters) 中找到一句关于 `imports` 的描述:`A list of modules. These are merged together to form the final configuration.`,可以意会一下...(Nix 的文档真的一言难尽...这么核心的参数文档就这么一句...) + +我们可以借助 `imports` 参数,将 `home.nix` 与 `configuration.nix` 拆分成多个 `.nix` 文件。 + +比如我之前的 i3wm 系统配置 [ryan4yin/nix-config/v0.0.2](https://github.com/ryan4yin/nix-config/tree/v0.0.2),结构如下: + +```shell +├── flake.lock +├── flake.nix +├── home +│ ├── default.nix # 在这里通过 imports = [...] 导入所有子模块 +│ ├── fcitx5 # fcitx5 中文输入法设置,我使用了自定义的小鹤音形输入法 +│ │ ├── default.nix +│ │ └── rime-data-flypy +│ ├── i3 # i3wm 桌面配置 +│ │ ├── config +│ │ ├── default.nix +│ │ ├── i3blocks.conf +│ │ ├── keybindings +│ │ └── scripts +│ ├── programs +│ │ ├── browsers.nix +│ │ ├── common.nix +│ │ ├── default.nix # 在这里通过 imports = [...] 导入 programs 目录下的所有 nix 文件 +│ │ ├── git.nix +│ │ ├── media.nix +│ │ ├── vscode.nix +│ │ └── xdg.nix +│ ├── rofi # rofi 应用启动器配置,通过 i3wm 中配置的快捷键触发 +│ │ ├── configs +│ │ │ ├── arc_dark_colors.rasi +│ │ │ ├── arc_dark_transparent_colors.rasi +│ │ │ ├── power-profiles.rasi +│ │ │ ├── powermenu.rasi +│ │ │ ├── rofidmenu.rasi +│ │ │ └── rofikeyhint.rasi +│ │ └── default.nix +│ └── shell # shell 终端相关配置 +│ ├── common.nix +│ ├── default.nix +│ ├── nushell +│ │ ├── config.nu +│ │ ├── default.nix +│ │ └── env.nu +│ ├── starship.nix +│ └── terminals.nix +├── hosts +│ ├── msi-rtx4090 # PC 主机的配置 +│ │ ├── default.nix # 这就是之前的 configuration.nix,不过大部分内容都拆出到 modules 了 +│ │ └── hardware-configuration.nix # 与系统硬件相关的配置,安装 nixos 时自动生成的 +│ └── nixos-test # 测试用的虚拟机配置 +│ ├── default.nix +│ └── hardware-configuration.nix +├── modules # 从 configuration.nix 中拆分出的一些通用配置 +│ ├── i3.nix +│ └── system.nix +└── wallpaper.jpg # 桌面壁纸,在 i3wm 配置中被引用 +``` + +详细结构与内容,请移步前面提供的 github 仓库链接,这里就不多介绍了。 + +#### 7.1. `mkOverride`, `lib.mkDefault` and `lib.mkForce` + +你可能会发现有些人在 Nix 文件中使用 `lib.mkDefault` `lib.mkForce` 来定义值,顾名思义,`lib.mkDefault` 和 `lib.mkForce` 用于设置选项的默认值,或者强制设置选项的值。 + +直接这么说可能不太好理解,官方文档也没啥对这几个函数的详细解释,最直接的理解方法,是看源码。 + +开个新窗口,输入命令 `nix repl -f ''` 进入 REPL 解释器,然后输入 `:e lib.mkDefault`,就可以看到 `lib.mkDefault` 的源码了(不太懂 `:e` 是干啥的?请直接输入 `:?` 查看帮助信息学习下)。 + +源码截取如下: + +```nix + # ...... + + mkOverride = priority: content: + { _type = "override"; + inherit priority content; + }; + + mkOptionDefault = mkOverride 1500; # priority of option defaults + mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default + mkImageMediaOverride = mkOverride 60; # image media profiles can be derived by inclusion into host config, hence needing to override host config, but do allow user to mkForce + mkForce = mkOverride 50; + mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’ + + # ...... +``` + +所以 `lib.mkDefault` 就是用于设置选项的默认值,它的优先级是 1000,而 `lib.mkForce` 则用于强制设置选项的值,它的优先级是 50。 +如果你直接设置选项的值,那么它的优先级就是 1000(和 `lib.mkDefault` 一样)。 + +`priority` 的值越低,它实际的优先级就越高,所以 `lib.mkForce` 的优先级比 `lib.mkDefault` 高。 +而如果你定义了多个优先级相同的值,Nix 会报错说存在参数冲突,需要你手动解决。 + +这几个函数在模块化 NixOS 配置中非常有用,因为你可以在低层级的模块(base module)中设置默认值,然后在高层级的模块(high-level module)中设置优先级更高的值。 + +举个例子,我在这里定义了一个默认值: + +```nix +{ lib, pkgs, ... }: + +{ + # ...... + + nixpkgs.config.allowUnfree = lib.mkDefault false; + + # ...... +} +``` + +然后在桌面机器的配置中,我强制覆盖了默认值: + +```nix +{ lib, pkgs, ... }: + +{ + # 导入 base module + imports = [ + ./core-server.nix + ]; + + # 覆盖 base module 中定义的默认值 + nixpkgs.config.allowUnfree = lib.mkForce true; + + # ...... +} +``` + +#### 7.2 `lib.mkOrder`, `lib.mkBefore` 与 `lib.mkAfter` + +`lib.mkBefore` 跟 `lib.mkAfter` 用于设置**列表类型**的合并顺序,它们跟 `lib.mkDefault` 和 `lib.mkForce` 一样,也被用于模块化配置。 + +前面说了如果你定义了多个优先级相同的值,Nix 会报错说存在参数冲突,需要你手动解决。 + +但是如果你定义的是**列表类型**的值,Nix 就不会报错了,因为 Nix 会把你定义的多个值合并成一个列表,而 `lib.mkBefore` 跟 `lib.mkAfter` 就是用于设置这个列表的合并顺序的。 + +还是先来看看源码,开个终端键入 `nix repl -f ''` 进入 REPL 解释器,然后输入 `:e lib.mkBefore`,就可以看到 `lib.mkBefore` 的源码了(不太懂 `:e` 是干啥的?请直接输入 `:?` 查看帮助信息学习下)。 + +```nix + # ...... + + mkOrder = priority: content: + { _type = "order"; + inherit priority content; + }; + + mkBefore = mkOrder 500; + mkAfter = mkOrder 1500; + + # The default priority for things that don't have a priority specified. + defaultPriority = 100; + + # ...... +``` + +能看到 `lib.mkBefore` 只是个 `lib.mkOrder 500` 的别名,而 `lib.mkAfter` 则是个 `lib.mkOrder 1500` 的别名。 + +为了更直观地理解这两个函数,现在来创建一个 flake 测试下: + +```shell +# 使用如下内容创建一个 flake.nix 文件 +› cat < :lf . +Added 9 variables. + +# 检查下 systemPackages 的顺序,看看跟我们预期的是否一致 +nix-repl> outputs.nixosConfigurations.nixos-test.config.environment.systemPackages +[ «derivation /nix/store/0xvn7ssrwa0ax646gl4hwn8cpi05zl9j-git-2.40.1.drv» + «derivation /nix/store/7x8qmbvfai68sf73zq9szs5q78mc0kny-curl-8.1.1.drv» + «derivation /nix/store/bly81l03kh0dfly9ix2ysps6kyn1hrjl-nixos-container.drv» + ...... + ...... + «derivation /nix/store/qpmpvq5azka70lvamsca4g4sf55j8994-vim-9.0.1441.drv» ] +``` + +能看到 `systemPackages` 的顺序是 `git -> curl -> default packages -> vim`,跟我们预期的一致。`lib.mkBefore [pkgs.git]` 确实是将 `git` 插入到了列表头,而 `lib.mkAfter [pkgs.vim]` 则是将 `vim` 插入到了列表尾。 + +> 虽然单纯调整 `systemPackages` 的顺序没什么用,但是在其他地方可能会有用... diff --git a/docs/zh/nixos-with-flakes/other-useful-tips.md b/docs/zh/nixos-with-flakes/other-useful-tips.md new file mode 100644 index 0000000..649ec7c --- /dev/null +++ b/docs/zh/nixos-with-flakes/other-useful-tips.md @@ -0,0 +1,62 @@ + +### 10. 使用 Git 管理 NixOS 配置 {#git-manage-nixos-config} + +NixOS 的配置文件是纯文本,因此跟普通的 dotfiles 一样可以使用 Git 管理。 + +此外 Nix Flakes 配置也不一定需要放在 `/etc/nixos` 目录下,可以放在任意目录下,只要在部署时指定正确的路径即可。 + +> 我们在前面第 3 小节的代码注释中有说明过,可以通过 `sudo nixos-rebuild switch --flake .#xxx` 的 `--flake` 参数指定 Flakes 配置的文件夹路径,并通过 `#` 后面的值来指定使用的 outputs 名称。 + +比如我的使用方式是将 Nix Flakes 配置放在 `~/nixos-config` 目录下,然后在 `/etc/nixos` 目录下创建一个软链接: + +```shell +sudo mv /etc/nixos /etc/nixos.bak # 备份原来的配置 +sudo ln -s ~/nixos-config/ /etc/nixos +``` + +然后就可以在 `~/nixos-config` 目录下使用 Git 管理配置了,配置使用普通的用户级别权限即可,不要求 owner 为 root. + +另一种方法是直接删除掉 `/etc/nixos`,并在每次部署时指定配置文件路径: + +```shell +sudo mv /etc/nixos /etc/nixos.bak # 备份原来的配置 +cd ~/nixos-config + +# 通过 --flake .#nixos-test 参数,指定使用当前文件夹的 flake.nix,使用的 nixosConfiguraitons 名称为 nixos-test +sudo nixos-rebuild switch --flake .#nixos-test +``` + +两种方式都可以,看个人喜好。搞定之后,系统的回滚也变得非常简单,只需要切换到上一个 commit 即可: + +```shell +cd ~/nixos-config +# 回滚到上一个 commit +git checkout HEAD^1 +# 部署 +sudo nixos-rebuild switch --flake .#nixos-test +``` + +Git 的更多操作这里就不介绍了,总之一般情况下的回滚都能直接通过 Git 完成,只在系统完全崩溃的情况下,才需要通过重启进入 grub,从上一个历史版本启动系统。 + +### 11. 查看与清理历史数据 {#view-and-delete-history} + +如前所述,NixOS 的每次部署都会生成一个新的版本,所有版本都会被添加到系统启动项中,除了重启电脑外,我们也可以通过如下命令查询当前可用的所有历史版本: + +```shell +nix profile history --profile /nix/var/nix/profiles/system +``` + +以及清理历史版本释放存储空间的命令: + +```shell +# 清理 7 天之前的所有历史版本 +sudo nix profile wipe-history --profile /nix/var/nix/profiles/system --older-than 7d +# 清理历史版本并不会删除数据,还需要手动 gc 下 +sudo nix store gc --debug +``` + +以及查看系统层面安装的所有软件包(这个貌似只能用 `nix-env`): + +```shell +nix-env -qa +``` diff --git a/docs/zh/nixos-with-flakes/start-using-home-manager.md b/docs/zh/nixos-with-flakes/start-using-home-manager.md new file mode 100644 index 0000000..e165def --- /dev/null +++ b/docs/zh/nixos-with-flakes/start-using-home-manager.md @@ -0,0 +1,219 @@ + +前面简单提过,NixOS 自身的配置文件只能管理系统级别的配置,而用户级别的配置则需要使用 home-manager 来管理。 + +根据官方文档 [Home Manager Manual](https://nix-community.github.io/home-manager/index.htm),要将 home manager 作为 NixOS 模块安装,首先需要创建 `/etc/nixos/home.nix`,配置方法如下: + +```nix +{ config, pkgs, ... }: + +{ + # 注意修改这里的用户名与用户目录 + home.username = "ryan"; + home.homeDirectory = "/home/ryan"; + + # 直接将当前文件夹的配置文件,链接到 Home 目录下的指定位置 + # home.file.".config/i3/wallpaper.jpg".source = ./wallpaper.jpg; + + # 递归将某个文件夹中的文件,链接到 Home 目录下的指定位置 + # home.file.".config/i3/scripts" = { + # source = ./scripts; + # recursive = true; # 递归整个文件夹 + # executable = true; # 将其中所有文件添加「执行」权限 + # }; + + # 直接以 text 的方式,在 nix 配置文件中硬编码文件内容 + # home.file.".xxx".text = '' + # xxx + # ''; + + # 设置鼠标指针大小以及字体 DPI(适用于 4K 显示器) + xresources.properties = { + "Xcursor.size" = 16; + "Xft.dpi" = 172; + }; + + # git 相关配置 + programs.git = { + enable = true; + userName = "Ryan Yin"; + userEmail = "xiaoyin_c@qq.com"; + }; + + # 通过 home.packages 安装一些常用的软件 + # 这些软件将仅在当前用户下可用,不会影响系统级别的配置 + # 建议将所有 GUI 软件,以及与 OS 关系不大的 CLI 软件,都通过 home.packages 安装 + home.packages = with pkgs;[ + # 如下是我常用的一些命令行工具,你可以根据自己的需要进行增删 + neofetch + nnn # terminal file manager + + # archives + zip + xz + unzip + p7zip + + # utils + ripgrep # recursively searches directories for a regex pattern + jq # A lightweight and flexible command-line JSON processor + yq-go # yaml processer https://github.com/mikefarah/yq + exa # A modern replacement for ‘ls’ + fzf # A command-line fuzzy finder + + # networking tools + mtr # A network diagnostic tool + iperf3 + dnsutils # `dig` + `nslookup` + ldns # replacement of `dig`, it provide the command `drill` + aria2 # A lightweight multi-protocol & multi-source command-line download utility + socat # replacement of openbsd-netcat + nmap # A utility for network discovery and security auditing + ipcalc # it is a calculator for the IPv4/v6 addresses + + # misc + cowsay + file + which + tree + gnused + gnutar + gawk + zstd + gnupg + + # nix related + # + # it provides the command `nom` works just like `nix + # with more details log output + nix-output-monitor + + # productivity + hugo # static site generator + glow # markdown previewer in terminal + + btop # replacement of htop/nmon + iotop # io monitoring + iftop # network monitoring + + # system call monitoring + strace # system call monitoring + ltrace # library call monitoring + lsof # list open files + + # system tools + sysstat + lm_sensors # for `sensors` command + ethtool + pciutils # lspci + usbutils # lsusb + ]; + + # 启用 starship,这是一个漂亮的 shell 提示符 + programs.starship = { + enable = true; + settings = { + add_newline = false; + aws.disabled = true; + gcloud.disabled = true; + line_break.disabled = true; + }; + }; + + # alacritty 终端配置 + programs.alacritty = { + enable = true; + env.TERM = "xterm-256color"; + font = { + size = 12; + draw_bold_text_with_bright_colors = true; + }; + scrolling.multiplier = 5; + selection.save_to_clipboard = true; + }; + + programs.bash = { + enable = true; + enableCompletion = true; + bashrcExtra = '' + export PATH="$PATH:$HOME/bin:$HOME/.local/bin:$HOME/go/bin" + ''; + + # set some aliases, feel free to add more or remove some + shellAliases = { + urldecode = "python3 -c 'import sys, urllib.parse as ul; print(ul.unquote_plus(sys.stdin.read()))'"; + urlencode = "python3 -c 'import sys, urllib.parse as ul; print(ul.quote_plus(sys.stdin.read()))'"; + httpproxy = "export https_proxy=http://127.0.0.1:7890; export http_proxy=http://127.0.0.1:7890;"; + }; + }; + + # This value determines the Home Manager release that your + # configuration is compatible with. This helps avoid breakage + # when a new Home Manager release introduces backwards + # incompatible changes. + # + # You can update Home Manager without changing this value. See + # the Home Manager release notes for a list of state version + # changes in each release. + home.stateVersion = "22.11"; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; +} +``` + +添加好 `/etc/nixos/home.nix` 后,还需要在 `/etc/nixos/flake.nix` 中导入该配置,它才能生效,可以使用如下命令,在当前文件夹中生成一个示例配置以供参考: + +```shell +nix flake new example -t github:nix-community/home-manager#nixos +``` + +调整好参数后的 `/etc/nixos/flake.nix` 内容示例如下: + +```nix +{ + description = "NixOS configuration"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + home-manager.url = "github:nix-community/home-manager"; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = inputs@{ nixpkgs, home-manager, ... }: { + nixosConfigurations = { + # 这里的 nixos-test 替换成你的主机名称 + nixos-test = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./configuration.nix + + # 将 home-manager 配置为 nixos 的一个 module + # 这样在 nixos-rebuild switch 时,home-manager 配置也会被自动部署 + home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + + # 这里的 ryan 也得替换成你的用户名 + # 这里的 import 函数在前面 Nix 语法中介绍过了,不再赘述 + home-manager.users.ryan = import ./home.nix; + + # 使用 home-manager.extraSpecialArgs 自定义传递给 ./home.nix 的参数 + # 取消注释下面这一行,就可以在 home.nix 中使用 flake 的所有 inputs 参数了 + # home-manager.extraSpecialArgs = inputs; + } + ]; + }; + }; + }; +} +``` + +然后执行 `sudo nixos-rebuild switch` 应用配置,即可完成 home-manager 的安装。 + +安装完成后,所有用户级别的程序、配置,都可以通过 `/etc/nixos/home.nix` 管理,并且执行 `sudo nixos-rebuild switch` 时也会自动应用 home-manager 的配置。 + +`home.nix` 中 Home Manager 的配置项有这几种查找方式: + +- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.html): 一份包含了所有配置项的列表,建议在其中关键字搜索。 +- [home-manager](https://github.com/nix-community/home-manager): 有些配置项在官方文档中没有列出,或者文档描述不够清晰,可以直接在这份 home-manager 的源码中搜索阅读对应的源码。 diff --git a/docs/zh/nixos-with-flakes/update-the-system.md b/docs/zh/nixos-with-flakes/update-the-system.md new file mode 100644 index 0000000..418f37e --- /dev/null +++ b/docs/zh/nixos-with-flakes/update-the-system.md @@ -0,0 +1,13 @@ + +### 8. 更新系统 {#update-nixos-system} + +在使用了 Nix Flakes 后,要更新系统也很简单,先更新 flake.lock 文件,然后部署即可。在配置文件夹中执行如下命令: + +```shell +# 更新 flake.lock +nix flake update +# 部署系统 +sudo nixos-rebuild switch +``` + +另外有时候安装新的包,跑 `sudo nixos-rebuild switch` 时可能会遇到 sha256 不匹配的报错,也可以尝试通过 `nix flake update` 更新 flake.lock 来解决(原理暂时不太清楚)。 diff --git a/docs/zh/nixos-with-flakes/upgrade-or-downgrade-packages.md b/docs/zh/nixos-with-flakes/upgrade-or-downgrade-packages.md new file mode 100644 index 0000000..94871ce --- /dev/null +++ b/docs/zh/nixos-with-flakes/upgrade-or-downgrade-packages.md @@ -0,0 +1,94 @@ + +## 升级与降级软件包 {#rollback-package-version} + +在使用 Nix Flakes 后,目前大家用得比较多的都是 `nixos-unstable` 分支的 nixpkgs,有时候就会遇到一些 bug,比如我最近(2023/5/6)就遇到了 [chrome/vscode 闪退的问题](https://github.com/swaywm/sway/issues/7562)。 + +这时候就需要退回到之前的版本,在 Nix Flakes 中,所有的包版本与 hash 值与其 input 数据源的 git commit 是一一对应的关系,因此回退某个包的到历史版本,就需要锁定其 input 数据源的 git commit. + +为了实现上述需求,首先修改 `/etc/nixos/flake.nix`,示例内容如下(主要是利用 `specialArgs` 参数): + +```nix +{ + description = "NixOS configuration of Ryan Yin" + + inputs = { + # 默认使用 nixos-unstable 分支 + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + # 最新 stable 分支的 nixpkgs,用于回退个别软件包的版本,当前最新版本为 22.11 + nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-22.11"; + + # 另外也可以使用 git commit hash 来锁定版本,这是最彻底的锁定方式 + nixpkgs-fd40cef8d.url = "github:nixos/nixpkgs/fd40cef8d797670e203a27a91e4b8e6decf0b90c"; + }; + + outputs = inputs@{ + self, + nixpkgs, + nixpkgs-stable, + nixpkgs-fd40cef8d, + ... + }: { + nixosConfigurations = { + nixos-test = nixpkgs.lib.nixosSystem rec { + system = "x86_64-linux"; + + # 核心参数是这个,将非默认的 nixpkgs 数据源传到其他 modules 中 + specialArgs = { + # 注意每次 import 都会生成一个新的 nixpkgs 实例 + # 这里我们直接在 flake.nix 中创建实例, 再传递到其他子 modules 中使用 + # 这样能有效重用 nixpkgs 实例,避免 nixpkgs 实例泛滥。 + pkgs-stable = import nixpkgs-stable { + system = system; # 这里递归引用了外部的 system 属性 + # 为了拉取 chrome 等软件包,需要允许安装非自由软件 + config.allowUnfree = true; + }; + + pkgs-fd40cef8d = import nixpkgs-fd40cef8d { + system = system; + config.allowUnfree = true; + }; + }; + modules = [ + ./hosts/nixos-test + + # 省略其他模块配置... + ]; + }; + }; + }; +} +``` + +然后在你对应的 module 中使用该数据源中的包,一个 Home Manager 的子模块示例: + +```nix +{ + pkgs, + config, + # nix 会从 flake.nix 的 specialArgs 查找并注入此参数 + pkgs-stable, + # pkgs-fd40cef8d, # 也可以使用固定 hash 的 nixpkgs 数据源 + ... +}: + +{ + # 这里从 pkg-stable 中引用包 + home.packages = with pkgs-stable; [ + firefox-wayland + + # chrome wayland support was broken on nixos-unstable branch, so fallback to stable branch for now + # https://github.com/swaywm/sway/issues/7562 + google-chrome + ]; + + programs.vscode = { + enable = true; + package = pkgs-stable.vscode; # 这里也一样,从 pkgs-stable 中引用包 + }; +} +``` + +配置完成后,通过 `sudo nixos-rebuild switch` 部署即可将 firefox/chrome/vscode 三个软件包回退到 stable 分支的版本。 + +> 根据 @fbewivpjsbsby 补充的文章 [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347),在子模块中用 `import` 来定制 `nixpkgs` 不是一个好的习惯,因为每次 `import` 都会重新求值并产生一个新的 nixpkgs 实例,在配置越来越多时会导致构建时间变长、内存占用变大。所以这里改为了在 `flake.nix` 中创建所有 nixpkgs 实例。 diff --git a/docs/zh/nixos/index.md b/docs/zh/nixos/index.md deleted file mode 100644 index 4fe9c19..0000000 --- a/docs/zh/nixos/index.md +++ /dev/null @@ -1,956 +0,0 @@ - -## VI. Managing the system declaratively - -> https://nixos.wiki/wiki/Overview_of_the_NixOS_Linux_distribution - -After learning the basics of the Nix language, we can start using it to configure our NixOS. The default configuration for NixOS is located at `/etc/nixos/configuration.nix`, which contains all the declarative configuration for the system, such as time zone, language, keyboard layout, network, users, file system, boot options, etc. - -If we want to modify the system state in a reproducible way (**which is also the most recommended way**), we need to manually edit `/etc/nixos/configuration.nix`, and then execute `sudo nixos-rebuild switch` to apply the modified configuration, it will generate a new system environment based on the configuration file we modified, sets the new environment as the default one, and also preserves & added the previous environment into the boot options of grub/sytemd-boot. This ensures we can always roll back to the old environment(even if the new environment fails to start). - -`/etc/nixos/configuration.nix` is the classic method to configure NixOS, which relies on data sources configured by `nix-channel` and has no version-locking mechanism, making it difficult to ensure the reproducibility of the system. **A better approach is to use Flakes**, which can ensure the reproducibility of the system and make it easy to manage the configuration. - -Now first, let's learn how to manage NixOS through the classic method, `/etc/nixos/configuration.nix`, and then migrate to the more advanced Flakes. - -### 1. Configuring the system using `/etc/nixos/configuration.nix` - -As I mentioned earlier, this is the classic method to configured NixOS, and also the default method currently used by NixOS. It relies on data sources configured by `nix-channel` and has no version-locking mechanism, making it difficult to ensure the reproducibility of the system. - -For example, to enable ssh and add a user "ryan", simply add the following content into `/etc/nixos/configuration.nix`: - -```nix -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running 'nixos-help'). -{ config, pkgs, ... }: - -{ - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - - # Omit the previous configuration....... - - # add user ryan - users.users.ryan = { - isNormalUser = true; - description = "ryan"; - extraGroups = [ "networkmanager" "wheel" ]; - openssh.authorizedKeys.keys = [ - # replace with your own public key - "ssh-ed25519 ryan@ryan-pc" - ]; - packages = with pkgs; [ - firefox - # thunderbird - ]; - }; - - # enable openssh-server - services.openssh = { - enable = true; - permitRootLogin = "no"; # disable root login - passwordAuthentication = false; # disable password login - openFirewall = true; - forwardX11 = true; # enable X11 forwarding - }; - - # omit the rest of the configuration....... -} -``` - -In this configuration, we declared that we want to enable the openssh service, add an ssh public key for the user ryan, and disable password login. - -Now, let's run `sudo nixos-rebuild switch` to deploy the modified configuration, and then we can login to the system using ssh with the ssh keys we configured. - -Any reproducible changes to the system can be made by modifying `/etc/nixos/configuration.nix` and deploying the changes by running `sudo nixos-rebuild switch`. - -All configuration options in `/etc/nixos/configuration.nix` can be found in the following places: - -- By searching on Google, such as `Chrome NixOS`, which will provide NixOS informations related to Chrome. Generally, the NixOS Wiki and the source code of Nixpkgs will be among the top results. -- By searching for keywords in [NixOS Options Search](https://search.nixos.org/options). -- For system-level configuration, relevant documentation can be found in [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration). -- By searching for keywords directly in the source code of [nixpkgs](https://github.com/NixOS/nixpkgs) on GitHub. - -### 2. Enabling NixOS Flakes Support - -Compared to the default configuration approach of NixOS, Flakes provide better reproducibility and a clearer package structure that is easier to maintain. Therefore, it is recommended to manage NixOS with Flakes. - -However, as Flakes is still an experimental feature currently, it's not enabled by default yet, we need to enable it manually by modifying `/etc/nixos/configuration.nix`, example as follows: - -```nix -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running 'nixos-help'). -{ config, pkgs, ... }: - -{ - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - - # omit the previous configuration....... - - # enable Flakes and the new command line tool - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - - environment.systemPackages = with pkgs; [ - # Flakes uses git to pull dependencies from data sources, so git must be installed first - git - vim - wget - curl - - ]; - - # omit the rest of the configuration....... -} -``` - -Now run `sudo nixos-rebuild switch` to apply the changes, and then you can write the configuration for NixOS with Flakes. - -### 3. Switching System Configuration to `flake.nix` - -After enabling `flakes`, `sudo nixos-rebuild switch` will try to read`/etc/nixos/flake.nix` first every time you run it, if not found, it will fallback to `/etc/nixos/configuration.nix`. - -Now to learn how to write a flake, let's take a look at the official flake templates provided by Nix. First, check which templates are available: - -```bash -nix flake show templates -``` - -The templates `templates#full` contains all possible usecases, let's take a look at it: - -```bash -nix flake init -t templates#full -cat flake.nix -``` - -After reading this example, let's create a file `/etc/nixos/flake.nix` and copy the content of the example into it. -With `/etc/nixos/flake.nix`, all system modifications will be taken over by Flakes from now on. - -The template we copied CAN NOT be used directly, we need to modify it to make it work, an example of `/etc/nixos/flake.nix` is as follows: - -```nix -{ - description = "Ryan's NixOS Flake"; - - # This is the standard format for flake.nix. `inputs` are the dependencies of the flake, - # and `outputs` function will return all the build results of the flake. - # Each item in `inputs` will be passed as a parameter to the `outputs` function after being pulled and built. - inputs = { - # There are many ways to reference flake inputs. The most widely used is github:owner/name/reference, - # 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 = { - url = "github:nix-community/home-manager/release-22.11"; - # The `follows` keyword in inputs is used for inheritance. - # Here, `inputs.nixpkgs` of home-manager is kept consistent with the `inputs.nixpkgs` of the current flake, - # to avoid problems caused by different versions of nixpkgs. - inputs.nixpkgs.follows = "nixpkgs"; - }; - }; - - # `outputs` are all the build result of the flake. - # A flake can have many use cases and different types of outputs. - # parameters in `outputs` are defined in `inputs` and can be referenced by their names. - # However, `self` is an exception, This special parameter points to the `outputs` itself (self-reference) - # The `@` syntax here is used to alias the attribute set of the inputs's parameter, making it convenient to use inside the function. - outputs = { self, nixpkgs, ... }@inputs: { - nixosConfigurations = { - # By default, NixOS will try to refer the nixosConfiguration with its hostname. - # so the system named `nixos-test` will use this configuration. - # However, the configuration name can also be specified using `sudo nixos-rebuild switch --flake /path/to/flakes/directory#`. - # The `nixpkgs.lib.nixosSystem` function is used to build this configuration, the following attribute set is its parameter. - # Run `sudo nixos-rebuild switch --flake .#nixos-test` in the flake's directory to deploy this configuration on any NixOS system - "nixos-test" = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - - # The Nix module system can modularize configuration, improving the maintainability of configuration. - # - # Each parameter in the `modules` is a Nix Module, and there is a partial introduction to it in the nixpkgs manual: - # - # It is said to be partial because the documentation is not complete, only some simple introductions - # (such is the current state of Nix documentation...) - # A Nix Module can be an attribute set, or a function that returns an attribute set. - # If a Module is a function, this function can only have the following parameters: - # - # lib: the nixpkgs function library, which provides many useful functions for operating Nix expressions - # https://nixos.org/manual/nixpkgs/stable/#id-1.4 - # config: all config options of the current flake - # options: all options defined in all NixOS Modules in the current flake - # pkgs: a collection of all packages defined in nixpkgs. - # 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 builtin modules folder, - # used to import some extra modules from nixpkgs. - # this parameter is rarely used, you can ignore it for now. - # - # Only these parameters can be passed by default. - # If you need to pass other parameters, you must use `specialArgs` by uncomment the following line - # specialArgs = {...} # pass custom arguments into sub module. - modules = [ - # Import the configuration.nix we used before, so that the old configuration file can still take effect. - # Note: /etc/nixos/configuration.nix itself is also a Nix Module, so you can import it directly here - ./configuration.nix - ]; - }; - }; - }; -} -``` - -Here we defined a NixOS system called `nixos-test`, whose configuration file is `./configuration.nix`, which is the classic configuration we modified before, so we can still make use of it. - -Now run `sudo nixos-rebuild switch` to apply the configuration, and 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. - -### 4. Manage system software through Flakes - -After the switch, we can now manage the system through Flakes. The most common requirement for managing a system is to install softwares. We have seen how to install packages through `environment.systemPackages` before, and these packages are all from the official nixpkgs repository. - -Now let's learn how to install packages from other sources through Flakes. This is much more flexible than installing from nixpkgs directly. The most obvious benefit is that you can easily set the version of the software. - -Use [helix](https://github.com/helix-editor/helix) editor as an example, first we need to add the helix as an input into `flake.nix`: - -```nix -{ - description = "NixOS configuration of Ryan Yin"; - - # ...... - - inputs = { - # ...... - - # helix editor, use the tag 23.05 - helix.url = "github:helix-editor/helix/23.05"; - }; - - outputs = inputs@{ self, nixpkgs, ... }: { - nixosConfigurations = { - nixos-test = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - - # set all inputs parameters as specialArgs of all sub module - # so that we can use `helix` input in sub modules - specialArgs = inputs; - modules = [ - ./configuration.nix - ]; - }; - }; - }; -} -``` - -Then udpate `configuration.nix` to install `helix` from the input `helix`: - -```nix -# Nix will automatically inject `helix` from specialArgs -# into the third parameter of this function through name matching -{ config, pkgs, helix, ... }: - -{ - # omit other configuration...... - - environment.systemPackages = with pkgs; [ - git - vim - wget - curl - - # install helix from the input `helix` - helix.packages."${pkgs.system}".helix - ]; - - # omit other configuration...... -} -``` - -Now deploy the changes by `sudo nixos-rebuild switch`, and then we can start the helix editor by `helix` command. - -### 5. Add Custom Cache Mirror - -> You can skip this section if you don't need to customize the cache mirror. - -To speed up package building, Nix provides to cache build results to avoid build every packages locally. - -With the NixOS's classic configuration method, other cache sources can be added by using `nix-channel`, but Flakes avoids using any system-level configuration and environment variables to ensure that its build results are not affected by the environment(so the build results are reproducible). - -Therefore, to customize the cache source, we must add the related configuration in `flake.nix` by using the parameter `nixConfig`. An example is as follows: - -```nix -{ - description = "NixOS configuration of Ryan Yin"; - - # 1. To ensure purity, Flakes does not rely on the system's `/etc/nix/nix.conf`, so we have to set related configuration here. - # 2. To ensure security, flake allows only a few nixConfig parameters to be set directly by default. - # you need to add `--accept-flake-config` when executing the nix command, - # otherwise all other parameters will be ignored, and an warning will printed by nix. - nixConfig = { - experimental-features = [ "nix-command" "flakes" ]; - substituters = [ - # replace official cache with a mirror located in China - "https://mirrors.bfsu.edu.cn/nix-channels/store" - "https://cache.nixos.org/" - ]; - - extra-substituters = [ - # nix community's cache server - "https://nix-community.cachix.org" - ]; - extra-trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - ]; - }; - - inputs = { - # omit some configuration... - }; - - outputs = { - # omit some configuration... - }; -} - -``` - -After the modification, run `sudo nixos-rebuild switch` to apply the updates. - -### 6. Install home-manager - -As I mentioned earlier, NixOS can only manage system-level configuration, to manage the Home directory(user-level configuration), we need to install home-manager. - -According to the official document [Home Manager Manual](https://nix-community.github.io/home-manager/index.htm), in order to install home-manager as a module of NixOS, we need to create `/etc/nixos/home.nix` first, an example content shown below: - -```nix -{ config, pkgs, ... }: - -{ - # TODO please change the username & home direcotry to your own - home.username = "ryan"; - home.homeDirectory = "/home/ryan"; - - # link the configuration file in current directory to the specified location in home directory - # home.file.".config/i3/wallpaper.jpg".source = ./wallpaper.jpg; - - # link all files in `./scripts` to `~/.config/i3/scripts` - # home.file.".config/i3/scripts" = { - # source = ./scripts; - # recursive = true; # link recursively - # executable = true; # make all files executable - # }; - - # encode the file content in nix configuration file directly - # home.file.".xxx".text = '' - # xxx - # ''; - - # set cursor size and dpi for 4k monitor - xresources.properties = { - "Xcursor.size" = 16; - "Xft.dpi" = 172; - }; - - # basic configuration of git, please change to your own - programs.git = { - enable = true; - userName = "Ryan Yin"; - userEmail = "xiaoyin_c@qq.com"; - }; - - # Packages that should be installed to the user profile. - home.packages = [ - # here is some command line tools I use frequently - # feel free to add your own or remove some of them - - neofetch - nnn # terminal file manager - - # archives - zip - xz - unzip - p7zip - - # utils - ripgrep # recursively searches directories for a regex pattern - jq # A lightweight and flexible command-line JSON processor - yq-go # yaml processer https://github.com/mikefarah/yq - exa # A modern replacement for ‘ls’ - fzf # A command-line fuzzy finder - - # networking tools - mtr # A network diagnostic tool - iperf3 - dnsutils # `dig` + `nslookup` - ldns # replacement of `dig`, it provide the command `drill` - aria2 # A lightweight multi-protocol & multi-source command-line download utility - socat # replacement of openbsd-netcat - nmap # A utility for network discovery and security auditing - ipcalc # it is a calculator for the IPv4/v6 addresses - - # misc - cowsay - file - which - tree - gnused - gnutar - gawk - zstd - gnupg - - # nix related - # - # it provides the command `nom` works just like `nix - # with more details log output - nix-output-monitor - - # productivity - hugo # static site generator - glow # markdown previewer in terminal - - btop # replacement of htop/nmon - iotop # io monitoring - iftop # network monitoring - - # system call monitoring - strace # system call monitoring - ltrace # library call monitoring - lsof # list open files - - # system tools - sysstat - lm_sensors # for `sensors` command - ethtool - pciutils # lspci - usbutils # lsusb - ]; - - # starship - an customizable prompt for any shell - programs.starship = { - enable = true; - settings = { - add_newline = false; - aws.disabled = true; - gcloud.disabled = true; - line_break.disabled = true; - }; - }; - - # alacritty - a cross-platform, GPU-accelerated terminal emulator - programs.alacritty = { - enable = true; - env.TERM = "xterm-256color"; - font = { - size = 12; - draw_bold_text_with_bright_colors = true; - }; - scrolling.multiplier = 5; - selection.save_to_clipboard = true; - }; - - programs.bash = { - enable = true; - enableCompletion = true; - bashrcExtra = '' - export PATH="$PATH:$HOME/bin:$HOME/.local/bin:$HOME/go/bin" - ''; - - # set some aliases, feel free to add more or remove some - shellAliases = { - urldecode = "python3 -c 'import sys, urllib.parse as ul; print(ul.unquote_plus(sys.stdin.read()))'"; - urlencode = "python3 -c 'import sys, urllib.parse as ul; print(ul.quote_plus(sys.stdin.read()))'"; - httpproxy = "export https_proxy=http://127.0.0.1:7890; export http_proxy=http://127.0.0.1:7890;"; - }; - }; - - # This value determines the home Manager release that your - # configuration is compatible with. This helps avoid breakage - # when a new home Manager release introduces backwards - # incompatible changes. - # - # You can update home Manager without changing this value. See - # the home Manager release notes for a list of state version - # changes in each release. - home.stateVersion = "22.11"; - - # Let home Manager install and manage itself. - programs.home-manager.enable = true; -} -``` - -After adding `/etc/nixos/home.nix`, you need to import this new configuration file in `/etc/nixos/flake.nix` to make use of it, use the following command to generate an example in the current folder for reference: - -```shell -nix flake new example -t github:nix-community/home-manager#nixos -``` - -After adjusting the parameters, the content of `/etc/nixos/flake.nix` is as follows: - -```nix -{ - description = "NixOS configuration"; - - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - home-manager.url = "github:nix-community/home-manager"; - home-manager.inputs.nixpkgs.follows = "nixpkgs"; - }; - - outputs = inputs@{ nixpkgs, home-manager, ... }: { - nixosConfigurations = { - # TODO please change the hostname to your own - nixos-test = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - ./configuration.nix - - # make home-manager as a module of nixos - # so that home-manager configuration will be deployed automatically when executing `nixos-rebuild switch` - home-manager.nixosModules.home-manager - { - home-manager.useGlobalPkgs = true; - home-manager.useUserPackages = true; - - # TODO replace ryan with your own username - home-manager.users.ryan = import ./home.nix; - - # Optionally, use home-manager.extraSpecialArgs to pass arguments to home.nix - } - ]; - }; - }; - }; -} -``` - -Then run `sudo nixos-rebuild switch` to apply the configuration, and home-manager will be installed automatically. - -After the installation, all user-level packages and configuration can be managed through `/etc/nixos/home.nix`. When running `sudo nixos-rebuild switch`, the configuration of home-manager will be applied automatically. (**It's not necessary to run `home-manager switch` manually**!) - -To find the options we can use in `home.nix`, referring to the following documents: - -- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.html): A list of all options, it is recommended to search for keywords in it. -- [home-manager](https://github.com/nix-community/home-manager): Some options are not listed in the official documentation, or the documentation is not clear enough, you can directly search and read the corresponding source code in this home-manager repo. - -### 7. Modular NixOS configuration - -At this point, the skeleton of the entire system is basically configured. The current configuration structure in `/etc/nixos` should be as follows: - -``` -$ tree -. -├── flake.lock -├── flake.nix -├── home.nix -└── configuration.nix -``` - -The functions of these four files are explained below: - -- `flake.lock`: An automatically generated version-lock file, which records all input sources, hash values, and version numbers of the entire flake to ensure that the system is reproducible. -- `flake.nix`: The entry file, which will be recognized and deployed when executing `sudo nixos-rebuild switch`. - - See [Flakes - NixOS Wiki](https://nixos.wiki/wiki/Flakes) for all options of flake.nix. -- `configuration.nix`: Imported as a nix module in flake.nix, all system-level configuration are currently written here. - - See [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) for all options of configuration.nix. -- `home.nix`: Imported by home-manager as the configuration of the user `ryan` in flake.nix, that is, it contains all the configuration of `ryan`, and is responsible for managing `ryan`'s home folder. - - See [Appendix A. Configuration Options - home Manager](https://nix-community.github.io/home-manager/options.html) for all options of home.nix. - -By modifying these files, you can change the status of the system and the home directory declaratively. - -As the configuration increases, it will be difficult to maintain the configuration by relying solely on `configuration.nix` and `home.nix`. Therefore, a better solution is to use the nix module system to split the configuration into multiple modules and write them in a classified manner. - -nix module system provide a paramter, `imports`, which accept a list of `.nix` files, and merge all the configuration defined in these files into the current nix module. Note that the word used here is "**merge**", which means that `imports` will **NOT** simply overwrite the duplicate configuration, but handle them more reasonably. For example, if I define `program.packages = [...]` in multiple modules, then `imports` will merge all `program.packages` defined in all nix modules into one list. Not only lists can be merged correctly, but attribute sets can also be merged correctly. The specific behavior can be explored by yourself. - -> I only found a description of `imports` in [nixpkgs-unstable official manual - evalModules parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters): `A list of modules. These are merged together to form the final configuration.`, it's a bit ambiguous... - -With the help of `imports`, we can split `home.nix` and `configuration.nix` into multiple nix modules defined in diffrent `.nix` files. - -Use [ryan4yin/nix-config/v0.0.2](https://github.com/ryan4yin/nix-config/tree/v0.0.2) as an example, which is the configuration of my previous NixOS system with i3 window manager. The structure of it is as follows: - -```shell -├── flake.lock -├── flake.nix -├── home -│ ├── default.nix # here we import all submodules by imports = [...] -│ ├── fcitx5 # fcitx5 input method's configuration -│ │ ├── default.nix -│ │ └── rime-data-flypy -│ ├── i3 # i3 window manager's configuration -│ │ ├── config -│ │ ├── default.nix -│ │ ├── i3blocks.conf -│ │ ├── keybindings -│ │ └── scripts -│ ├── programs -│ │ ├── browsers.nix -│ │ ├── common.nix -│ │ ├── default.nix # here we import all modules in programs folder by imports = [...] -│ │ ├── git.nix -│ │ ├── media.nix -│ │ ├── vscode.nix -│ │ └── xdg.nix -│ ├── rofi # rofi launcher's configuration -│ │ ├── configs -│ │ │ ├── arc_dark_colors.rasi -│ │ │ ├── arc_dark_transparent_colors.rasi -│ │ │ ├── power-profiles.rasi -│ │ │ ├── powermenu.rasi -│ │ │ ├── rofidmenu.rasi -│ │ │ └── rofikeyhint.rasi -│ │ └── default.nix -│ └── shell # shell/terminal related configuration -│ ├── common.nix -│ ├── default.nix -│ ├── nushell -│ │ ├── config.nu -│ │ ├── default.nix -│ │ └── env.nu -│ ├── starship.nix -│ └── terminals.nix -├── hosts -│ ├── msi-rtx4090 # My main machine's configuration -│ │ ├── default.nix # This is the old configuration.nix, but most of the content has been split out to modules. -│ │ └── hardware-configuration.nix # hardware & disk related configuration, autogenerated by nixos -│ └── nixos-test # my test machine's configuration -│ ├── default.nix -│ └── hardware-configuration.nix -├── modules # some common NixOS modules that can be reused -│ ├── i3.nix -│ └── system.nix -└── wallpaper.jpg # wallpaper -``` - -For more details, see [ryan4yin/nix-config/v0.0.2](https://github.com/ryan4yin/nix-config/tree/v0.0.2). - -#### 7.1. `mkOverride`, `lib.mkDefault` and `lib.mkForce` - -You may found some people use `lib.mkDefault` `lib.mkForce` to define values in Nix files, as their names suggest, `lib.mkDefault` and `lib.mkForce` are used to set default values or force values of options. - -You can read the source code of `lib.mkDefault` and `lib.mkForce` to understand them by running `nix repl -f ''` and then enter `:e lib.mkDefault`(To learn the basic usage of `nix repl`, just type `:?` to see the help information). - -its source code is as follows: - -```nix - # ...... - - mkOverride = priority: content: - { _type = "override"; - inherit priority content; - }; - - mkOptionDefault = mkOverride 1500; # priority of option defaults - mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default - mkImageMediaOverride = mkOverride 60; # image media profiles can be derived by inclusion into host config, hence needing to override host config, but do allow user to mkForce - mkForce = mkOverride 50; - mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’ - - # ...... -``` - -So `lib.mkDefault` is used to set default values of options, it has a priority of 1000 internally, -and `lib.mkForce` is used to force values of options, it has a priority of 50 internally. -If you just set a value of an option directly, it will be set with a default priority of 1000(the same as `lib.mkDefault`). - -the lower the `priority`'s value is, the higher the actual priority is, so `lib.mkForce` has a higher priority than `lib.mkDefault`. -If you defined multiple values with the same priority, Nix will throw an error. - -They are useful to modularize the configuration, as you can set default values in a low-level module(base module), and force values in a high-level module. - -For example, I defined some default values in : - -```nix -{ lib, pkgs, ... }: - -{ - # ...... - - nixpkgs.config.allowUnfree = lib.mkDefault false; - - # ...... -} -``` - -And for my dekstop machine, I force the values to another value in : - -```nix -{ lib, pkgs, ... }: - -{ - # import the base module - imports = [ - ./core-server.nix - ]; - - # override the default value defined in the base module - nixpkgs.config.allowUnfree = lib.mkForce true; - - # ...... -} -``` - -#### 7.2 `lib.mkOrder`, `lib.mkBefore` and `lib.mkAfter` - -`lib.mkBefore` and `lib.mkAfter` are used to set the merge order of **list-type options**, just like `lib.mkDefault` and `lib.mkForce`, they're also useful to modularize the configuration. - -I said before that if you defined multiple values with the same **override priority**, Nix will throw an error. -But with `lib.mkOrder`, `lib.mkBefore` or `lib.mkAfter`, you can define multiple values with the same override priority, they will be merged in the order you defined. - -Let's running `nix repl -f ''` and then enter `:e lib.mkBefore` to take a look at its source code(To learn the basic usage of `nix repl`, just type `:?` to see the help information): - -```nix - # ...... - - mkOrder = priority: content: - { _type = "order"; - inherit priority content; - }; - - mkBefore = mkOrder 500; - mkAfter = mkOrder 1500; - - # The default priority for things that don't have a priority specified. - defaultPriority = 100; - - # ...... -``` - -So `lib.mkBefore` is a shortcut for `lib.mkOrder 500`, and `lib.mkAfter` is a shortcut for `lib.mkOrder 1500`. - -To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Flake project: - -```shell -# create flake.nix with the following content -› cat < :lf . -Added 9 variables. - -# check the order of systemPackages -nix-repl> outputs.nixosConfigurations.nixos-test.config.environment.systemPackages -[ «derivation /nix/store/0xvn7ssrwa0ax646gl4hwn8cpi05zl9j-git-2.40.1.drv» - «derivation /nix/store/7x8qmbvfai68sf73zq9szs5q78mc0kny-curl-8.1.1.drv» - «derivation /nix/store/bly81l03kh0dfly9ix2ysps6kyn1hrjl-nixos-container.drv» - ...... - ...... - «derivation /nix/store/qpmpvq5azka70lvamsca4g4sf55j8994-vim-9.0.1441.drv» ] -``` - -So we can see that the order of `systemPackages` is `git -> curl -> default packages -> vim`, which is the same as the order we defined in `flake.nix`. - -> Though it's useless to adjust the order of `systemPackages`, it may be helpful at some other places... - -### 8. Update the system - -With Flakes, it is also very simple to update the system. Just run the following commands in `/etc/nixos`: - -```shell -# update flake.lock -nix flake update -# apply the updates -sudo nixos-rebuild switch -``` - -Sometimes you may encounter some error of sha256 mismatch when running `nixos-rebuild switch`, which may be solved by updating `flake.lock` through `nix flake update`. - -### 9. Downgrade or upgrade some packages - -After using Flakes, most people are currently using the `nixos-unstable` branch of nixpkgs. Sometimes you will encounter some bugs, such as the [chrome/vscode crash problem](https://github.com/swaywm/sway/issues/7562) - -To resolve problems, we may need to downgrade or upgrade some packages. In Flakes, all package versions and hash values are one-to-one corresponding to the git commit of their flake input. -Therefore, to downgrade or upgrade a package, we need to lock the git commit of its flake input. - -For exmaple, let's add multiple nixpkgs, each using a different git commit or branch: - -```nix -{ - description = "NixOS configuration of Ryan Yin" - - inputs = { - # default to nixos-unstable branch - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - - # the latest stable branch of nixpkgs, used to rollback the version of some packages - # the current latest version is 22.11 - nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-22.11"; - - # we can also use git commit hash to lock the version - nixpkgs-fd40cef8d.url = "github:nixos/nixpkgs/fd40cef8d797670e203a27a91e4b8e6decf0b90c"; - outputs = inputs@{ - self, - nixpkgs, - nixpkgs-stable, - nixpkgs-fd40cef8d, - ... - }: { - nixosConfigurations = { - nixos-test = nixpkgs.lib.nixosSystem rec { - system = "x86_64-linux"; - - # The core parameter, which passes the non-default nixpkgs instances to other nix modules - specialArgs = { - # To use packages from nixpkgs-stable, we need to configure some parameters for it first - pkgs-stable = import nixpkgs-stable { - system = system; # refer the `system` parameter form outer scope recursively - # To use chrome, we need to allow the installation of non-free software - config.allowUnfree = true; - }; - pkgs-fd40cef8d = import nixpkgs-fd40cef8d { - system = system; - config.allowUnfree = true; - }; - }; - modules = [ - ./hosts/nixos-test - - # omit other configuration... - ]; - }; - }; - }; -} -``` - -And then refer the packages from `pkgs-stable` or `pkgs-fd40cef8d` in your sub module, a home manager's sub module as an example: - -```nix -{ - pkgs, - config, - # nix will search and jnject this parameter from specialArgs in flake.nix - pkgs-stable, - # pkgs-fd40cef8d, - ... -}: - -{ - # refer packages from pkgs-stable instead of pkgs - home.packages = with pkgs-stable; [ - firefox-wayland - - # chrome wayland support was broken on nixos-unstable branch, so fallback to stable branch for now - # https://github.com/swaywm/sway/issues/7562 - google-chrome - ]; - - programs.vscode = { - enable = true; - package = pkgs-stable.vscode; # refer vscode from pkgs-stable instead of pkgs - }; -} -``` - -After adjusted the configuration, deploy it with `sudo nixos-rebuild switch`, then your firefox/chrome/vscode will be downgraded to the version corresponding to `nixpkgs-stable` or `nixpkgs-fd40cef8d`. - -> according to [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347), it's not a good practice to use `import` in sub modules to customize `nixpkgs`, because each `import` will create a new instance of nixpkgs, which will increase the build time and memory usage as the configuration grows. So here we create all nixpkgs instances in `flake.nix` to avoid this problem. - -### 10. Manage the configuration with Git - -NixOS configuration is just a set of text files, it is very suitable to be managed with Git, and thus we can easily rollback to a previous version when we encounter some problems. - -However, NixOS places the configuration in `/etc/nixos` by default, which requires root permissions to modify, which is not convenient for daily use. -Luckily, Flakes can solve this problem, you can place your flake anywhere you like. - -For example, my usage is to place my flake in `~/nixos-config`, and then create a soft link in `/etc/nixos`: - -```shell -sudo mv /etc/nixos /etc/nixos.bak # backup the original configuration -sudo ln -s ~/nixos-config/ /etc/nixos - -# deploy the flake.nix located at the default location(/etc/nixos) -sudo nixos-rebuild switch -``` - -And then you can use Git to manage the configuration in `~/nixos-config`. The configuration can be used with ordinary user-level permissions, and it is not required to be owned by root. - -Another method is jsut to delete `/etc/nixos` directly, and specify the configuration file path each time you deploy it: - -```shell -sudo mv /etc/nixos /etc/nixos.bak -cd ~/nixos-config - -# `--flake .#nixos-test` means deploy the flake.nix located in the current directory, and the nixosConfiguration's name is `nixos-test` -sudo nixos-rebuild switch --flake .#nixos-test -``` - -Choose whichever you like. After that, system rollback will become very simple, just switch to the previous commit and then deploy it: - -```shell -cd ~/nixos-config -# switch to the previous commit -git checkout HEAD^1 -# deploy the flake.nix located in the current directory, and the nixosConfiguration's name is `nixos-test` -sudo nixos-rebuild switch --flake .#nixos-test -``` - -More operations on Git are not described here. Generally speaking, rollback can be done directly through Git. Only when the system crashes completely, you will need to restart into bootloader and boot the system from the previous historical version. - -### 11. View and delete history data {#view-and-delete-history} - -As we mentioned before, each deployment of NixOS will generate a new version, and all versions will be added to the system boot options. In addition to restarting the computer, we can also query all available historical versions through the following command: - -```shell -nix profile history --profile /nix/var/nix/profiles/system -``` - -The command to clean up historical versions to release storage space: - -```shell -# delete all historical versions older than 7 days -sudo nix profile wipe-history --profile /nix/var/nix/profiles/system --older-than 7d - -# we need to collect garbages after wipe-history -sudo nix store gc --debug -``` - -Another command returns all packages installed in the system: - -```shell -nix-env -qa -``` diff --git a/docs/zh/nixpkgs/index.md b/docs/zh/nixpkgs/index.md index f2a8a00..8036c0d 100644 --- a/docs/zh/nixpkgs/index.md +++ b/docs/zh/nixpkgs/index.md @@ -1,43 +1,43 @@ -## VIII. Nixpkgs's Advanced Usage +## 八、Nixpkgs 的高级用法 {#nixpkgs-advanced-usage} -`callPackage`, `Overriding`, and `Overlays` are the techniques occasionally used when using Nix to customize the build method of Nix packages. +callPackage、Overriding 与 Overlays 是在使用 Nix 时偶尔会用到的技术,它们都是用来自定义 Nix 包的构建方法的。 -We know that many programs have a large number of build parameters that need to be configured, and different users may want to use different build parameters. This is where `Overriding` and `Overlays` come in handy. Let me give you a few examples I have encountered: +我们知道许多程序都有大量构建参数需要配置,不同的用户会希望使用不同的构建参数,这时候就需要 Overriding 与 Overlays 来实现。我举几个我遇到过的例子: -1. [`fcitx5-rime.nix`](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): By default, `fcitx5-rime` use `rime-data` as the value of `rimeDataPkgs`, but this parameter can be customized by `override`. -2. [`vscode/with-extensions.nix`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vscode/with-extensions.nix): This package for VS Code can also be customized by overriding the value of `vscodeExtensions`, thus we can install some custom plugins into VS Code. - - [`nix-vscode-extensions`](https://github.com/nix-community/nix-vscode-extensions): This is a vscode plugin manager implemented by overriding `vscodeExtensions`. -3. [`firefox/common.nix`](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): Firefox has many customizable parameters too. -4. ... +1. [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): fcitx5-rime 的 `rimeDataPkgs` 默认使用 `rime-data` 包,但是也可以通过 override 来自定义该参数的值,以加载自定义的 rime 配置(比如加载小鹤音形输入法配置)。 +2. [vscode/with-extensions.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vscode/with-extensions.nix): vscode 的这个包也可以通过 override 来自定义 `vscodeExtensions` 参数的值来安装自定义插件。 + 1. [nix-vscode-extensions](https://github.com/nix-community/nix-vscode-extensions): 就是利用该参数实现的 vscode 插件管理 +3. [firefox/common.nix](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): firefox 同样有许多可自定义的参数 +4. 等等 -In short, `Overriding` or `Overlays` can be used to customize the build parameters of Nix packages. +总之如果需要自定义上述这类 Nix 包的构建参数,或者实施某些比较底层的修改,我们就得用到 Overriding 跟 Overlays。 ### 1. pkgs.callPackage {#callpackage} > [Chapter 13. Callpackage Design Pattern - Nix Pills](https://nixos.org/guides/nix-pills/callpackage-design-pattern.html) -In the previous content, We have used `import xxx.nix` to import Nix files many times, this syntax simply returns the execution result of the file, without any further processing of the it. +前面我们介绍并大量使用了 `import xxx.nix` 来导入 Nix 文件,这种语法只是单纯地返回该文件的执行结果,不会对该结果进行进一步处理。 +比如说 `xxx.nix` 的内容是形如 `{...}: {...}`,那么 `import xxx.nix` 的结果就是该文件中定义的这个函数。 -`pkgs.callPackage` is also used to import Nix files, its syntax is `pkgs.callPackage xxx.nix { ... }`, but unlike `import`, the Nix file imported by it must be a Derivation or a function that returns a Derivation. Its result is a Derivation(a software package) too. +`pkgs.callPackage` 也是用来导入 Nix 文件的,它的语法是 `pkgs.callPackage xxx.nix { ... }`. 但跟 `import` 不同的是,它导入的 nix 文件内容必须是一个 Derivation 或者返回 Derivation 的函数,它的执行结果一定是一个 Derivation,也就是一个软件包。 -So what does the Nix file that can be used as a parameter of `pkgs.callPackge` look like? You can take a look at the `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix` we mentioned earlier, they can all be imported by `pkgs.callPackage`. +那可以作为 `pkgs.callPackge` 参数的 nix 文件具体长啥样呢,可以去看看我们前面举例过的 `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix`,它们都可以被 `pkgs.callPackage` 导入。 -When the `xxx.nix` used in `pkgs.callPackge xxx.nix {...}` is a function (most Nix packages are like this), the execution flow is as follows: +当 `pkgs.callPackge xxx.nix {...}` 中的 `xxx.nix`,其内容为一个函数时(绝大多数 nix 包都是如此),执行流程如下: -1. `pkgs.callPackge xxx.nix {...}` will first `import xxx.nix` to get the function defined in it. The parameters of this function usually have `lib`, `stdenv`, `fetchurl` and other parameters, as well as some custom parameters, which usually have default values. -2. Then `pkgs.callPackge` will first look up the value matching the name from the current environment as the parameter to be passed to the function. parameters like `lib` `stdenv` `fetchurl` are defined in nixpkgs, and they will be found in this step. -3. Then `pkgs.callPackge` will merge its second parameter `{...}` with the attribute set obtained in the previous step, and then pass it to the function imported from `xxx.nix` and execute it. -4. Finally we get a Derivation as the result of the function execution. +1. `pkgs.callPackge xxx.nix {...}` 会先 `import xxx.nix`,得到其中定义的函数,该函数的参数通常会有 `lib`, `stdenv`, `fetchurl` 等参数,以及一些自定义参数,自定义参数通常都有默认值。 +2. 接着 `pkgs.callPackge` 会首先从当前环境中查找名称匹配的值,作为将要传递给前述函数的参数。像 `lib` `stdenv` `fetchurl` 这些都是 nixpkgs 中的函数,在这一步就会查找到它们。 +3. 接着 `pkgs.callPackge` 会将其第二个参数 `{...}` 与前一步得到的参数集(attribute set)进行合并,得到一个新的参数列表,然后将其传递给该函数并执行。 +4. 函数执行结果是一个 Derivation,也就是一个软件包。 -So the common usage of `pkgs.callPackage` is to import custom Nix packages and used it in Nix Module. -For example, we wrote a `hello.nix` ourselves, and then we can use `pkgs.callPackage ./hello.nix {}` in any Nix Module to import and use it. +这个函数比较常见的用途是用来导入一些自定义的 Nix 包,比如说我们自己写了一个 `hello.nix`,然后就可以在任意 Nix Module 中使用 `pkgs.callPackage ./hello.nix {}` 来导入并使用它。 ### 2. Overriding {#overriding} > [Chapter 4. Overriding - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overrides) -Simply put, all Nix packages in nixpkgs can be customized with `.override {}` to define some build parameters, which returns a new Derivation that uses custom parameters. For example: +简单的说,所有 nixpkgs 中的 Nix 包都可以通过 `.override {}` 来自定义某些构建参数,它返回一个使用了自定义参数的新 Derivation. 举个例子: ```nix pkgs.fcitx5-rime.override {rimeDataPkgs = [ @@ -45,16 +45,15 @@ pkgs.fcitx5-rime.override {rimeDataPkgs = [ ];} ``` -The result of this Nix expression is a new Derivation, where `rimeDataPkgs` is overridden as `[./rime-data-flypy]`, while other parameters remain their original values. +上面这个 Nix 表达式的执行结果就是一个新的 Derivation,它的 `rimeDataPkgs` 参数被覆盖为 `[./rime-data-flypy]`,而其他参数则沿用原来的值。 -How to know which parameters of `fcitx5-rime` can be overridden? There are several ways: +如何知道 `fcitx5-rime` 这个包有哪些参数可以覆写呢?有几种方法: -1. Try to find the source code of the package in the nixpkgs repository on GitHub, such as [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix) - 1. Note: Be sure to select the correct branch, for example, if you are using the nixos-unstable branch, you need to find it in the nixos-unstable branch. -2. Check by using `nix repl ''`, then enter `:e pkgs.fcitx5-rime`, which will open the source code of this package through the default editor, and then you can see all the parameters of this package. - 1. Note: To learn the basic usage of `nix repl`, just type `:?` to see the help information +1. 直接在 GitHub 的 nixpkgs 源码中找:[fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix) + 1. 注意要选择正确的分支,加入你用的是 nixos-unstable 分支,那就要在 nixos-unstable 分支中找。 +2. 通过 `nix repl` 交互式查看:`nix repl ''`,然后输入 `:e pkgs.fcitx5-rime`,会通过编辑器打开这个包的源码,然后就可以看到这个包的所有参数了。 -Through these two methods, you can see that the `fcitx5-rime` package has the following input parameters, which can all be modified by `override`: +通过上述两种方法,都可以看到 `fcitx5-rime` 这个包拥有如下输入参数,它们都是可以通过 `override` 修改的: ```nix { lib, stdenv @@ -75,9 +74,8 @@ stdenv.mkDerivation rec { } ``` -Instead of override the function's parameters, we can also override the attributes of the Derivation created by `stdenv.mkDerivation`. - -Take `pkgs.hello` as an example, first check the source code of this package through the method we mentioned earlier: +除了覆写参数,还可以通过 `overrideAttrs` 来覆写使用 `stdenv.mkDerivation` 构建的 Derivation 的属性。 +以 `pkgs.hello` 为例,首先通过前述方法查看这个包的源码: ```nix # https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/applications/misc/hello/default.nix @@ -105,7 +103,7 @@ stdenv.mkDerivation (finalAttrs: { }) ``` -The attributes showed above, such as `pname` `version` `src` `doCheck`, can all be overridden by `overrideAttrs`, for example: +其中 `pname` `version` `src` `doCheck` 等属性都是可以通过 `overrideAttrs` 来覆写的,比如: ```nix helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: { @@ -113,9 +111,9 @@ helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: { }); ``` -Here we use `overrideAttrs` to override `doCheck`, while other attributes remain their original values. +上面这个例子中,`doCheck` 就是一个新的 Derivation,它的 `doCheck` 参数被改写为 `false`,而其他参数则沿用原来的值。 -Some default attributes defined in `stdenv.mkDerivation` can also be overridden by `overrideAttrs`, for example: +除了包源码中自定义的参数值外,我们也可以通过 `overrideAttrs` 直接改写 `stdenv.mkDerivation` 内部的默认参数,比如: ```nix helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: { @@ -123,36 +121,36 @@ helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: { }); ``` -The attribute we override here, `separateDebugInfo`, is defined in `stdenv.mkDerivation`, not in the source code of `hello`. -We can check the source code of `stdenv.mkDerivation` to see all the attributes defined in it by using `nix repl ''` and then enter `:e stdenv.mkDerivation`(To learn the basic usage of `nix repl`, just type `:?` to see the help information). +具体的内部参数可以通过 `nix repl ''` 然后输入 `:e stdenv.mkDerivation` 来查看其源码。 -### 3. Overlays +### 3. Overlays {#overlays} > [Chapter 3. Overlays - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays) -The `override` we introduced previously will generate a new Derivation, which does not affect the original Derivation in `pkgs`, and is only suitable for use as a local parameter, -if you need to override a Derivation that is also depended on by other Nix packages, then other Nix packages will still use the original Derivation. +前面介绍的 override 函数都会生成新的 Derivation,不影响 pkgs 中原有的 Derivation,只适合作为局部参数使用。 +但如果你需要覆写的 Derivation 还被其他 Nix 包所依赖,那其他 Nix 包使用的仍然会是原有的 Derivation. -To solve this problem, Nix provides the ability to use `overlays`. Simply put, `overlays` can globally modify the Derivation in `pkgs`. +为了解决这个问题,Nix 提供了 overlays 能力。简单的说,Overlays 可以全局修改 pkgs 中的 Derivation。 -In the classic Nix environment, Nix automatically applies all `overlays` configuration under the paths `~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix`, -but in Flakes, in order to ensure the reproducibility of the system, it cannot depend on any configuration outside the Git repository, so this classic method cannot be used now. +在旧的 Nix 环境中,Nix 默认会自动应用 `~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix` 这类路径下的所有 overlays 配置。 -When using Flakes to write configuration for NixOS, home Manager and NixOS both provide the `nixpkgs.overlays` option to define `overlays`, related documentation: +但是在 Flakes 中,为了确保系统的可复现性,它不能依赖任何 Git 仓库之外的配置,所以这种旧的方法就不能用了。 + +在使用 Nix Flakes 编写 NixOS 配置时,Home Manager 与 NixOS 都提供了 `nixpkgs.overlays` 这个 option 来引入 overlays, 相关文档: - [home-manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.html#opt-nixpkgs.overlays) - [nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169) -For example, the following content is a Module that loads Overlays, which can be used as either a home Manager Module or a NixOS Module, because the two definitions are exactly the same: +举个例子,如下内容就是一个加载 Overlays 的 Module,它既可以用做 Home Manager Module,也可以用做 NixOS Module,因为这俩定义完全是一致的: -> home Manager is an external component after all, and most people use the unstable branch of home Manager & nixpkgs, which sometimes causes problems with home Manager Module, so it is recommended to import `overlays` in a NixOS Module. +> 不过我使用发现,Home Manager 毕竟是个外部组件,而且现在全都用的 unstable 分支,这导致 Home Manager Module 有时候会有点小毛病,因此更建议以 NixOS Module 的形式引入 overlays ```nix { config, pkgs, lib, ... }: { nixpkgs.overlays = [ - # overlayer1 - use self and super to express the inheritance relationship + # overlayer1 - 参数名用 self 与 super,表达继承关系 (self: super: { google-chrome = super.google-chrome.override { commandLineArgs = @@ -160,8 +158,8 @@ For example, the following content is a Module that loads Overlays, which can be }; }) - # overlayer2 - you can also use `extend` to inherit other overlays - # use `final` and `prev` to express the relationship between the new and the old + # overlayer2 - 还可以使用 extend 来继承其他 overlay + # 这里改用 final 与 prev,表达新旧关系 (final: prev: { steam = prev.steam.override { extraPkgs = pkgs: @@ -181,52 +179,51 @@ For example, the following content is a Module that loads Overlays, which can be }; }) - # overlay3 - define overlays in other files - # here the content of overlay3.nix is the same as above: - # `final: prev: { xxx = prev.xxx.override { ... }; }` + # overlay3 - 也可以将 overlay 定义在其他文件中 + # 这里 overlay3.nix 中的内容格式与上面的一致,都是 `final: prev: { xxx = prev.xxx.override { ... }; }` (import ./overlays/overlay3.nix) ]; } ``` -refer to this example to write your own overlays, import the configuration as a NixOS Module or a home Manager Module, and then deploy it to see the effect. +这里只是个示例配置,参照此格式编写你自己的 overlays 配置,将该配置作为 NixOS Module 或者 Home Manager Module 引入,然后部署就可以看到效果了。 -#### Modular overlays +#### 模块化 overlays 配置 -The previous example shows how to write overlays, but all overlays are written in a single nix file, which is a bit difficult to maintain. +上面的例子说明了如何编写 overlays,但是所有 overlays 都一股脑儿写在一起,就有点难以维护了,写得多了自然就希望模块化管理这些 overlays. -To resolve this problem,here is a best practice of how to manage overlays in a modular way. +这里介绍下我找到的一个 overlays 模块化管理的最佳实践。 -First, create an `overlays` folder in the Git repository to store all overlays configuration, and then create `overlays/default.nix`, whose content is as follows: +首先在 Git 仓库中创建 `overlays` 文件夹用于存放所有 overlays 配置,然后创建 `overlays/default.nix`,其内容如下: ```nix args: - # import all nix files in the current folder, and execute them with args as parameters - # The return value is a list of all execution results, which is the list of overlays + # import 当前文件夹下所有的 nix 文件,并以 args 为参数执行它们 + # 返回值是一个所有执行结果的列表,也就是 overlays 的列表 builtins.map - (f: (import (./. + "/${f}") args)) # the first parameter of map, a function that import and execute a nix file - (builtins.filter # the second parameter of map, a list of all nix files in the current folder except default.nix + (f: (import (./. + "/${f}") args)) # map 的第一个参数,是一个 import 并执行 nix 文件的函数 + (builtins.filter # map 的第二个参数,它返回一个当前文件夹下除 default.nix 外所有 nix 文件的列表 (f: f != "default.nix") (builtins.attrNames (builtins.readDir ./.))) ``` -Then you can write all overlays configuration in the `overlays` folder, an example configuration `overlays/fcitx5/default.nix` is as follows: +后续所有 overlays 配置都添加到 `overlays` 文件夹中,一个示例配置 `overlays/fcitx5/default.nix` 内容如下: ```nix -# to add my custom input method, I override the default rime-data here -# refer to https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix +# 为了不使用默认的 rime-data,改用我自定义的小鹤音形数据,这里需要 override +# 参考 https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix {pkgs, config, lib, ...}: (self: super: { - # my custom input method's rime-data, downloaded from https://flypy.com + # 小鹤音形配置,配置来自 flypy.com 官方网盘的鼠须管配置压缩包「小鹤音形“鼠须管”for macOS.zip」 rime-data = ./rime-data-flypy; fcitx5-rime = super.fcitx5-rime.override { rimeDataPkgs = [ ./rime-data-flypy ]; }; }) ``` -I custom the `rime-data` package through the overlay shown above. +我通过上面这个 overlays 修改了 fcitx5-rime 输入法的默认数据,加载了我自定义的小鹤音形输入法。 -At last, you need to load all overlays returned by `overlays/default.nix` through the `nixpkgs.overlays` option, add the following parameter to any NixOS Module to achieve this: +最后,还需要通过 `nixpkgs.overlays` 这个 option 加载 `overlays/default.nix` 返回的所有 overlays 配置,在任一 NixOS Module 中添加如下参数即可: ```nix { config, pkgs, lib, ... } @ args: @@ -234,14 +231,14 @@ At last, you need to load all overlays returned by `overlays/default.nix` throug { # ...... - # add this parameter + # 添加此参数 nixpkgs.overlays = import /path/to/overlays/dir; # ...... } ``` -For example, you can just add it directly in `flake.nix`: +比如说直接写 `flake.nix` 里: ```nix { @@ -261,8 +258,8 @@ For example, you can just add it directly in `flake.nix`: modules = [ ./hosts/nixos-test - # add the following inline module definition - # here, all parameters of modules are passed to overlays + # 添加如下内嵌 module 定义 + # 这里将 modules 的所有参数 args 都传递到了 overlays 中 (args: { nixpkgs.overlays = import ./overlays args; }) # ...... @@ -273,7 +270,7 @@ For example, you can just add it directly in `flake.nix`: } ``` -By using this modular approach, it is very convenient to modularize all your overlays. Taking my configuration as an example, the structure of the `overlays` folder is roughly as follows: +按照上述方法进行配置,就可以很方便地模块化管理所有 overlays 配置了,以我的配置为例,overlays 文件夹的结构大致如下: ```nix . @@ -284,26 +281,15 @@ By using this modular approach, it is very convenient to modularize all your ove ├── modules ├── ...... ├── overlays -│ ├── default.nix # it returns a list of all overlays. +│ ├── default.nix # 它返回一个所有 overlays 的列表 │ └── fcitx5 # fcitx5 overlay │ ├── default.nix │ ├── README.md -│ └── rime-data-flypy # my custom rime-data +│ └── rime-data-flypy # 自定义的 rime-data,需要遵循它的文件夹格式 │ └── share │ └── rime-data -│ ├── ...... # rime-data files +│ ├── ...... # rime-data 文件 └── README.md ``` - -## IV. Package Repositories of Nix - -Similar to Arch Linux, Nix also has official and community software package repositories: - -1. [nixpkgs](https://github.com/NixOS/nixpkgs) is a Git repository containing all Nix packages and NixOS modules. - 1. Its `master` branch contains the latest Nix packages and modules. - 2. The `nixos-unstable` branch contains the latest tested modules, but some bugs may still exist. - 3. And the `nixos-XX.YY` branch(the stable branch) contains the latest stable Nix packages and modules. -2. [NUR](https://github.com/nix-community/NUR) is similar to Arch Linux's AUR. - 1. NUR is a third-party Nix package repository and serves as a supplement to nixpkgs, use it at your own risk. -3. Flakes can also install software packages directly from Git repositories, which can be used to install Flakes provided by anyone, we will talk about this later. +你可以在我的配置仓库 [ryan4yin/nix-config/v0.0.4](https://github.com/ryan4yin/nix-config/tree/v0.0.4) 查看更详细的内容,获取些灵感。