With Docker or Ansible you usually get a "snapshot" of a system where you can't easily and automatically change the implementation details from outside; you would have to run some unreliable script afterwards that "fixes up" system by further mutation.
For example, let's say Ansible generates you a big nginx config, (which is a single text file) but it does not enables some setting you want, e.g. transparent gzip compression for every virtualhost.
With Ansible, you now have to use string replacement on the generated config file, which is very error prone.
With NixOS, you generate a declarative config tree from which the whole system is rendered once. You can import somebody else's nginx settings and then structurally override parts of it's config tree from your config, thus composing your config with one you use "as a library".
That includes sophisticated things like "map over all virtualhosts existent (some of which may be declared by the library) and add gzip settings to them".
In other words, all programs' text based config of various formats become a single JSON-like tree that you can apply functional programming transformations on, and this enables real composable code sharing which does not work well for Ansible or Docker.
This also makes it easy to follow updates of your base library, and apply them to your running system without having to regenerate e.g. a docker image. For example, you can easily declare "always use the latest Linux kernel but apply my custom patch", and enable auto-updates. This means you won't run at risk of vulnerabilities because your manual kernel patching disabled automatic updates, like it does for e.g. Debian pinned packages.
Overall it means it's easy to configure, customise, and update stateful systems, which self-hosting always requires.
With Docker or Ansible you usually get a "snapshot" of a system where you can't easily and automatically change the implementation details from outside; you would have to run some unreliable script afterwards that "fixes up" system by further mutation.
For example, let's say Ansible generates you a big nginx config, (which is a single text file) but it does not enables some setting you want, e.g. transparent gzip compression for every virtualhost.
With Ansible, you now have to use string replacement on the generated config file, which is very error prone.
With NixOS, you generate a declarative config tree from which the whole system is rendered once. You can import somebody else's nginx settings and then structurally override parts of it's config tree from your config, thus composing your config with one you use "as a library".
That includes sophisticated things like "map over all virtualhosts existent (some of which may be declared by the library) and add gzip settings to them".
In other words, all programs' text based config of various formats become a single JSON-like tree that you can apply functional programming transformations on, and this enables real composable code sharing which does not work well for Ansible or Docker.
This also makes it easy to follow updates of your base library, and apply them to your running system without having to regenerate e.g. a docker image. For example, you can easily declare "always use the latest Linux kernel but apply my custom patch", and enable auto-updates. This means you won't run at risk of vulnerabilities because your manual kernel patching disabled automatic updates, like it does for e.g. Debian pinned packages.
Overall it means it's easy to configure, customise, and update stateful systems, which self-hosting always requires.