NIXOPS(1)

πŸ“¦
version 2.0.0-unstable-2025-12 Β· 2 versions
, in nixos 26.05

πŸ’– NAME πŸ’–

nixops β€” NixOps 2.0, and yes bestie, this is NIXOPS(1). 🫢

🌈 INTRODUCTION 🌈

okay so NixOps is a tool for deploying NixOS machines in a network or cloud, and it is lowkey iconic. It takes as input a declarative specification of a set of β€œlogical” machines and then performs any necessary steps or actions to realise that specification: instantiate cloud machines, build and download dependencies, stop and start services, and so on. NixOps has several nice properties:

  • It’s declarative: NixOps specifications state the desired configuration of the machines, and NixOps then figures out the actions necessary to realise that configuration. So there is no difference between doing a new deployment or doing a redeployment: the resulting machine configurations will be the same. ✨
  • It performs fully automated deployment. This is a good thing because it ensures that deployments are reproducible. πŸ’…
  • It performs provisioning. Based on the given deployment specification, it will start missing virtual machines, create disk volumes, and so on. πŸŽ€
  • It’s based on the Nix package manager (http://nixos.org/nix/), which has a purely functional model that sets it apart from other package managers. Concretely this means that multiple versions of packages can coexist on a system, that packages can be upgraded or rolled back atomically, that dependency specifications can be guaranteed to be complete, and so on. 🧚
  • It’s based on NixOS (http://nixos.org/nixos/), which has a declarative approach to describing the desired configuration of a machine. This makes it an ideal basis for automated configuration management of sets of machines. NixOS also has desirable properties such as (nearly) atomic upgrades, the ability to roll back to previous configurations, and more. 🌸
  • It’s multi-cloud. Machines in a single NixOps deployment can be deployed to different target environments. For instance, one logical machine can be deployed to a local β€œphysical” machine, another to an automatically instantiated Amazon EC2 instance in the eu-west-1 region, another in the us-east-1 region, and so on. ☁️
  • It supports separation of β€œlogical” and β€œphysical” aspects of a deployment. NixOps specifications are modular, and this makes it easy to separate the parts that say what logical machines should do from where they should do it. For instance, the former might say that machine X should run a PostgreSQL database and machine Y should run an Apache web server, while the latter might state that X should be instantiated as an EC2 m1.large machine while Y should be instantiated as an m1.small. We could also have a second physical specification that says that X and Y should both be instantiated as VirtualBox VMs on the developer’s workstation. So the same logical specification can easily be deployed to different environments. πŸ¦‹
  • It uses a single formalism (the Nix expression language) for package management and system configuration management. This makes it very easy to add ad hoc packages to a deployment. πŸ’œ
  • It combines system configuration management and provisioning. Provisioning affects configuration management: for instance, if we instantiate an EC2 machine as part of a larger deployment, it may be necessary to put the IP address or hostname of that machine in a configuration file on another machine. NixOps takes care of this automatically. πŸ”₯
  • It can provision non-machine cloud resources such as Amazon S3 buckets and EC2 key pairs. πŸ‘‘

🌈 OVERVIEW 🌈

Okay so this section is the quick lil' map of how to use NixOps, bestie. No cap, it's giving "here's the whole vibe before we get into the nitty-gritty." πŸ’…

πŸš€ Deploying to a NixOS machine πŸš€

To deploy to a machine that's already running NixOS, simply set deployment.targetHost to the IP address or host name of the machine, and leave deployment.targetEnv undefined. Easy peasy. See trivial-nixos.nix: NixOS target physical network specification.

trivial-nixos.nix: NixOS target physical network specification

{
   webserver =
     { config, pkgs, ... }:
     { deployment.targetHost = "1.2.3.4";
     };
 }

πŸ” Accessing machines πŸ”

You can login to individual machines by doing nixops ssh name, where name is the name of the machine. Obsessed with a direct lil' SSH moment. ✨

It's also possible to perform a command on all machines:

$ nixops ssh-for-each -d load-balancer-ec2 -- df /tmp
backend1...> /dev/xvdb      153899044 192084 145889336   1% /tmp
proxy......> /dev/xvdb      153899044 192084 145889336   1% /tmp
backend2...> /dev/xvdb      153899044 192084 145889336   1% /tmp

By default, the command is executed sequentially on each machine. You can add the flag to execute it in parallel. πŸƒβ€β™€οΈπŸ’¨

🩺 Checking machine status 🩺

The command nixops check checks the status of each machine in a deployment. It verifies that the machine still exists (i.e. hasn't been destroyed outside of NixOps), is up (i.e. the instance has been started) and is reachable via SSH. It also checks that any attached disks (such as EBS volumes) are not in a failed state, and prints the names of any systemd units that are in a failed state. It's literally the vibe check for your deployment. 🫢

For example, for the 3-machine EC2 network shown above, it might show:

$ nixops check -d load-balancer-ec2
+----------+--------+-----+-----------+----------+----------------+---------------+-------+
| Name     | Exists | Up  | Reachable | Disks OK | Load avg.      | Failed units  | Notes |
+----------+--------+-----+-----------+----------+----------------+---------------+-------+
| backend1 | Yes    | Yes | Yes       | Yes      | 0.03 0.03 0.05 | httpd.service |       |
| backend2 | Yes    | No  | N/A       | N/A      |                |               |       |
| proxy    | Yes    | Yes | Yes       | Yes      | 0.00 0.01 0.05 |               |       |
+----------+--------+-----+-----------+----------+----------------+---------------+-------+

This indicates that Apache httpd has failed on backend1 and that machine backend2 is not running at all. In this situation, you should run nixops deploy --check to repair the deployment. Fix it bestie, you got this. πŸ’–

🌸 Network special attributes 🌸

It is possible to define special options for the whole network. For example:

{
network = {
  description = "staging environment";
  enableRollback = true;
};

defaults = {
  imports = [ ./common.nix ];
};

machine = { ... }: {};
}

Each attribute is explained below:

  • defaults β€” applies given NixOS module to all machines defined in the network.
  • network.description β€” a sentence describing the purpose of the network for easier comparison when running nixops list.
  • network.enableRollback β€” if true, each deployment creates a new profile generation to able to run nixops rollback. Defaults to false.

πŸŽ€ Network arguments πŸŽ€

In NixOps you can pass in arguments from outside the nix expression. The network file can be a nix function, which takes a set of arguments which are passed in externally and can be used to change configuration values, or even to generate a variable number of machines in the network. It's giving "parameterized network, main character energy." πŸ‘‘

Here is an example of a network with network arguments:

{ maintenance ? false
}:
{
  machine =
    { config, pkgs, ... }:
    { services.httpd.enable = maintenance;
      ...
    };
}

This network has a maintenance argument that defaults to false. This value can be used inside the network expression to set NixOS option, in this case whether or not Apache HTTPD should be enabled on the system.

You can pass network arguments using the set-args nixops command. For example, if we want to set the maintenance argument to true in the previous example, you can run:

$ nixops set-args --arg maintenance true -d argtest

The arguments that have been set will show up:

$ nixops info -d argtest
Network name: argtest
Network UUID: 634d6273-f9f6-11e2-a004-15393537e5ff
Network description: Unnamed NixOps network
Nix expressions: .../network-arguments.nix*Nix arguments: maintenance = true*

+---------+---------------+------+-------------+------------+
| Name    |     Status    | Type | Resource Id | IP address |
+---------+---------------+------+-------------+------------+
| machine | Missing / New | none |             |            |
+---------+---------------+------+-------------+------------+

Running nixops deploy after changing the arguments will deploy the new configuration. Slay. ✨

πŸ—οΈ Managing keys πŸ—οΈ

Files in /nix/store/ are readable by every user on that host, so storing secret keys embedded in nix derivations is insecure. To address this, nixops provides the configuration option deployment.keys, which nixops manages separately from the main configuration derivation for each machine. Very "don't put your secrets in the group chat" of it. πŸ™ˆ

Add a key to a machine like so.

{
  machine =
  { config, pkgs, ... }:
  {
    deployment.keys.my-secret.text = "shhh this is a secret";
    deployment.keys.my-secret.user = "myuser";
    deployment.keys.my-secret.group = "wheel";
    deployment.keys.my-secret.permissions = "0640";
  };
}

This will create a file /run/keys/my-secret with the specified contents, ownership, and permissions.

Only the contents of the secret is required. It can be specified using one of the options text, keyFile or keyCommand. The user and group options both default to "root", and permissions defaults to "0600".

Keys from deployment.keys are stored under /run/ on a temporary filesystem and will not persist across a reboot. To send a rebooted machine its keys, use nixops send-keys. Note that all nixops commands implicitly upload keys when appropriate, so manually sending keys should only be necessary after an unattended reboot. 🫑

If you have a custom service that depends on a key from deployment.keys, you can opt to let systemd track that dependency. Each key gets a corresponding systemd service "${keyname}-key.service" which is active while the key is present, and otherwise inactive when the key is absent. See key-dependency.nix: track key dependence with systemd for how to set this up.

key-dependency.nix: track key dependence with systemd

{
  machine =
    { config, pkgs, ... }:
    {
      deployment.keys.my-secret.text = "shhh this is a secret";

      systemd.services.my-service = {
        after = [ "my-secret-key.service" ];
        wants = [ "my-secret-key.service" ];
        script = ''
          export MY_SECRET=$(cat /run/keys/my-secret)
          run-my-program
        '';
      };
    };
}

These dependencies will ensure that the service is only started when the keys it requires are present. For example, after a reboot, the services will be delayed until the keys are available, and systemctl status and friends will lead you to the cause. It's literally systemd holding the key for you. πŸ”‘

🧚 Special NixOS module inputs 🧚

In deployments with multiple machines, it is often convenient to access the configuration of another node in the same network, e.g. if you want to store a port number only once.

This is possible by using the extra NixOS module input nodes.

{
  network.description = "Gollum server and reverse proxy";

  gollum =
    { config, pkgs, ... }:
    {
      services.gollum = {
        enable = true;
        port = 40273;
      };
      networking.firewall.allowedTCPPorts = [ config.services.gollum.port ];
    };

  reverseproxy =
    { config, pkgs, nodes, ... }:
    let
      gollumPort = nodes.gollum.config.services.gollum.port;
    in
    {
      services.nginx = {
        enable = true;
        virtualHosts."wiki.example.net".locations."/" = {
          proxyPass = "http://gollum:${toString gollumPort}";
        };
      };
      networking.firewall.allowedTCPPorts = [ 80 ];
    };
}

Moving the port number to a different value is now without the risk of an inconsistent deployment. Iconic. πŸ‘‘

Additional module inputs are

  • name β€” The name of the machine.
  • uuid β€” The NixOps UUID of the deployment.
  • resources β€” NixOps resources associated with the deployment.

🌸 DEPLOYING WITHOUT ROOT 🌸

🧚 Requirements 🧚

NixOps 2.0 allows for deploying as users other than root, as long as the deploying user meets two requirements:

  1. The user can become root without needing to type a password.
  2. Nix considers the user to be a "trusted user" (https://nixos.org/nix/manual/#conf-trusted-users).

In this guide, we will use passwordless sudo. Very "root energy without being root" of it. πŸ’…

We assume:

  1. The deploying user's name is "deployer".
  2. The target machine's name is "hermes".
  3. The target machine is already managed by NixOps.

πŸŽ€ Steps πŸŽ€

  1. Configure the target machine according to the listed requirements.
  2. Update the NixOps network to use our alternative user.
  3. Deploy as the new user.

πŸ› οΈ Configuring the Target Machine πŸ› οΈ

First, mark the deploying user as trusted:

{
  nix.trustedUsers = [ "deployer" ];
}

This will let the user copy Nix store paths to the target.

Let the deploying user use sudo:

{
  users.users.deployer.extraGroups = [ "wheel" ];
}

Then, we configure the machine to have passwordless sudo:

{
  security.sudo.wheelNeedsPassword = false;
}

Now use NixOps to deploy these changes to the server before taking the next step.

🌈 Configuring the NixOps Network 🌈

Edit your nixops.nix to specify the machine's deployment.targetUser:

{
  network.description = "Non-root deployment";

  hermes =
    { resources, ... }:
    {
      deployment.targetUser = "deployer";
    };
}

πŸ§ͺ Testing our Changes πŸ§ͺ

Then, run nixops deploy to update the NixOps database. This deploy will use your "deployer" user instead of root.

Try running nixops ssh, and see that you are logged in as "deployer". Periodt. πŸ’–

πŸ“ Notes πŸ“

  • NixOps caches the target user and related variables in its state file, and commands like nixops send-keys and ssh use the cached data. After changing these values, run nixops deploy to update the cache.

πŸ› οΈ AUTHORING A PLUGIN πŸ› οΈ

okay so NixOps plugins are literally how you make NixOps core do more β€” like supporting extra hosting providers and resource types. that's the whole vibe. πŸ’…

some example plugins, so you can see what we're talking about (go look at them, bestie, they're iconic):

fr fr this guide is light on the details on purpose β€” it just wants to describe the supported hooks and the integration process. that's it. no cap.


🌸 Packaging with Poetry and poetry2nix 🌸

NixOps and its plugins are packaged as standard Python applications. most packages will use Poetry <https://python-poetry.org> and poetry2nix <https://github.com/nix-community/poetry2nix> for packaging with Nix. slay.

Note: NixOps is formatted with black and strictly typechecked with mypy. your project should follow these guidelines too β€” and use a mypy configuration at least as strict as the NixOps mypy configuration. no shortcuts, bestie. 😀

first up, create a pyproject.toml (see PEP-0517 <https://www.python.org/dev/peps/pep-0517/>) to describe your project. we do not use setup.py, and trying to use both a setup.py and pyproject.toml may cause confusing build errors. only use a pyproject.toml:

[tool.poetry]
name = "nixops_neatcloud"
version = "1.0"
description = "NixOps plugin for NeatCloud"
authors = ["Your Name <your.name@example.com>"]
license = "MIT"
include = [ "nixops_neatcloud/nix/*.nix" ]

[tool.poetry.dependencies]
python = "^3.7"
nixops = {git = "https://github.com/NixOS/nixops.git", rev = "master"}

[tool.poetry.dev-dependencies]
mypy = "^0.770"
black = "^19.10b0"

[tool.poetry.plugins."nixops"]
neatcloud = "nixops_neatcloud.plugin"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

πŸ’… Important Notes πŸ’…

read these. all of them. they're giving "final boss of migration" energy but they're short, i promise. 🫢

  1. if you have a setup.py, delete it now. like, right now.
  2. if your plugin is named nixops_neatcloud, the source directory must be named nixops_neatcloud.
  3. if your source directory was named nixopsneatcloud, please rename it to nixops_neatcloud.
  4. older style plugins used to store the Nix expressions in a directory named nix next to the python plugin directory, like this:
.
β”œβ”€β”€ nix
β”‚   └── default.nix
└── nixops_neatcloud
    β”œβ”€β”€ __init__.py
    └── plugin.py

plugins must now put the nix expressions underneat the plugin's python directory:

.
└── nixops_neatcloud
    β”œβ”€β”€ nix
    β”‚   └── default.nix
    β”œβ”€β”€ __init__.py
    └── plugin.py

and the nixexprs hook function which looked like this:

@nixops.plugins.hookimpl
def nixexprs():
    expr_path = os.path.realpath(os.path.dirname(__file__) + "/../../../../share/nix/nixops-vbox")
    if not os.path.exists(expr_path):
        expr_path = os.path.realpath(os.path.dirname(__file__) + "/../../../../../share/nix/nixops-vbox")
    if not os.path.exists(expr_path):
        expr_path = os.path.dirname(__file__) + "/../nix"

    return [
        expr_path
    ]

can now look like this:

from nixops.plugins import Plugin

class NeatCloudPlugin(Plugin):

    @staticmethod
    def nixexprs():
        return [
            os.path.dirname(os.path.abspath(__file__)) + "/nix"
        ]
  1. resource subclasses must now work with Python objects instead of XML. this is the glow-up, honestly. ✨

this old-style ResourceDefinition subclass:

class NeatCloudMachineDefinition(nixops.resources.ResourceDefinition):

    def __init__(self, xml):
        super().__init__(xml)
        self.store_keys_on_machine = (
            xml.find("attrs/attr[@name='storeKeysOnMachine']/bool").get("value")
            == "true"
        )

should now look like:

class NeatCloudMachineOptions(nixops.resources.ResourceOptions):
    storeKeysOnMachine: bool

class NeatCloudMachineDefinition(nixops.resources.ResourceDefinition):

    config: MachineOptions

    store_keys_on_machine: bool

    def __init__(self, name: str, config: nixops.resources.ResourceEval):
        super().__init__(name, config)
        self.store_keys_on_machine = config.storeKeysOnMachine

ResourceEval is an immutable typing.Mapping implementation. also note that ResourceEval has turned Nix lists into Python tuples, dictionaries into ResourceEval objects and so on. typing.Tuple cannot be used as it's fixed-size β€” use typing.Sequence instead. iykyk. πŸ”₯

ResourceOptions is an immutable object that provides type validation both with mypy and at runtime. any attributes which are not explicitly typed are passed through as-is.


✨ On with Poetry ✨

now create your first poetry.lock file with poetry lock:

nixops_neatcloud$ nix-shell -p poetry
[nix-shell:nixops_neatcloud]$ poetry lock
Creating virtualenv nixops_neatcloud-FrXThxiS-py3.7 in ~/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies... (2.1s)

Writing lock file

exit the Nix shell, and create the supporting Nix files.

create a default.nix:

{ pkgs ? import <nixpkgs> {} }:
let
  overrides = import ./overrides.nix { inherit pkgs; };
in pkgs.poetry2nix.mkPoetryApplication {
  projectDir = ./.;
  overrides = pkgs.poetry2nix.overrides.withDefaults overrides;
}

and a minimal overrides.nix:

{ pkgs }:

self: super: {
  nixops = super.nixops.overridePythonAttrs({ nativeBuildInputs ? [], ... }: {
    format = "pyproject";
    nativeBuildInputs = nativeBuildInputs ++ [ self.poetry ];
  });
}

and finally, a shell.nix:

{ pkgs ? import <nixpkgs> {} }:
let
  overrides = import ./overrides.nix { inherit pkgs; };
in pkgs.mkShell {
  nativeBuildInputs = [
    pkgs.poetry
  ];
  buildInputs = [
    (pkgs.poetry2nix.mkPoetryEnv {
      projectDir = ./.;
      overrides = pkgs.poetry2nix.overrides.withDefaults overrides;
    })
  ];
}

now you can enter a Nix and Poetry shell to develop on your plugin. main character energy activated. πŸ‘‘

nixops_neatcloud$ nix-shell
[nix-shell:nixops_neatcloud]$ poetry install
[nix-shell:nixops_neatcloud]$ poetry shell
Note: install is making a virtual environment, and does not install anything in the traditional sense. it's giving "it's not what you think" but in a good way. πŸ’–

create an empty file at nixops_neatcloud/plugin.py, and then you'll be able to list plugins and see your plugin:

now you can list plugins and see your plugin is installed:

(nixops_neatcloud-FrXThxiS-py3.7)
nixops_neatcloud$ nixops list-plugins
+-------------------+
| Installed Plugins |
+-------------------+
|     neatcloud     |
+-------------------+

at this point, you can develop your plugin from within this shell, running nixops and mypy nixops_neatcloud./


🧚 Plug-in Loading 🧚

NixOps uses Pluggy <https://pluggy.readthedocs.io/en/latest/> to discover and load plugins. the glue which hooks things together is in pyproject.toml:

[tool.poetry.plugins."nixops"]
neatcloud = "nixops_neatcloud.plugin"

NixOps implements a handful of hooks which your plugin can integrate with. see nixops/plugins/hookspec.py for a complete list. that file is your bestie, genuinely. πŸ¦‹


πŸ‘‘ Defining a plugin πŸ‘‘

to define a plugin you need to inherit from the Plugin base class and return it in the appropriate plugin hook:

from nixops.plugins import Plugin
import nixops.plugins

class NeatCloudPlugin(Plugin):

    @staticmethod
    def nixexprs():
        return [ ]  # List of paths to nix expressions

@nixops.plugins.hookimpl
def plugin():
    return NeatCloudPlugin()

🫢 Developing NixOps and a plugin at the same time 🫢

in this case you want a mutable copy of NixOps and your plugin. since we are developing the plugin like any other Python program, we can specify a relative path to NixOps's source in the pyproject.toml:

nixops = { path = "../nixops" }

then run poetry lock; poetry install; poetry shell like normal. easy. periodt. πŸ’…


🩹 Troubleshooting 🩹

if you run in to trouble, you might try deleting some things:

$ rm -rf nixops_neatcloud.egg-info pip-wheel-metadata/

πŸ”₯ Building a dependency fails πŸ”₯

first, run your nix-shell or nix-build with --keep-going and then again with --jobs 1 to isolate the cause. the first run will build everything it can complete, and the second one will build only one derivation and then fail:

nixops_neatcloud$ nix-shell -j1 --keep-going
these derivations will be built:
  /nix/store/3s2a0hky73b24m4yppd7581c9w2clpnb-python3.7-nixops-1.8.0.drv
  /nix/store/bv6gwayic2xxx3pd489d4gbs03kafxsd-python3-3.7.6-env.drv
building '/nix/store/3s2a0hky73b24m4yppd7581c9w2clpnb-python3.7-nixops-1.8.0.drv'...
[...]
Traceback (most recent call last):
  File "nix_run_setup", line 8, in <module>
    exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))
  File "/nix/store/n8nviwmllwqv0fjsar8v8k8gjap1vhcw-python3-3.7.6/lib/python3.7/tokenize.py", line 447, in open
    buffer = _builtin_open(filename, 'rb')
FileNotFoundError: [Errno 2] No such file or directory: 'setup.py'
builder for '/nix/store/3s2a0hky73b24m4yppd7581c9w2clpnb-python3.7-nixops-1.8.0.drv' failed with exit code 1
cannot build derivation '/nix/store/bv6gwayic2xxx3pd489d4gbs03kafxsd-python3-3.7.6-env.drv': 1 dependencies couldn't be built
error: build of '/nix/store/bv6gwayic2xxx3pd489d4gbs03kafxsd-python3-3.7.6-env.drv' failed

if a dependency is missing, add the dependency to your pyproject.toml, and add an override like the Toml example for Zipp. 😭


πŸ“ Zipp can't find toml πŸ“

add zipp to your overrides.nix, providing toml explicitly:

{ pkgs }:

self: super: {
  zipp = super.zipp.overridePythonAttrs({ propagatedBuildInputs ? [], ... } : {
    propagatedBuildInputs = propagatedBuildInputs ++ [
      self.toml
    ];
  });
}

πŸ’€ FileNotFoundError: [Errno 2] No such file or directory: 'setup.py' πŸ’€

this dependency needs to be built in the pyproject format, which means it will also need poetry as a dependency. add this to your overrides.nix:

package-name = super.package-name.overridePythonAttrs({ nativeBuildInputs ? [], ... }: {
  format = "pyproject";
  nativeBuildInputs = nativeBuildInputs ++ [ self.poetry ];
});

🌈 MIGRATING FROM NIXOPS 1 🌈

Overview <>

πŸ’… COMMAND REFERENCE

Description <>

(it literally just says that, bestie β€” empty angle brackets, nothing else. We move 🫢)


✨ CONFIGURATION OPTIONS ✨

πŸ–₯️ Machines

NixOps slides a whole bunch of extra options into the NixOS machine configuration system. For the standard NixOS configuration options β€” the vanilla ones β€” go check the NixOS manual (http://hydra.nixos.org/job/nixos/trunk/manual/latest/download) or the configuration.nix5 man page. iykyk πŸ’–


πŸ“ RELEASE NOTES

(okay so this heading is just... here. Sitting alone. Nothing under it in the source. The real release notes are further down, girl, we'll get there πŸ‘€)


πŸŽ€ WRITING DOCUMENTATION

New NixOps documentation uses a standard configuration of Sphinx. The older documentation is in Docbook, and honestly it should be ported to reStructuredText. Glow-up pending ✨

Sphinx's primer on reStructuredText (reST) lives right here: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html.

The NixOps repo has live-reloading support, which is lowkey iconic:

nixops$ ./live-docs.py
Serving on http://127.0.0.1:5500

Open http://127.0.0.1:5500 in your browser. As you edit and save .rst files, your browser automatically reloads. No more manual refreshing bestie, we're literally in the future 🌈

βœ… Before Committing

Validate the source files for correctly written reST and spelling:

nixops$ ./ci/lint-docs.sh

Fix any errors before committing. Fr fr. Not optional πŸ’…


πŸ“œ RELEASE NOTES

πŸš€ Release 2.0

This release has contributions by: Aaron Hall, Adam HΓΆse, Adam Mccullough, Amine Chikhaoui, Andreas Rammhold, Andrey Golovizin, Antoine Eiche, Benjamin Hipple, Bernardo Meurer, Chaker Benhamed, Cole Helbling, David Kleuker, DavΓ­Γ° Steinn Geirsson, Domen KoΕΎar, Eelco Dolstra, Florian Klink, Graham Christensen, Jean-baptiste Musso, Jeff Slight, Jleeuwes, John A. Lotoski, John Lotoski, Joseph Lucas, Lenz Weber, Lorenzo Manacorda, Luke Bentley-fox, Matthieu Coudron, Maximilian Bosch, Mazen.homrane, Michael Fellinger, Nathan Van Doorn, Niklas HambΓΌchen, Pascal Wittmann, Pixelkind, Psyanticy, Regnat, Robert Hensing, Ryan Mulligan, Samuel Leathers, Shay Bergmann, Tanner Doshier, Tewfik Ghariani, Tobias Pflug, Tom Bereknyei, Tomasz Rybarczyk, Victor Multun Collod, Vika, Vladimir Serov, Wout Mertens, Yc.s. πŸ‘‘ absolute legends, every single one

🌸 Release 1.7 (April 17, 2019)

General

  • Mitigation for the ssh StrictHostKeyChecking=no issue.
  • Fix nixops info --plain output.
  • Documentation fixes: add AWS VPC resources and fix some outdated command outputs.
  • Addition of Hashicorp's Vault AppRole resource.

AWS

  • Add more auto retries to api calls to prevent eventual consistency issues.
  • Fix nixops check with NVMe devices.
  • Route53: normalize DNS hostname.
  • S3: support bucket lifecycle configuration as well as versioning.
  • S3: introduce persistOnDestroy for S3 buckets which allows keeping the bucket during a destroy for later usage.
  • Fix backup-status output when backup is performed on a subset of devices.

Datadog

  • add tags for Datadog monitors

GCE

  • Fix machines being leaked when running destroy after a stop operation.
  • make sure the machine exists before attempting a destroy.

Hetzner

  • Remove usage of local commands for network configuration.
⚠️ Warning β€” note that this is incompatible with NixOS versions prior to 18.03. See release-notes: https://nixos.org/nixos/manual/release-notes.html#sec-release-18.03-notable-changes 😭

VirtualBox

  • added NixOS 18.09/19.03 images.
  • handle deleted VMs from outside NixOps.

This release has contributions from Amine Chikhaoui, Assassinkin, aszlig, Aymen Memni, Chaker Benhamed, Chawki Cheikch, David Kleuker, Domen Kožar, Dorra Hadrich, dzanot, Eelco Dolstra, Jârg Thalheim, Kosyrev Serge, Max Wilson, Michael Bishop, Niklas Hambüchen, Pierre Bourdon, PsyanticY, Robert Hensing. 🫢

πŸ¦‹ Release 1.6.1 (Sep 14, 2018)

General

  • Fix the deployment of machines with a large number of keys.
  • Show exit code of configuration activation script, when it is non-zero.
  • Ignore evaluation errors in destroy and delete operations.
  • Removed top-level Exception catch-all.
  • Minor bugfixes.

AWS

  • Automatically retry certain API calls.
  • Fixed deployment errors when deployment.route53.hostName contains uppercase letters.
  • Support for GCE routes.
  • Support attaching NVMe disks.

GCE

  • Add labels for GCE volumes and snapshots.
  • Add option to enable IP forwarding.

VirtualBox

  • Use images from nixpkgs if available.

This release has contributions from Amine Chikhaoui, aszlig, Aymen Memni, Chaker Benhamed, Domen KoΕΎar, Eelco Dolstra, Justin Humm, Michael Bishop, Niklas HambΓΌchen, Rob Vermaas, Sergei Khoma. πŸ’–

πŸŽ€ Release 1.6 (Mar 28, 2018)

General

  • JSON output option for show-option command.
  • Added experimental --show-plan to deploy command. Only works for VPC resources currently.

Backend: libvirtd

  • Added support for custom kernel/initrd/cmdline, for easier kernel testing/developing.
  • Fail early when defining domain.
  • Support NixOS 18.03

Backend: AWS/EC2

  • Allow changing security groups for instances that were deployed with a default VPC (no explicit subnetId/vpc)
  • Make sure EC2 key pair not destroyed when it is in use, instead produce error.
  • Support for separate Route53 resources.
  • Support CloudWatch metrics and alarms.
  • Support updating IAM instance profile of an existing instance.
  • Support VPC resources.
  • RDS: allow multiple security groups.
  • Allow S3 buckets to be configured as websites.
  • Fix issue where S3 bucket policy was only set on initial deploy.

Backend: Datadog

  • Support sending start/finish of deploy and destroy events.
  • Support setting downtime during deployment.

Backend: Azure

  • Fix Azure access instructions.

Backend: Google Compute

  • Add support for labelling GCE instances
  • Minor fixes to make GCE backend more consistent with backends such as EC2.
  • Fix attaching existing volumes to instances.
  • Implemented show-physical --backup for GCE, similar to EC2.
  • Prevent google-instance-setup service from replacing the host key deployed by NixOps.
  • Allow instances to be created inside VPC subnets.

This release has contributions from Adam Scott, Amine Chikhaoui, Anthony Cowley, Brian Olsen, Daniel Kuehn, David McFarland, Domen KoΕΎar, Eelco Dolstra, Glenn Searby, Graham Christensen, Masato Yonekawa, Maarten Hoogendoorn, Matthieu Coudron, Maximilian Bosch, Michael Bishop, Niklas HambΓΌchen, Oussama Elkaceh, Pierre-Γ‰tienne Meunier, Peter Jones, Rob Vermaas, Samuel Leathers, Shea Levy, Tomasz CzyΕΌ, Vaibhav Sagar. 🌟

🌈 Release 1.5.2 (Oct 29, 2017)

General

  • This release has various minor bug and documentation fixes.
  • #703: don't ask for known host if file doesn't exist.
  • Deprecated --evaluate-only for --dry-run.

Backend: libvirtd

  • Added domainType option.
  • Make the libvirt images readable only by their owner/group.
  • Create "persistent" instead of "transient" domains, this ensures that nixops deployments/VMs survive a reboot.
  • Stop using disk backing file and use self contained images.

Backend: EC2

  • #652, allow securityGroups of Elastic File System mount target to be set.
  • #709: allow Elastic IP resource for security group sourceIP attribute.

Backend: Azure

  • Use Azure images from nixpkgs, if they are available.

Backend: Google Compute

  • Use Google Compute images from nixpkgs, if they are available.

This release has contributions from Andreas Rammhold, Bjørn Forsman, Chris Van Vranken, Corbin, Daniel Ehlers, Domen Kožar, Johannes Bornhold, John M. Harris, Jr, Kevin Quick, Kosyrev Serge, Marius Bergmann, Nadrieril, Rob Vermaas, Vlad Ki. ⭐

πŸ“ Release 1.5.1 (Jul 5, 2017)

General

  • This release has various minor bug and documentation fixes.

Backend: None

  • #661: Added deployment.keys.*.keyFile option to provide keys from local files, rather than from text literals.
  • #664: Added deployment.keys.*.destDir and deployment.keys.*.path options to give more control over where the deployment keys are stored on the deployed machine.

Backend: Datadog

  • Show URL for dashboards and timeboards in info output.

Backend: Hetzner

  • Added option to disable creation of sub-accounts.

Backend: Google Compute

  • Added option to set service account for an instance.
  • Added option to use preemptible option when creating an instance.

Backend: Digital Ocean

  • Added option to support IPv6 on Digital Ocean.

shoutout szn, bestie β€” this release has contributions from Albert Peschar, Amine Chikhaoui, aszlig, Clemens Fruhwirth, Domen KoΕΎar, Drew Hess, Eelco Dolstra, Igor Pashev, Johannes Bornhold, Kosyrev Serge, Leon Isenberg, Maarten Hoogendoorn, Nadrieril Feneanar, Niklas HambΓΌchen, Philip Patsch, Rob Vermaas, Sven Slootweg. literally every single one of them ate πŸ’…


🌈 Release 1.5 (Feb 16, 2017)

  • General ✨
    • Various minor documentation and bug fixes
    • #508: the SSH tunnels implementation got a whole rewrite so it uses iproute instead of netttools β€” glow up πŸ’…
    • #400: key ownership is now handled after user/group creation (order matters, bestie)
    • #216: added the --keep-days option, for cleaning up backups πŸŽ€
    • #594: the NixOps statefile is created with stricter permissions now β€” safety slay
    • Uses types.submodule instead of the deprecated types.optionSet
    • #566: support for setting deployment.hasFastConnection
    • support for nixops deploy --evaluate-only
  • Backend: None
    • creates /etc/hosts
  • Backend: Amazon Web Services πŸ”₯
    • support for Elastic File Systems
    • support for the latest EBS volume types
    • support for Simple Notification Service
    • support for Cloudwatch Logs resources
    • support for loading credentials from ~/.aws/credentials (the AWS default)
    • HVM is now the default virtualization type (all the new instance types are HVM, iykyk)
    • #550: fixed that sporadic Error binding parameter 0 - probably unsupported type error β€” she's gone πŸ’€
  • Backend: Datadog
    • support for provisioning Datadog Monitors
    • support for provisioning Datadog Dashboards
  • Backend: Hetzner
    • #564: binary cache substitutions were broken by certificate errors β€” fixed
  • Backend: VirtualBox
    • support for dots in machine names
    • added the vcpu option
  • Backend: Libvirtd
    • documentation typo fixes (we love a proofread era 🌸)
  • Backend: Digital Ocean
    • initial support for Digital Ocean to deploy machines β€” baby's first steps πŸ¦‹

This release has contributions from Amine Chikhaoui, Anders Papitto, aszlig, Aycan iRiCAN, Christian Kauhaus, Corbin Simpson, Domen Kožar, Eelco Dolstra, Evgeny Egorochkin, Igor Pashev, Maarten Hoogendoorn, Nathan Zadoks, Pascal Wittmann, Renzo Carbonaram, Rob Vermaas, Ruslan Babayev, Susan Potter and Danylo Hlynskyi. 🫢


🌈 Release 1.4 (Jul 11, 2016)

  • General ✨
    • added the show-arguments command, so you can query the nixops arguments that are defined in the nix expressions
    • added the --dry-activate option to the deploy command, so you can peek at which services will be stopped/started/restarted πŸ‘€
    • added the --fallback option to the deploy command, matching the same flag on nix-build
    • added the --cores option to the deploy command, also matching the same flag on nix-build
  • Backend: None
    • (nothing here, iconique silence πŸŽ€)
  • Amazon EC2
    • uses hvm-s3 AMIs when appropriate
    • the EBS optimized flag can now be changed (this needs --allow-reboot, just so you know)
    • you can now recover from a spot instance kill when you're using an external volume defined as a resource (resources.ebsVolumes)
    • when disassociating an elastic IP, it now checks that the current instance is the one actually associated with it, in case somebody else has 'stolen' the elastic IP 😭 rude
    • uses a generated list for deployment.ec2.physicalProperties, based on the Amazon Pricing listing
    • the EC2 AMI registry has been moved to the nixpkgs repository
    • you can set a timeout on spot instance creation
    • you can update security groups on running instances in a VPC
    • support for x1 instances πŸ”₯
  • Backend: Azure
    • brand new Azure Cloud backend, contributed by Evgeny Egorochkin πŸ‘‘
  • Backend: VirtualBox
    • respects deployment.virtualbox.disks.*.size for images with a baseImage
    • you can override the VirtualBox base image size for disk1
  • Libvirt
    • improved logging messages
    • #345: uses qemu-system-x86_64 instead of qemu-kvm so non-NixOS is supported
    • added the extraDomainXML NixOS option
    • added the extraDevicesXML NixOS option
    • added the vcpu NixOS option

This release has contributions from Amine Chikhaoui, aszlig, Cireo, Domen KoΕΎar, Eelco Dolstra, Eric Sagnes, Falco Peijnenburg, Graham Christensen, Kevin Cox, Kirill Boltaev, Mathias Schreck, Michael Weiss, Brian Zach Abe, Pablo Costa, Peter Hoeg, Renzo Carbonara, Rob Vermaas, Ryan Artecona, Tobias Pflug, Tom Hunger, Vesa Kaihlavirta, Danylo Hlynskyi. πŸ’–


🌈 Release 1.3.1 (January 14, 2016)

  • General ✨
    • #340: the too long for Unix domain socket error
    • #335: uses the correct port when setting up an SSH tunnel
    • #336: added support for non-machine IP resources in /etc/hosts
    • fixed how system.stateVersion is determined
    • ssh_util: reconnects when the SSH master socket is dead
    • #379: removed the reference to the jobs attribute in NixOS
  • Backend: None
    • passes deployment.targetPort to ssh for none backend
    • #361: doesn't use _ssh_private_key if its corresponding public key hasn't been deployed yet
  • Amazon EC2
    • you can specify assumeRolePolicy for IAM roles
    • added the vpcId option to EC2 security group resources
    • VPC security groups can refer to sec. group names (within the same sec. group) as well as group ids
    • stops VPC calls from being made when only security group ids are being used (instead of names)
    • uses the correct credentials for VPC API calls
    • fixed creating EC2 instance (... region β€˜None’) when recreating a missing instance
    • you can keep volumes while destroying a deployment
  • VirtualBox
    • #359: changed sbin/mount.vboxsf to bin/mount.vboxsf
  • Hetzner
    • #349: doesn't create /root/.ssh/authorized_keys
    • #348: fixup and refactor of the Hetzner backend tests
    • hetzner-bootstrap: fixes wrapping Nix inside chroot
    • hetzner-bootstrap: you can now easily enter the chroot
  • Libvirt
    • #374: added headless mode
    • #374: uses a more reliable method to retrieve the IP address
    • #374: nicer error message for a missing images dir
    • #374: you can specify xml for devices

This release has contributions from aszlig, Bas van Dijk, Domen Kožar, Eelco Dolstra, Kevin Cox, Paul Liu, Robin Gloster, Rob Vermaas, Russell O'Connor, Tristan Helmich and Yves Parès (Ywen). 🌸


🌈 Release 1.3 (September 28, 2015)

  • General ✨
    • NixOps now requires NixOS 14.12 and up ⚠️ (so check that before you come crying to me)
    • machines in a NixOps network now have access to the deployment name, uuid and its arguments, via the deployment.name, deployment.uuid and deployment.arguments options
    • support for <...> paths in network spec filenames, e.g. you can do:
nixops create '<nixops/templates/container.nix>'
  • support for username@machine for nixops scp
  • Amazon EC2
    • support for the latest EC2 instance types, including t2 and c4 instances
    • support for Amazon EBS SSD disks
    • instances can be placed in an EC2 placement group, which lets instances be grouped in a low-latency 10 Gbps network πŸ”₯
    • you can start EC2 instances in a VPC subnet
    • more robust handling of spot instance creation
    • support for setting bucket policies on S3 buckets created by NixOps
    • Route53 support now uses a CNAME to the public DNS hostname instead of an A record to the public IP address
    • support for Amazon RDS instances
  • Google Cloud
    • new backend for Google Cloud Platform. It includes support for the following resources:
  • VirtualBox
    • VirtualBox 5.0 is required for the VirtualBox backend ⚠️
  • NixOS container
    • new backend for NixOS containers πŸŽ€
  • Libvirt
    • new backend for libvirt using QEMU/KVM

This release has contributions from Andreas Herrmann, Andrew Murray, aszlig, Aycan iRiCAN, Bas van Dijk, Ben Moseley, BjΓΈrn Forsman, Boris Sukholitko, Bruce Adams, Chris Forno, Dan Steeves, David Guibert, Domen KoΕΎar, Eelco Dolstra, Evgeny Egorochkin, Leroy Hopson, Michael Alyn Miller, Michael Fellinger, Ossi Herrala, Rene Donner, Rickard Nilsson, Rob Vermaas, Russell O'Connor, Shea Levy, Tomasz Kontusz, Tom Hunger, Trenton Strong, Trent Strong, Vladimir Kirillov, William Roe. πŸ’œ


🌈 Release 1.2 (April 30, 2014)

  • General ✨
    • NixOps now requires NixOS 13.10 and up ⚠️
    • added the --all option to nixops destroy, nixops delete and nixops ssh-for-each
    • the -d option now matches based on prefix for convenience, when the specified uuid/id isn't found
    • resources can now be accessed via direct reference, i.e. you can use securityGroups = [ resources.ec2SecurityGroups.foo ]; in stead of securityGroups = [ resources.ec2SecurityGroups.foo.name ];
    • the default value of deployment.storeKeysOnMachine changed to false, which is the more secure option πŸ” β€” but heads up: this can prevent an unattended reboot from finishing, because keys will need to be pushed to the machine. so like, know that before you set it
  • Amazon EC2
    • support for provisioning elastic IP addresses
    • support for provisioning EC2 security groups
    • support for all HVM instance types
    • support for the ap-southeast-1 region
    • better handling of errors when pushing Route53 records
    • support for using ARNs to apply instance profiles to EC2 instances, which allows cross-account API access
    • the base HVM image was updated to allow using all ephemeral devices
    • the instance ID is now available in nix through the deployment.ec2.instanceId option, set by nixops
    • support for independent provisioning of EBS volumes. before this, EBS volumes could only be created as part of an EC2 instance, which meant their lifetime was tied to the instance and they couldn't be managed separately. now they can be provisioned independently, e.g.:
resources.ebsVolumes.bigdata =
  { name = "My Big Fat Data";
    region = "eu-west-1";
    zone = "eu-west-1a";
    accessKeyId = "...";
    size = 1000;
  };
  • to allow cross-account API access, the deployment.ec2.instanceProfile option can now be set to either a name (the previous behaviour) or an Amazon Resource Name (ARN) of the instance profile you want to apply
  • Hetzner
    • always hard resets when destroying a machine
    • support for Hetzner vServers
    • the root password is disabled by default
    • fixed hard reset for rebooting into rescue mode. this one's extra useful if you have a dead server and want to put it in rescue mode β€” now you can just run:
nixops reboot --hard --rescue --include=deadmachine
  • VirtualBox
    • requires VirtualBox >= 4.3.0 ⚠️
    • support for shared folders in VirtualBox β€” you can mount a host folder on the guest by setting the deployment.virtualbox.sharedFolders option πŸŽ€
  • Allow destroy if the VM is gone already

This release has contributions from aszlig, Corey O'Connor, Domen KoΕΎar, Eelco Dolstra, Michael Stone, Oliver Charles, Rickard Nilsson, Rob Vermaas, Shea Levy and Vladimir Kirillov.

πŸ› Release 1.1.1 (October 2, 2013)

Okay so this one is a lil minor bugfix release, but it still ate πŸ’…

  • Added a command-line option --include-keys so you can import SSH public host keys of the machines that are gonna be imported into the user's .ssh/known_hosts. Handy, no cap.
  • Fixed a bug that was literally blocking you from switching the deployment.storeKeysOnMachine option value. Rude behaviour, now gone.
  • On non-EC2 systems, NixOps now generates ECDSA SSH host key pairs instead of DSA. Moving on up ✨
  • VirtualBox deployments use generated SSH host key pairs.
  • For all machines where nixops generates an SSH host key pair, it adds the SSH public host key to the known_hosts configuration of every machine in the network. Everyone gets to know everyone 🫢
  • For EC2 deployments, if the nixops expression specifies a set of security groups for a machine that's different from the security groups already applied to the existing machine, you get a warning that the change cannot be made. It's giving "we can't do that, bestie" 😭
  • For EC2 deployments, disks that aren't supposed to be attached to the machine are detached only after system activation has been completed. Before this, it happened before β€” which could lead to volumes not being able to detach without needing to stop the machine. πŸ’€
  • Added a command-line option --repair as a convenient way to pass this option (which allows repairing of broken or changed paths in the nix store) to nix-build calls that nixops performs.
Heads up: --repair only works in nix setups that run without the nix daemon. Important, fr fr.

This release has contributions from aszlig, Ricardo Correia, Eelco Dolstra, Rob Vermaas.

πŸ¦‹ Release 1.1 (September 9, 2013)

  • Backend for Hetzner <http://hetzner.de>, a German data center provider. More information and a demo video can be found here <https://github.com/NixOS/nixops/pull/119>. Iconic.
  • When using the deployment.keys.* options, the keys in /run/keys are now created with mode 600. Locked down πŸ”₯
  • Fixed a bug where the EBS snapshots name tag was overridden by the instance name tag. Not the main character energy we wanted.
  • The nixops executable now has the default OpenSSH from nixpkgs in its PATH by default, to work around issues with left-over SSH master connections on older versions of OpenSSH β€” like the version installed by default on CentOS. We love a workaround πŸ’–
  • A new resource type has been introduced to generate sets of SSH public/private keys. Slay.
  • Support for spot instances in the EC2 backend. By specifying the deployment.ec2.spotInstancePrice option for a machine, you can set the spot instance price in cents. NixOps will wait 10 minutes for a spot instance to be fulfilled β€” and if not, then it errors out for that machine. Tick tock ⏰

πŸŽ€ Release 1.0.1 (July 11, 2013)

This is a minor bugfix release. Short and sweet.

  • Reduce parallelism for running EC2 backups, to prevent hammering the AWS API in case of many disks. Be nice to the API, bestie.
  • Propagate the instance tags to the EBS volumes (except for the Name tag, which is overridden with a detailed description of the volume and its use).

🌈 Release 1.0 (June 18, 2013)

Initial release. The origin story πŸ‘‘

  • Index <>
  • Module Index <>
  • Search Page <>

πŸ‘‘ Author

NixOps Contributors

2020, NixOps Contributors


And that's the whole thing, bestie! You just read NIXOPS(1) β€” dated Jan 02, 1980 in the footer, which is a whole vibe β€” written by the NixOps Contributors, with copyright 2020, NixOps Contributors. Go forth and deploy βœ¨πŸ’œπŸ¦‹

πŸ“¦ where this page comes from