Table of Contents

GNU Guix System

GNU Guix System is a distribution where the system, services, and packages are described declaratively in Guile Scheme. Like NixOS, it creates system generations when the configuration changes and lets you return to an earlier generation.

How the template works

The vpsFree template contains a minimal Guix System with OpenSSH and two files:

system.scm resolves %ct-operating-system-base from the vpsadminos module and inherits it. Keep the module lookup and inheritance: the platform base provides the container bootloader, file systems, kernel placeholder, packages, services, and network integration. The current versions of both files are available in the Guix template sources.

The kernel is managed by vpsAdminOS. Do not add your own Linux kernel or a bootloader intended for a physical machine to the configuration.

Editing the configuration

Start by editing /etc/config/system.scm. The host name, timezone, and locale are visible there as defaults that you can change. You can also add fields such as packages, which Guix evaluates directly. Keep the platform-system lookup and (inherit platform-system) so the platform-specific settings remain active.

When changing services, first derive and bind the service list outside the operating-system record, then assign that binding to the services field. The deployment example below follows this pattern. Guix evaluates service fields after loading the configuration, so they must not depend on bindings from its temporary configuration module.

Activate the configuration as root:

#!/usr/bin/env bash
set -eo pipefail
 
# Use the Guix revision that built the active system generation.
export GUIX_PROFILE=/run/current-system/profile
# shellcheck disable=SC1091
. "$GUIX_PROFILE/etc/profile"
hash guix
 
test -r /etc/config/system.scm
test -r /etc/config/vpsadminos.scm
test -r /run/current-system/channels.scm
guix time-machine -C /run/current-system/channels.scm -- \
  system reconfigure -L /etc/config /etc/config/system.scm

guix time-machine uses the channels recorded in the active generation, so reconfiguration does not depend on later channel-history changes. The -L /etc/config option makes the vpsadminos module available. The command builds and immediately activates a new generation. Before logging out, verify that SSH and the services you need are running. See the manuals for guix time-machine and guix system for details.

Updating Guix

The example above selects the Guix revision and channels that built the active system generation. Reconfiguration therefore does not require guix pull before every configuration change, keeping repeated deployments predictable.

When you intentionally update Guix, first record the current channels with guix describe. Then run guix pull, load the updated profile as instructed by the command, and reconfigure again. Read the news before changing revisions, and allow extra time, memory, and disk space for the build. The channels manual explains channels and pinned revisions.

Network and SSH

Do not configure the primary network with static-networking-service-type. At every boot, vpsAdminOS creates /ifcfg.add from the current addresses and the vpsadminos-networking service runs it. Add any custom networking services on top of this layer.

For convenient first access, the default template permits SSH login as root. Once your keys work, you can harden access as described in SSH.

Deploying with guix deploy

If you manage several Guix VPSes, you can keep their configurations on one coordinator Guix system and deploy them with guix deploy. The complete configuration below is a starting point for one VPS. You maintain only deploy.scm; the container details continue to come from the maintained /etc/config/vpsadminos.scm module.

The coordinator needs the SSH key /root/.ssh/id_ed25519, and you must add its public part to root on the target VPS before the first deployment. Test key-only login first. Run cat /etc/ssh/ssh_host_ed25519_key.pub on the target VPS and verify the resulting key fingerprint by following the SSH guide. The configuration needs the whole line beginning with ssh-ed25519, not just the fingerprint.

Save this configuration as /etc/config/deploy.scm on the coordinator and replace the target VPS address and host key:

;; Load the maintained vpsAdminOS container integration.
(add-to-load-path "/etc/config")
(use-modules (gnu)
             (gnu machine)
             (gnu machine ssh)
             (gnu services base))
(use-service-modules ssh)
 
(let* ((platform-system
        (module-ref (resolve-interface '(vpsadminos))
                    '%ct-operating-system-base))
       ;; These files belong to the machine from which you run guix deploy.
       (controller-signing-key
        (local-file "/etc/guix/signing-key.pub"))
       (root-ssh-key
        (local-file "/root/.ssh/id_ed25519.pub"))
       ;; Build the service list before assigning the delayed services field.
       (user-services
        (cons
         (simple-service 'controller-signing-key
                         guix-service-type
                         (guix-extension
                          (authorized-keys
                           (list controller-signing-key))))
         (modify-services
             (operating-system-user-services platform-system)
           (openssh-service-type config =>
             (openssh-configuration
              (inherit config)
              (permit-root-login 'prohibit-password)
              (password-authentication? #f)
              (authorized-keys
               `(("root" ,root-ssh-key))))))))
       (system
        (operating-system
          (inherit platform-system)
          (host-name "guix-target")
          (timezone "Etc/UTC")
          (locale "en_US.utf8")
          (services user-services)))
       (target-machine
        (machine
          (operating-system system)
          (environment managed-host-environment-type)
          (configuration
           (machine-ssh-configuration
            ;; Replace the address and host key with those of your target VPS.
            (host-name "192.0.2.3")
            (system "x86_64-linux")
            (user "root")
            (identity "/root/.ssh/id_ed25519")
            (host-key "ssh-ed25519 REPLACE_WITH_TARGET_HOST_KEY")
            (authorize? #t)
            (allow-downgrades? #f)
            ;; vpsAdminOS supplies the kernel and exposes a dummy /dev/null root.
            ;; Guix's bare-metal file-system/initrd checks cannot inspect it.
            (safety-checks? #f))))))
  (list target-machine))

First load the configuration without deploying it with guix time-machine -C /run/current-system/channels.scm – deploy -L /etc/config /etc/config/deploy.scm –dry-run. Then run the same command without –dry-run. The first deployment automatically authorizes the coordinator's signing key on the target, and the declaration keeps it authorized in the new generation.

The configuration deliberately allows only key-based root login and verifies the target host key. The container-specific safety-checks? #f disables Guix checks for physical file systems and initrd modules: vpsAdminOS supplies the kernel and its integration module exposes a dummy /dev/null root which current Guix cannot inspect. Downgrade protection stays enabled. If deployment fails, fix its cause instead of enabling allow-downgrades?.

Generations and recovery

List generations with guix system list-generations. Verify the new system before deleting older generations. The Guix manual describes rollback and generation management.

If a new configuration does not boot or you lose SSH access, follow the remote console guide. The vpsAdminOS start menu guide explains how to restore an older Guix generation. Fix the configuration and reconfigure again.