4o1x5.dev/content/post/guides/nix/remote-development/index.md
2024-05-10 15:51:31 +02:00

6.4 KiB

title description date image categories tags draft
Remote deployments on NixOs A quick and dirty guide to get started with building systems to remote instances 2024-05-04 00:00:00+0000 taylor-vick-M5tzZtFCOfs-unsplash.jpg
Nix
Guide
Sysadmin
Nix
NixOs
Server Management
false

With the capabilities of Nix & Nixos, we can tailor-make services on our local computer, build the system, and then transmit it to a remote server using the --target-host argument for nixos-rebuild command. This is an efficient method of deploying services to distant servers because you don't have to connect to the machine via SSH and set up the files locally before building them there.

How remote deployments work

NixOS allows for a seamless build process, where you can create the system on your local computer and then use SSH to transfer the configuration files to a remote machine where the services are deployed.
This process is easy to manage and streamline. Ez to learn!

Getting started

First you will need a machine running NixOs. Duh. But also you will need to have root access to it in some way.
If you have the root user and its password then you are set to go and can skip to the section where I explain how to get ready for remote deployment

Setting up NixOs on a server.

Installing

I assume if you are reading this article you know how to install an operating system.

You will need to flash an usb drive with NixOs, for the sake of an easy install I will use latest-nixos-plasma5-x86_64-linux.iso since It comes with a fearly easy to use Calamares installer.

Installer You can go ahead and click through it and it will install.

First boot

For remote deployment to work you will need to enable ssh and configure some parameters for it to work. We are enabling root login and also sftp for file transfer.

# configuration.nix
  services.openssh = {
    enable = true;
    allowSFTP = true;
    settings = {
      PasswordAuthentication = true;
      PermitRootLogin = "yes";
    };
  };
  networking.hostName = "server1";
  networking.domain = "localhost";

Rebuild the system

sudo nixos-rebuild switch

Setting up key auth

To facilitate easy deployments, you can transfer your public SSH key to the remote machine, allowing you to log in without having to enter the password for each rebuild. This method is both more convenient and safe

ssh-copy-id root@server

Create a directory for the remote

On your local machine, it's important to organize your files into a directory, particularly when working with multiple servers. This is demonstrated below, where I showcase my personal file organization method.

{{< filetree/container >}} {{< filetree/folder name="servers" >}}

{{< filetree/folder name="server1" state="closed" >}} {{< filetree/file name="configuration.nix" >}} {{< filetree/file name="flake.nix" >}} {{< filetree/file name="flake.lock" >}} {{< /filetree/folder >}}

{{< filetree/folder name="server2" state="closed" >}} {{< filetree/file name="configuration.nix" >}} {{< filetree/folder name="services" state="closed" >}} {{< filetree/file name="matrix.nix" >}} {{< filetree/file name="webserver.nix" >}} {{< /filetree/folder >}} {{< filetree/file name="flake.nix" >}} {{< filetree/file name="flake.lock" >}} {{< /filetree/folder >}} {{< /filetree/folder >}}

{{< /filetree/container >}}

Copying essential files from remote

NixOS does not support partial builds, so you will need to transfer all the necessary files from /etc/nixos to your local machine. This includes files such as hardware-configuration.nix and configuration.nix.

scp root@server:/etc/nixos/configuration.nix configuration.nix
scp root@server:/etc/nixos/hardware-configuration.nix hardware-configuration.nix

Create flakes

You can create a file called flake.nix or use nix to do so.

nix flake init .

Paste the following in the file.

# flake.nix
{
  description = "Server1 deployments";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
  };

  outputs =
    { self
    , nixpkgs
    , ...
    }:
    let
      system = "x86_64-linux";
    in
    {
      nixosConfigurations.server1 = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [
          ./configuration.nix
        ];
      };
    };
}

Here is an example of how your configuration.nix should look like.

# configuration.nix

{ config, pkgs, ... }:

{
  imports =
    [
      ./hardware-configuration.nix
    ];

  networking.hostName = "server1";
  networking.domain = "example.com";

  services.openssh = {
      enable = true;
      allowSFTP = true;
      settings = {
        PasswordAuthentication = true;
        PermitRootLogin = "yes";
      };
    };

}


Set up a service

This little example shows a dummy nginx service.

# nginx.nix
services.nginx = {
    enable = true;
    virtualHosts = {
      "example.com" = {
        locations."/" = {
            # ...
        };
      };
    };
}

Insert it in the configuration.nix imports section.

imports = [
        ./hardware-configuration.nix
        ./nginx.nix
    ];

Deploy!

After all this we can just go ahead and execute a rebuild like we would do on our local machine. Except in this case we have to add the --flake to the rebuild command and also add the hostname we are building for.

nixos-rebuild switch --flake .#server1 --target-host root@server --show-trace

Service management

Since NixOs uses systemd we can utilize its tools such as journalctl or systemcl to check up on how our services are doing. Here are a few commands I recommend using

Prints the last 100 logs of nginx

journalctl -u nginx.service -n 200

Displays the status of the service

systemctl status nginx.service

Afterthoughts

The first-boot section could be skipped if you create a custom nixos installation media then flash that to the server. With a custom media you can define ssh to already have these options enabled and also can add your public key. This is how I've been doing my deployments for the past 1 month for the 4 of my servers. It's much easier than my old-school method of ssh-ing into my alpine machines and manage my deployments with docker-compose