--- #title: Getting started with remote deployment on NixOs title: Remote deployments on NixOs description: A quick and dirty guide to get started with building systems to remote instances date: 2024-05-04 00:00:00+0000 image: taylor-vick-M5tzZtFCOfs-unsplash.jpg categories: - Nix - Guide - Sysadmin tags: - Nix - NixOs - Server Management draft: 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 ![](diagram1.svg) 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](#first-boot) ### 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](nixosinstaller.png) 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. ```nix # configuration.nix services.openssh = { enable = true; allowSFTP = true; settings = { PasswordAuthentication = true; PermitRootLogin = "yes"; }; }; networking.hostName = "server1"; networking.domain = "localhost"; ``` **Rebuild the system** ```zsh 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 ```bash 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`. ```bash scp configuration.nix root@server:/etc/nixos ``` ```bash scp hardware-configuration.nix root@server:/etc/nixos ``` ## Create flakes You can create a file called `flake.nix` or use `nix` to do so. ```bash nix flake init . ``` Paste the following in the file. ```nix # 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. ```nix # 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. ```nix # nginx.nix services.nginx = { enable = true; virtualHosts = { "example.com" = { locations."/" = { # ... }; }; }; } ``` Insert it in the configuration.nix `imports` section. ```nix 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. ```bash 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 ```bash journalctl -u nginx.service -n 200 ``` Displays the status of the service ```bash systemctl status nginx.service ``` ## Afterthoughts The first-boot section could be skipped if you [create a custom nixos installation media](https://wiki.nixos.org/wiki/Creating_a_NixOS_live_CD) 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`