running nixos on digitalocean
Lately, I have been running NixOS on my primary machine after having switched from Arch. The initial transition was a bit challenging as the Nix documentation felt somewhat lacking, but things eventually improved with the help of the Nix forums.
My existing servers were running Ubuntu, and I wanted to bring all the Nix goodness to them. The appeal of a deterministic and stateless configuration is strong, as it means I wouldn’t have to reset my VM or create backups after messing something up with privileged access (yes, a skill issue, I know). With NixOS, however, I could simply reboot to an older generation of my operating system.
However, my VPS provider, DigitalOcean, doesn’t offer pre-built NixOS images. So, I’ll describe here how I created a custom NixOS image specifically for DigitalOcean. To deploy NixOS on my servers, I needed to upload a custom image that met their requirements, including:
- A supported image format (like qcow2)
- The presence of cloud-init for initial configuration
- An included SSH key for secure access
Enter nixos-generators: Building the Base Image#
The nixos-generators project came to the rescue. It provides generators specifically designed to create custom NixOS images that tick all the boxes for DigitalOcean. These generators build the image in the required qcow2 format, include cloud-init, and allow you to add your SSH key during the build process.
However, while nixos-generators is a great starting point, building and updating the image every time is time-consuming and inefficient. The recommended way to update NixOS systems is by using nixos-rebuild, which applies the necessary changes directly to a running system.
Creating a Modular Configuration#
The next step was to refactor my configuration by splitting the common elements into a separate module. This module includes some of the programs that need to be installed, my SSH key, and my home-manager configuration, which I use to manage my shell settings and other useful utilities.
The snippet below defines two outputs:
- nixosConfigurations.whirlpool
This builds a complete NixOS system configuration for a server named “whirlpool”. It combines the server-specific modules with the general digital-ocean-config.nix module.
- whirlpool_do
This leverages nixos-generators.nixosGenerate to build a qcow2 image specifically for DigitalOcean using the “whirlpool” configuration.
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
home-manager = {
inputs.nixpkgs.follows = "nixpkgs";
url = "github:nix-community/home-manager";
};
nixos-generators = {
inputs.nixpkgs.follows = "nixpkgs";
url = "github:nix-community/nixos-generators";
};
};
outputs = inputs@{ self, nixpkgs, home-manager, nixos-generators, ... }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.x86_64-linux.pkgs;
homeConfig = hostname: {
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.augtheo = import ./hosts/${hostname}/home.nix;
};
getModules = hostname: [
./hosts/${hostname}/configuration.nix
home-manager.nixosModules.home-manager
(homeConfig hostname)
];
in {
nixosConfigurations = {
whirlpool = nixpkgs.lib.nixosSystem {
inherit system;
modules = (getModules "whirlpool") ++ [
"${nixpkgs}/nixos/modules/virtualisation/digital-ocean-config.nix"
];
};
whirlpool_do = nixos-generators.nixosGenerate {
inherit system;
format = "do";
modules = getModules "whirlpool";
};
};
}
Building the Custom Image and Performing Updates#
Building the base image is as simple as running:
nix build .#whirlpool_do
This command will output the qcow2 file that you can use to import into DigitalOcean’s image service. Once the image is uploaded, you can use it to create a droplet.
Rebuilding the running NixOS system is done with the nixos-rebuild command. Make sure you apply the updates from a host machine whose SSH key is added.
nixos-rebuild switch --flake .#whirlpool --target-host <host>@<ip>