#! /usr/bin/env bash # Use Digital Ocean Droplet image: # # Fedora 24 x64 # Ubuntu 16.04 x64 # Debian 8.5 x64 # # YMMV with any other hoster + image combination. # nixos-infect is so named because of the high likelihood of rendering a system # inoperable. Use with caution and preferably only on newly-provisioned # systems. # # WARNING NB This script wipes out the targeted host's root filesystem when it # runs to completion. Any errors halt execution. set -x is used to help debug, # as often a failed run leaves the system in an inconsistent state, requiring a # rebuild (in DigitalOcean panel: Droplet Settings -> "Destroy" -> "Rebuild # from original"). # # TO USE: # - Add any custom config you want (see notes below) # - Deploy the droplet indicated at the top of the file, enable ipv6, add your ssh key # - cat customConfig.optional nixos-infect | ssh root@targethost # # Alternatively, use the user data mechamism by supplying the following lines (without >) # in the Digital Ocean Web UI (or HTTP API): # # > #cloud-config # > # > runcmd: # > - curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | bash 2>&1 | tee /tmp/infect.log # # Potential tweaks: # /etc/nixos/{,hardware-}configuration.nix : rudimentary mostly static config # /etc/nixos/networking.nix, networking settings determined at runtime # tweak if no ipv6, different number of adapters, etc. # # Motivation for this script: nixos-assimilate should supplant this script # entirely, if it's ever completed. nixos-in-place was quite broken when I # tried it, and also took a pretty janky approach that was substantially more # complex than this (although it supported more platforms): it didn't install # to root (/nixos instead), left dregs of the old filesystem (almost always # unnecessary since starting from a fresh deployment), and most importantly, # simply didn't work for me! (old system was being because grub wasnt properly # reinstalled) set -ex export disk=$( (>/dev/null ls -l /dev/vda && echo vda) \ || (>/dev/null ls -l /dev/sda && echo sda) ) makeConf() { # NB <<"EOF" quotes / $ ` in heredocs, < /etc/nixos/configuration.nix << EOF { ... }: { imports = [ ./hardware-configuration.nix ./networking.nix # generated at runtime by nixos-infect ]; boot.cleanTmpDir = true; networking.hostName = "$(hostname)"; networking.firewall.allowPing = true; services.openssh.enable = true; users.users.root.openssh.authorizedKeys.keys = [$(for key in ${keys[@]}; do echo -n " \"$key\""; done) ]; } EOF # (nixos-generate-config will add qemu-user and bind-mounts, so avoid) cat > /etc/nixos/hardware-configuration.nix << EOF { ... }: { imports = [ ]; boot.loader.grub.device = "/dev/$disk"; fileSystems."/" = { device = "/dev/${disk}1"; fsType = "ext4"; }; } EOF local IFS=$'\n' eth0_ip4s=($(ip address show dev eth0 | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|')) eth0_ip6s=($(ip address show dev eth0 | grep 'inet6 .*global' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|')) eth1_ip4s=($(ip address show dev eth1 | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|')) eth1_ip6s=($(ip address show dev eth1 | grep 'inet6 .*global' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|')) gateway=($(ip route show dev eth0 | grep default | sed -r 's|default via ([0-9.]+).*|\1|')) gateway6=($(ip -6 route show dev eth0 | grep default | sed -r 's|default via ([0-9a-f:]+).*|\1|')) ether0=($(ip address show dev eth0 | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|')) ether1=($(ip address show dev eth1 | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|')) nameservers=($(grep ^nameserver /etc/resolv.conf | cut -f2 -d' ')) cat > /etc/nixos/networking.nix << EOF { ... }: { # This file was populated at runtime with the networking # details gathered from the active system. networking = { nameservers = [$(for a in ${nameservers[@]}; do echo -n " \"$a\""; done) ]; defaultGateway = "${gateway}"; defaultGateway6 = "${gateway6}"; interfaces = { eth0 = { ip4 = [$(for a in ${eth0_ip4s[@]}; do echo -n " $a"; done) ]; ip6 = [$(for a in ${eth1_ip6s[@]}; do echo -n " $a"; done) ]; }; eth1 = { ip4 = [$(for a in ${eth1_ip4s[@]}; do echo -n " $a"; done) ]; ip6 = [$(for a in ${eth1_ip6s[@]}; do echo -n " $a"; done) ]; }; }; }; services.udev.extraRules = '' KERNEL=="eth*", ATTR{address}=="${ether0}", NAME="eth0" KERNEL=="eth*", ATTR{address}=="${ether1}", NAME="eth1" ''; } EOF #! /usr/bin/env bash # NB put your semi-sensitive (not posted to github) configuration in a separate # file and include it via this customConfig() function. e.g.: # customConfig() { # cat > /etc/nixos/custom.nix << EOF # { config, lib, pkgs, ... }: { # } # EOF # } # # then you can add the files in configuration.nix's imports above and run something like: # cat customConfig nixos-infect | root@targethost bash if [[ `type -t customConfig` == "function" ]]; then customConfig; fi } makeSwap() { swapFile=`mktemp` dd if=/dev/zero of=$swapFile bs=1M count=$((1*1024)) chmod 0600 $swapFile mkswap $swapFile swapon $swapFile } makeConf makeSwap # smallest (512MB) droplet needs extra memory! which dnf && dnf install -y perl-Digest-SHA # Fedora 24 which bzcat || (which yum && yum install -y bzip2) # CentOS # DigitalOcean doesn't seem to set USER while running user data export USER="root" export HOME="/root" groupadd -r nixbld -g 30000 || true seq 1 10 | xargs -I{} useradd -c "Nix build user {}" -d /var/empty -g nixbld -G nixbld -M -N -r -s `which nologin` nixbld{} || true curl https://nixos.org/nix/install | sh source ~/.nix-profile/etc/profile.d/nix.sh [ -z "$NIX_CHANNEL"] && NIX_CHANNEL="nixos-16.09" nix-channel --remove nixpkgs nix-channel --add "https://nixos.org/channels/$NIX_CHANNEL" nixos nix-channel --update export NIXOS_CONFIG=/etc/nixos/configuration.nix nix-env --set \ -I nixpkgs=$HOME/.nix-defexpr/channels/nixos \ -f '' \ -p /nix/var/nix/profiles/system \ -A system # Remove nix installed with curl | bash rm -fv /nix/var/nix/profiles/default* /nix/var/nix/profiles/system/sw/bin/nix-collect-garbage # Follow the symlinks [ -L /etc/resolv.conf ] && mv -v /etc/resolv.conf /etc/resolv.conf.lnk && cat /etc/resolv.conf.lnk > /etc/resolv.conf # Staging for the Nix coup d'état touch /etc/NIXOS cat > /etc/NIXOS_LUSTRATE << EOF etc/nixos etc/resolv.conf root/.nix-defexpr/channels EOF rm -rf /boot.bak && mv -v /boot /boot.bak && /nix/var/nix/profiles/system/bin/switch-to-configuration boot reboot