{"id":37850,"date":"2022-10-05T11:01:00","date_gmt":"2022-10-05T09:01:00","guid":{"rendered":"https:\/\/www.inovex.de\/?p=37850"},"modified":"2022-11-03T08:10:37","modified_gmt":"2022-11-03T07:10:37","slug":"nix-and-nixos-for-devops","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/","title":{"rendered":"Nix and NixOS for DevOps"},"content":{"rendered":"<p>\u201cWorks on my machine\u201c has been the unhelpful answer when the CI or, even worse, production fails catastrophically. Nix, among other things, is an approach to fix this by providing reproducible, declarative, and reliable systems. This makes it a great tool for both sides of what is commonly called DevOps: the development and the process of operating systems. This post will show both with a hands-on example, but first, let&#8217;s look at what those promises exactly mean from a birds-eye perspective.<!--more--><\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_83 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Reproducible\" >Reproducible<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Declarative\" >Declarative<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Reliable\" >Reliable<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#OK-how-does-it-work\" >OK, how does it work?<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Nix-flakes\" >Nix flakes<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#A-practical-example\" >A practical example<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#The-Development-Dev\" >The Development (Dev)<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Adding-a-package\" >Adding a package<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Adding-a-shell-Ad-hoc-environments\" >Adding a shell (Ad-hoc environments)<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#The-Operation-Ops\" >The Operation (Ops)<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Configuration\" >Configuration<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Modules\" >Modules<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Deployment\" >Deployment<\/a><\/li><\/ul><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#A-note-about-Docker\" >A note about Docker<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Dockers-missing-reproducibility\" >Docker&#8217;s missing reproducibility<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Nix-Docker\" >Nix + Docker<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Nix-to-build-Docker-iamges\" >Nix to build Docker iamges<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#NixOS-to-deploy-container\" >NixOS to deploy container<\/a><\/li><\/ul><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#Further-reading\" >Further reading<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Reproducible\"><\/span>Reproducible<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Nix takes inspiration from a functional programming language, modeling the build process of packages and configuration itself as \u201cpure\u201c functions. The same inputs should always lead to the same outputs. While that sounds rather abstract, in practice this means if it runs on your notebook, it will run on the production server, the CI, or your colleague&#8217;s machine exactly the same. Nix strictly prohibits you from using undeclared dependencies, everything is pinned by a cryptographic hash, and packages are evaluated and built in isolation from each other.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Declarative\"><\/span>Declarative<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>While a simple script or other more complex tools like Ansible will tell your machine \u201cwhat to do\u201c to get to a certain state, when writing Nix code you will be \u201cdefining what something is\u201c. This is not a new concept for anyone who has done any functional programming. But while the difference is small, it is of big consequences. Declarative configuration is a big part of the reproducibility discussed above and the idempotency of deployment processes. Nix allows not only to share configuration and build instructions, but also the development and build environments for a project itself. With a few lines of code, you will be able to add a development environment with all the tools, programming languages, and pinned versions that every developer in the team will need to work on a project.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Reliable\"><\/span>Reliable<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The installation of a package should never break a different one. The same goes for upgrades between versions of the same software. Nix not only provides atomic upgrades but ensures that one package will never be able to break a different one. You even can (and often will) have multiple versions or configurations of the same package coexisting happily on the same system. Even better, you can roll back or switch between what is referred to as generations as you wish. During an upgrade, there will never be an inconsistent state, imagine installing and configuring the new version of the package alongside the old one, and when everything is ready, switching to it.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"OK-how-does-it-work\"><\/span>OK, how does it work?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>First up, a bit of terminology to avoid confusion. Nix refers to two things:<\/p>\n<ul>\n<li>The declarative package manager<\/li>\n<li>The programming language used to define packages and configuration<\/li>\n<\/ul>\n<p>NixOS on the other hand is a Linux distribution built around the Nix package manager, which uses its capabilities to define the whole system configuration.<\/p>\n<p>Nix breaks with the commonly known Linux file system hierarchy. If you ever have used it, you will have stumbled upon a pretty big directory under <code>\/nix\/store<\/code> with a lot of cryptically named paths in it. This is the so-called Nix store, where Nix stores all packages in its own unique subdirectory, such as:<\/p>\n<pre class=\"lang:default decode:true\">\/nix\/store\/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1\/<\/pre>\n<p>Throwing everything into one big directory might sound counter-intuitive but this is actually the concept that enables most of the magic of Nix. Every store path has the same structure:<\/p>\n<pre class=\"lang:default decode:true \">\/nix\/store\/&lt;hash&gt;-&lt;name&gt;-&lt;version&gt;<\/pre>\n<p>Where the hash is a unique identifier calculated from all the package&#8217;s dependencies (to be precise: a cryptographic hash of the package&#8217;s build dependency graph).<\/p>\n<p><em>But&#8230; why?<\/em><\/p>\n<p>This very simple structure allows for a lot of desirable features. First of all, the same path will have the exact same contents. This is our first step in ensuring reproducibility. It also ensures the files will not have been tampered with without you knowing, as the hash verifies the content mathematically.<\/p>\n<p>You can now have multiple versions of the same package all at once. They will have different hashes and thus lie in different paths in the store. Instead of dependency version conflicts between packages (i.e. \u201cDLL-hell\u201c), every package can reference and use its own desired version.<\/p>\n<p>An important consequence is that operations like upgrading or uninstalling an application cannot break other applications, since these operations never \u201cdestructively\u201c update or delete files that are used by other packages. This enables us to have what is referred to as atomic upgrades and rollbacks.<\/p>\n<p>Getting rid of global locations like <code>\/usr\/lib<\/code>\u00a0on a traditional Linux system ensures no hidden dependencies that are not specified in the package. If it builds on one system, it will build on a different one regardless of what other software is installed.<\/p>\n<p>In practice, packages are built from Nix (language) expressions. From here, Nix computes a derivation. This is best described as a \u201cbuild action\u201c, a complete specification of all dependencies, tools, environment variables, sources, and steps needed to build a certain package. Derivations are independent of programming languages and deterministic.<\/p>\n<p>Having every package and part of your system strictly identified by a hash also allows for powerful caching. When instructed to build<\/p>\n<pre class=\"lang:default decode:true\">\/nix\/store\/b6gvzjyb2pg0...-firefox-33.1<\/pre>\n<p>from the source, Nix would first check if it already exists in the store or any of the configured caches and pull it from there if already present. In practice, building from source becomes a mere fallback for commonly used packages.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Nix-flakes\"><\/span>Nix flakes<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Flakes are a newer feature of Nix, best described as \u201ca mechanism to package Nix expressions into composable entities\u201c. In practice, a flake is a file system tree (typically fetched from a Git repository or a tarball) that contains a file named flake.nix in the root directory.<\/p>\n<p>They are a standardized interface to split and distribute Nix code and make reuse and composition easy. We will use this format for the following sections and build your <code>flake.nix<\/code> file step by step further explaining on the way.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"A-practical-example\"><\/span>A practical example<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>With all that out of the way, let&#8217;s see how Nix is used in practice. The following example will demonstrate the DevOps process of building (the \u201cDev\u201c in DevOps) and deploying (the \u201cOps\u201c in DevOps) an example Go application using Nix everywhere we can.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The-Development-Dev\"><\/span>The Development (Dev)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>For the \u201cDev\u201c part, let&#8217;s first present our example application. A very simple web server written in go. It is assumed we are using Go modules, i.e., have run <code>go mod init<\/code> and <code>go mod tidy<\/code> to create a <code>go.mod<\/code> and <code>go.sum<\/code> file for our application.package main<\/p>\n<pre class=\"lang:go decode:true\">import (\r\n  \"fmt\"\r\n  \"net\/http\"\r\n)\r\n\r\nfunc hello(w http.ResponseWriter, req *http.Request) {\r\n  fmt.Fprintf(w, \"Hello World!\\n\")\r\n}\r\n\r\nfunc main() {\r\n  http.HandleFunc(\"\/\", hello)\r\n  http.ListenAndServe(\":8080\", nil)\r\n}\r\n<\/pre>\n<p>In its simplest form, a flake is an attribute set that defines the attribute&#8217;s <code>outputs<\/code> and (optionally) <code>inputs<\/code> and <code>description<\/code>. Inputs are the sources or dependencies used in the flake, in most cases git repositories or plain URLs to fetch from. Outputs are commonly packages, deployment instructions, configuration or Nix code (functions) to be used in other flakes. While the outputs attribute set can have any form you want, there are standardized names for common outputs.<\/p>\n<p>To \u201cnixify\u201c our project, let&#8217;s start by adding a file called <code>flake.nix<\/code>\u00a0to the root of the repository, with a very basic flake:<\/p>\n<pre class=\"lang:default decode:true\">{\r\n  description = \"A very basic flake\";\r\n\r\n  inputs = {\r\n    nixpkgs.url = \"github:nixos\/nixpkgs\";\r\n  };\r\n\r\n  outputs = { self, nixpkgs }: { };\r\n}<\/pre>\n<p>Our flake defines <code>github.com\/nixos\/nixpkgs<\/code> as an input and has no outputs for now. While it is not very useful yet, it is functional. We can use <code>nix flake metadata<\/code>\u00a0to display some information about it.<\/p>\n<pre class=\"lang:default decode:true\">\u276f nix flake metadata\r\nResolved URL: git+file:\/\/\/home\/pinpox\/code\/example_app\r\nLocked URL: git+file:\/\/\/home\/pinpox\/code\/example_app\r\nDescription: A very basic flake\r\nPath: \/nix\/store\/c4vxaphd27qjl253m5lmqrb3isg9rc5h-source\r\nLast modified: 2022-05-30 12:09:33\r\nInputs:\r\n\u2514\u2500\u2500\u2500nixpkgs: github:nixos\/nixpkgs\/0907dc851fa2e56db75ae260a8ecc9880dc7b49\r\n<\/pre>\n<p>If not already present, this will also create a <code>flake.lock<\/code> file for us, pinning all our inputs to a specific version, verified by a hash of the input.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Adding-a-package\"><\/span>Adding a package<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>With the basic boilerplate done, we can add our first output: A package for our application.<\/p>\n<pre class=\"lang:default decode:true \">packages.x86_64-linux = {\r\n  default = pkgs.buildGoModule {\r\n    pname = \"example_app\";\r\n    version = \"1.0.0\";\r\n    src = .\/.;\r\n    vendorSha256 = \"sha256-aCFVUq58hpK7O9DoYJ\/7Sr4ICSUzz\/JHNrse40um1n4=\";\r\n  };\r\n};<\/pre>\n<p>The above specifies how our application is to be built on Linux systems with <code>x64_64<\/code> system architecture. We could use the generic <code>mkDerivation<\/code> function to define our package (derivation), but Nix includes helper functions for most common programming languages and frameworks. Here <code>buildGoModule<\/code> is used to define the package for our Golang project, specifying the source to be the current directory <code>.\/.<\/code>, a name, version, and the hash of the dependencies specified in our <code>go.mod<\/code> file, since all versions have to be pinned with a hash.<\/p>\n<p>We can now use <code>nix build<\/code> to build our application. This will build our application and create a symbolic link called <code>result<\/code> pointing to it in the nix store.<\/p>\n<pre class=\"lang:default decode:true\">\u276f ls -l\r\nlrwxrwxrwx 61 pinpox 7 Jun 16:17 result -&gt; \/nix\/store\/0yasl97rl4drf9rgmbaqbcbii0rsizsi-example_app-1.0.0\r\n.rwxr-xr-x 6,2M pinpox 7 Jun 16:06 example_app\r\n.rw-r--r-- 534 pinpox 7 Jun 15:44 flake.lock\r\n.rw-r--r-- 571 pinpox 7 Jun 16:08 flake.nix\r\n.rw-r--r-- 80 pinpox 7 Jun 15:20 go.mod\r\n.rw-r--r-- 189 pinpox 7 Jun 15:20 go.sum\r\n.rw-r--r-- 415 pinpox 7 Jun 15:22 main.go\r\n<\/pre>\n<p>Okay, but we could have saved ourselves the hassle and just used <code>go build<\/code> to get the same thing, right? Well, not quite.<\/p>\n<p>Nix and especially flakes promise us a hermetic evaluation, meaning everything needed to build our application is pinned to a specific version and verified using a checksum. This includes the code of the app itself, but also the compiler used, any other dependencies, tools, and packages used, and the system architecture itself. Not only does that ensure our app will not break because of external factors, but it will also build on any machine. Be it a coworker&#8217;s notebook, CI, or production, there are no more \u201cworks (only) on my machine\u201c. Since Nix is language-agnostic and not specific to go, we also have a common interface for building software in any language. The process for building and running (<code>nix run<\/code>) a nixified go application stays the same.<\/p>\n<p>It should be noted explicitly that none of the prerequisites like a go compiler or any other tools (apart from Nix itself) need to be installed on the system before we can build or run the application with Nix. Nix will create the complete environment specified by the flake. Inputs will be fetched on the first run and subsequently checked from there on with the hash to ensure a deterministic build while caching as much as possible.<\/p>\n<h4><\/h4>\n<h4><span class=\"ez-toc-section\" id=\"Adding-a-shell-Ad-hoc-environments\"><\/span>Adding a shell (Ad-hoc environments)<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>While the package definition already allows us to build and run our application, it is not really suited for development. By adding a Nix shell to the outputs we can create a development environment with all the tools in their specific versions that all developers can use. Instead of every developer wasting time on setting up a tech stack for a new project, we can pass around a shell with all tools needed to work on it available in their specified version.<\/p>\n<p>Since the requirements for our project are all already packaged in nixpkgs we can add a simple shell with the following lines in our outputs:<\/p>\n<pre class=\"lang:default decode:true\">devShell.x86_64-linux = pkgs.mkShell {\r\n  buildInputs = with pkgs; [\r\n    go\r\n    gopls\r\n    gotools\r\n    go-tools\r\n  ];\r\n\r\n  shellHook = ''\r\n    GOPATH=$HOME\/go\r\n  '';\r\n};\r\n<\/pre>\n<p>Now,\u00a0<code>nix flake show<\/code> will show us two outputs: our previously specified package and the newly added shell.<\/p>\n<pre class=\"lang:default decode:true \">\u276f nix flake show\r\ngit+file:\/\/\/home\/pinpox\/code\/example_app\r\n\u251c\u2500\u2500\u2500devShell\r\n\u2502 \u2514\u2500\u2500\u2500x86_64-linux: development environment 'nix-shell'\r\n\u2514\u2500\u2500\u2500packages\r\n\u2514\u2500\u2500\u2500x86_64-linux\r\n\u2514\u2500\u2500\u2500default: package 'example_app-1.0.0'<\/pre>\n<p>We can enter the shell by running <code>nix develop<\/code> and will be dropped into a shell<br \/>\nwith all tools we need available.<\/p>\n<pre class=\"lang:default decode:true\">\u276f nix develop\r\n[pinpox@ahorn:~\/code\/example_app]$ go version\r\ngo version go1.17.10 linux\/amd64<\/pre>\n<p>In this example, we have only used tools and dependencies available prepackaged in <code>nixpkgs<\/code>. It is of course possible to specify tools outside of <code>nixpkgs<\/code> or to override specific versions of packages. This can be archived by either adding your own package definitions or using <code>overrides<\/code> and <a href=\"https:\/\/nixos.org\/manual\/nixpkgs\/stable\/#chap-overlays\">overlays<\/a>) to modify the existing ones on the fly. The tools specified in <code>buildInputs<\/code> of our shell are of course pinned to a version as well since our <code>nixpkgs<\/code> input is pinned in the flake.lock file to a specific git commit.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The-Operation-Ops\"><\/span>The Operation (Ops)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Until now, we have only used Nix, the package manager, which is as stated in the beginning, a separate tool. For the operations part, let&#8217;s take a NixOS, the Linux distribution, which takes the Nix principles and applies them to the complete system configuration. The core idea is simple and just a natural extension of what we have seen with Nix already: In the same manner as our packages are stored in isolated paths like <code>\/nix\/store\/5rnfzla9kcx4mj5zdc7nlnv8na1najvg-firefox-3.5.4\/<\/code> in the store, let&#8217;s also apply that to configuration. For example, the configuration for an SSH server could be defined in the Nix language and stored in a path like <code>\/nix\/store\/s2sjbl85xnrc18rl4fhn56irkxqxyk4p-sshd_config<\/code> after evaluating it.<\/p>\n<p>This results in the complete operating system making use of the benefits we saw with packages: It&#8217;s isolated, can be rolled back, and will not change without notice as everything is once again verified by the hash.<\/p>\n<p>The <code>nixos-rebuild<\/code> tool is used to perform these operations. To switch to a new configuration:<\/p>\n<pre class=\"lang:default decode:true\">nixos-rebuild switch<\/pre>\n<p>After every build of the configuration, you get what is referred to as a generation. This is the point to which you can switch or roll back to. In the same way, if something goes wrong or does not work as expected<\/p>\n<pre class=\"lang:default decode:true\">nixos-rebuild switch --rollback\r\n<\/pre>\n<p>will bring you to the generation before. At boot, you can select any generation you have saved.<\/p>\n<p>To clarify the extent, NixOS is completely built around the Nix package manager. It&#8217;s used to build the kernel, applications, system packages, and configuration files in a purely functional language. This results in atomic system upgrades and the ability to roll back the full system, among other things. Furthermore, the system is completely reproducible, which makes re-installation or replication easy. Another example:<\/p>\n<pre class=\"lang:default decode:true\">$ nixos-rebuild build-vm\r\n$ .\/result\/bin\/run-*-vm<\/pre>\n<p>will build your system configuration inside a virtual machine and start it. The VM will have the same configuration as your host system itself, allowing you to test, experiment, and \u201cpreview\u201c as you like without risking breaking the host.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Configuration\"><\/span>Configuration<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>The system configuration is usually defined in a file called <code>configuration.nix<\/code><\/p>\n<p>A very simple example could look like this:<\/p>\n<pre class=\"lang:default decode:true\">{\r\n    boot.loader.grub.device = \"\/dev\/sda\";\r\n    fileSystems.\"\/\".device = \"\/dev\/sda1\";\r\n    services.sshd.enable = true;\r\n}<\/pre>\n<p>This minimal configuration is enough to build a machine with a running SSH daemon. When using flake, we will also add the configuration to our <code>flake.nix<\/code> flake under the <code>nixosConfiguration<\/code>\u00a0output.<\/p>\n<pre class=\"lang:default decode:true\">{\r\n  outputs = { self, nixpkgs }: {\r\n    # replace 'my-hostname' with your hostname here.\r\n    nixosConfigurations.my-hostname = nixpkgs.lib.nixosSystem {\r\n      system = \"x86_64-linux\";\r\n      modules = [ .\/configuration.nix ];\r\n    };\r\n  };\r\n}<\/pre>\n<p>Then pass the flake to the <code>nixos-rebuild<\/code> command<\/p>\n<pre class=\"lang:default decode:true\">nixos-rebuild switch --flake '\/path\/to\/flake#my-hostname'\r\n<\/pre>\n<h4><span class=\"ez-toc-section\" id=\"Modules\"><\/span>Modules<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>All options you are able to set in your system configuration, come from modules which are files containing NixOS expressions. The <code>configuration.nix<\/code> file is also a module. Most other modules are in the <a href=\"https:\/\/github.com\/NixOS\/nixpkgs\/tree\/master\/nixos\/modules\" target=\"_blank\" rel=\"noopener\">nixpkgs repository<\/a>. Modules are files that are then combined by NixOS to produce the full system configuration.<\/p>\n<p>It is outside the scope of this post to explain the module system in its entirety, so let&#8217;s focus on a practical example for our application from above. We will add a module for it to your <code>flake.nix<\/code> file so that anyone can just import it, resulting in a running instance of your application.<\/p>\n<p>The module will have only one option called \u201cenable\u201c, which when set to true will add the part under <code>config=<\/code> to the system&#8217;s configuration. This is the full module saved in <code>module.nix<\/code>:<\/p>\n<pre class=\"lang:default decode:true\">{ lib, pkgs, config, ... }:\r\nwith lib;\r\nlet\r\n  cfg = config.services.hello;\r\nin\r\n{\r\n  options.services.hello = {\r\n    enable = mkEnableOption \"hello service\";\r\n  };\r\n\r\n  config = mkIf cfg.enable {\r\n    systemd.services.hello = {\r\n      wantedBy = [ \"multi-user.target\" ];\r\n      serviceConfig.ExecStart = \"${pkgs.hello}\/bin\/hello -g'Hello, ${escapeShellArg cfg.greeter}!'\";\r\n    };\r\n  };\r\n}\r\n<\/pre>\n<p>To import it, just add it to the <code>nixosConfigurations<\/code> output the same way we added the <code>configuration.nix<\/code> file:<\/p>\n<pre class=\"lang:default decode:true \">modules = [ .\/configuration.nix .\/module.nix ];\r\n<\/pre>\n<p>The module creates a systemd unit running our application. Commonly you would also add configuration for a reverse-proxy here, as well as environment variables, other dependent applications and settings, users, groups, and other properties that should be present when our application is running.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Deployment\"><\/span>Deployment<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Assuming we have a running NixOS host with SSH access, we can deploy your configuration<\/p>\n<pre class=\"lang:default decode:true\">nixos-rebuild build --flake '.#my-hostname' --target-host root@our.host.tld\r\n<\/pre>\n<p>And voil\u00e0, our application is running!<\/p>\n<h2><span class=\"ez-toc-section\" id=\"A-note-about-Docker\"><\/span>A note about Docker<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>When introducing to nix, a recurring question is: \u201cWhat about docker?\u201c While Nix and Docker are essentially tools for different things, it is unquestionable that people (ab)use both to solve overlapping problems.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Dockers-missing-reproducibility\"><\/span>Docker&#8217;s missing reproducibility<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In regard to reproducible environments, Docker <strong>images<\/strong> can be used to archive something similar. Note, that specifically build images are meant, as a Dockerfile or container definition is <em>not<\/em> reproducible. This can be easily confirmed by building an image multiple times and comparing its checksum.<\/p>\n<pre class=\"lang:default decode:true\">docker save $(docker build --no-cache -q .) -o img1.tar\r\ndocker save $(docker build --no-cache -q .) -o img2.tar\r\n\r\nsha256sum img1.tar\r\nb830edb19a8653ef6ef5846a115b7ab90fdd8ce828a072c3698b21f13429e8c7 img1.tar\r\n\r\nsha256sum img2.tar\r\nc07301820e59aefad9b36feeca4c0da911e88b56b56a083fdea8d1763bd0c5f3 img2.tar<\/pre>\n<p>This can be attributed to multiple factors, e.g., Dockerfile commands<\/p>\n<p>What is \u201clatest\u201c in this expression?<\/p>\n<pre class=\"lang:default decode:true\">FROM ubuntu:latest<\/pre>\n<p>Which version of python will get installed when running this code?<\/p>\n<pre class=\"lang:default decode:true\">RUN apt-get update &amp;&amp; apt-get install python -y<\/pre>\n<p>Which of possibly multiple entries in <code>$PATH<\/code> will get run?<\/p>\n<pre class=\"lang:default decode:true\">CMD [ \"somebin\" ]<\/pre>\n<p>There are workarounds for some of these problems, but Docker (or more specifically Dockerfile) is not built to be reproducible in the first place and there are many real-world examples of image building today but not in a few months&#8216; time.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Nix-Docker\"><\/span>Nix + Docker<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>But the question does not need to be one or the other. In fact, Nix and Docker are used together and can complement each other perfectly.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Nix-to-build-Docker-iamges\"><\/span>Nix to build Docker iamges<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Nix can be used to build docker images. Nix provides multiple utility functions like <code>pkgs.dockerTools.buildImage<\/code> and <code>pkgs.dockerTools.buildLayeredImage<\/code> that can be used to build docker images as flake output, just like any other package. A recent lightning talk about its use was recently given by <a href=\"https:\/\/www.youtube.com\/watch?v=0uixRE8xlbY\" target=\"_blank\" rel=\"noopener\">Matthew Croughan at MCH2022.<\/a><\/p>\n<p>It can also be used for more fine-grained optimization for caching of Docker layers as detailed by <a href=\"https:\/\/grahamc.com\/blog\/nix-and-layered-docker-images\" target=\"_blank\" rel=\"noopener\">Graham Christensen.<\/a><\/p>\n<h4><span class=\"ez-toc-section\" id=\"NixOS-to-deploy-container\"><\/span>NixOS to deploy container<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>NixOS provides a very elegant way of running containers. This is an example of running configuring NixOS to run a container<\/p>\n<pre class=\"lang:default decode:true \">virtualisation.oci-containers.containers = {\r\n  bitwardenrs = {\r\n    autoStart = true;\r\n    image = \"bitwardenrs\/server:latest\";\r\n    environment = {\r\n      ADMIN_TOKEN = \"myAdminTokenString\";\r\n      DOMAIN = \"https:\/\/pw.mydomain.com\";\r\n      INVITATIONS_ALLOWED = \"true\";\r\n      SIGNUPS_ALLOWED = \"true\";\r\n    };\r\n    ports = [\r\n      \"80:80\"\r\n    ];\r\n    volumes = [\r\n      \"\/var\/docker\/bitwarden\/:\/data\/\"\r\n    ];\r\n  };\r\n};\r\n<\/pre>\n<p>It will set up everything needed to run the container and generate matching systemd units to start, stop and manage it. All pinned by hashes.<\/p>\n<p>Using Nix and NixOS in combination with container runtimes is a topic too broad to cover in its entirety here and the examples above only are able to scratch the surface of what is possible.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Further-reading\"><\/span>Further reading<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>This only scratches the surface of what is possible with Nix and NixOS. There are multiple layers of abstraction above and below and tools to simplify the usage and configuration. Deployment tools to manage a large number of hosts like <a href=\"https:\/\/github.com\/NixOS\/nixops\" target=\"_blank\" rel=\"noopener\">nixOps<\/a> or <a href=\"https:\/\/github.com\/pinpox\/lollypops\" target=\"_blank\" rel=\"noopener\">lollypops<\/a>, secrets management like <a href=\"https:\/\/github.com\/Mic92\/sops-nix\" target=\"_blank\" rel=\"noopener\">sops-nix<\/a> or <a href=\"https:\/\/github.com\/ryantm\/agenix\" target=\"_blank\" rel=\"noopener\">agenix<\/a> and CI systems like <a href=\"https:\/\/hydra.nixos.org\/\" target=\"_blank\" rel=\"noopener\">Hydra<\/a>. Nix plays nicely with <a href=\"https:\/\/nixos.org\/manual\/nixos\/stable\/#ch-containers\" target=\"_blank\" rel=\"noopener\">containers<\/a> and its ecosystem is constantly growing and evolving with 2,981 Pull requests merged by 534 people in the last month alone.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u201cWorks on my machine\u201c has been the unhelpful answer when the CI or, even worse, production fails catastrophically. Nix, among other things, is an approach to fix this by providing reproducible, declarative, and reliable systems. This makes it a great tool for both sides of what is commonly called DevOps: the development and the process [&hellip;]<\/p>\n","protected":false},"author":305,"featured_media":38737,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[66],"service":[420,432],"coauthors":[{"id":305,"display_name":"Pablo Ovelleiro Corral","user_nicename":"povelleiro-corral"}],"class_list":["post-37850","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-devops","service-apps","service-devops"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Nix and NixOS for DevOps - inovex GmbH<\/title>\n<meta name=\"description\" content=\"Nix, among other things, is an approach to fix this by providing reproducible, declarative and reliable systems.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Nix and NixOS for DevOps - inovex GmbH\" \/>\n<meta property=\"og:description\" content=\"Nix, among other things, is an approach to fix this by providing reproducible, declarative and reliable systems.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2022-10-05T09:01:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-11-03T07:10:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Pablo Ovelleiro Corral\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops-1024x576.png\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Pablo Ovelleiro Corral\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"18\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Pablo Ovelleiro Corral\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/\"},\"author\":{\"name\":\"Pablo Ovelleiro Corral\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/person\\\/57ecdcdb8757fb6087436556e2462d2c\"},\"headline\":\"Nix and NixOS for DevOps\",\"datePublished\":\"2022-10-05T09:01:00+00:00\",\"dateModified\":\"2022-11-03T07:10:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/\"},\"wordCount\":2834,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/nix-and-nixos-for-devops.png\",\"keywords\":[\"DevOps\"],\"articleSection\":[\"Applications\",\"English Content\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/\",\"name\":\"Nix and NixOS for DevOps - inovex GmbH\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/nix-and-nixos-for-devops.png\",\"datePublished\":\"2022-10-05T09:01:00+00:00\",\"dateModified\":\"2022-11-03T07:10:37+00:00\",\"description\":\"Nix, among other things, is an approach to fix this by providing reproducible, declarative and reliable systems.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/nix-and-nixos-for-devops.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/nix-and-nixos-for-devops.png\",\"width\":1920,\"height\":1080,\"caption\":\"the nix logo arranged in a devops infinity loop\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/nix-and-nixos-for-devops\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Nix and NixOS for DevOps\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#website\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/inovexde\",\"https:\\\/\\\/x.com\\\/inovexgmbh\",\"https:\\\/\\\/www.instagram.com\\\/inovexlife\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/inovex\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/person\\\/57ecdcdb8757fb6087436556e2462d2c\",\"name\":\"Pablo Ovelleiro Corral\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b71de2f92353c36e6e182c68c80f38bf3ea553a111002268d31d947f582086ab?s=96&d=retro&r=ge2557653d8386189090c9da419e52536\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b71de2f92353c36e6e182c68c80f38bf3ea553a111002268d31d947f582086ab?s=96&d=retro&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b71de2f92353c36e6e182c68c80f38bf3ea553a111002268d31d947f582086ab?s=96&d=retro&r=g\",\"caption\":\"Pablo Ovelleiro Corral\"},\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/author\\\/povelleiro-corral\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Nix and NixOS for DevOps - inovex GmbH","description":"Nix, among other things, is an approach to fix this by providing reproducible, declarative and reliable systems.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/","og_locale":"de_DE","og_type":"article","og_title":"Nix and NixOS for DevOps - inovex GmbH","og_description":"Nix, among other things, is an approach to fix this by providing reproducible, declarative and reliable systems.","og_url":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2022-10-05T09:01:00+00:00","article_modified_time":"2022-11-03T07:10:37+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops.png","type":"image\/png"}],"author":"Pablo Ovelleiro Corral","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops-1024x576.png","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Pablo Ovelleiro Corral","Gesch\u00e4tzte Lesezeit":"18\u00a0Minuten","Written by":"Pablo Ovelleiro Corral"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/"},"author":{"name":"Pablo Ovelleiro Corral","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/57ecdcdb8757fb6087436556e2462d2c"},"headline":"Nix and NixOS for DevOps","datePublished":"2022-10-05T09:01:00+00:00","dateModified":"2022-11-03T07:10:37+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/"},"wordCount":2834,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops.png","keywords":["DevOps"],"articleSection":["Applications","English Content","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/","url":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/","name":"Nix and NixOS for DevOps - inovex GmbH","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops.png","datePublished":"2022-10-05T09:01:00+00:00","dateModified":"2022-11-03T07:10:37+00:00","description":"Nix, among other things, is an approach to fix this by providing reproducible, declarative and reliable systems.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/nix-and-nixos-for-devops.png","width":1920,"height":1080,"caption":"the nix logo arranged in a devops infinity loop"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/nix-and-nixos-for-devops\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Nix and NixOS for DevOps"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/57ecdcdb8757fb6087436556e2462d2c","name":"Pablo Ovelleiro Corral","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/b71de2f92353c36e6e182c68c80f38bf3ea553a111002268d31d947f582086ab?s=96&d=retro&r=ge2557653d8386189090c9da419e52536","url":"https:\/\/secure.gravatar.com\/avatar\/b71de2f92353c36e6e182c68c80f38bf3ea553a111002268d31d947f582086ab?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b71de2f92353c36e6e182c68c80f38bf3ea553a111002268d31d947f582086ab?s=96&d=retro&r=g","caption":"Pablo Ovelleiro Corral"},"url":"https:\/\/www.inovex.de\/de\/blog\/author\/povelleiro-corral\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/37850","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/305"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=37850"}],"version-history":[{"count":5,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/37850\/revisions"}],"predecessor-version":[{"id":39127,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/37850\/revisions\/39127"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/38737"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=37850"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=37850"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=37850"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=37850"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}