├── .gitignore ├── README.adoc ├── cfg ├── apcupsd.nix ├── avahi.nix ├── base-big.nix ├── base-medium.nix ├── base-small.nix ├── bcache.nix ├── cgit.nix ├── clamav.nix ├── cpu-update-microcode.nix ├── deconz.nix ├── desktop-gnome3.nix ├── desktop-lxqt.nix ├── desktop-plasma5.nix ├── dictionary.nix ├── disable-suspend.nix ├── extra-host-addrs.nix ├── fhs-compat.nix ├── fonts.nix ├── fstrim.nix ├── git-daemon.nix ├── gitolite.nix ├── home-manager │ ├── dconf.nix │ ├── home.nix │ └── shell.nix ├── hydra.nix ├── kdeconnect.nix ├── kernel.nix ├── keyboard.nix ├── locate.nix ├── lttng.nix ├── max-perf-pct.nix ├── munin.nix ├── mytinytodo.nix ├── nix-path.nix ├── nix-remote-build-client.nix ├── nix-remote-build-server.nix ├── nix-settings.nix ├── nixpkgs-config.nix ├── nixpkgs-overlays.nix ├── popwk.nix ├── postfix.nix ├── pulseaudio.nix ├── resources.nix ├── shell.nix ├── skype-flip-camera.nix ├── smart-daemon.nix ├── software-defined-radio.nix ├── sudo.nix ├── swraid.nix ├── syncthing.nix ├── transmission.nix ├── virtualisation.nix └── xserver.nix ├── default.nix ├── deploy ├── doc └── disaster-recovery.adoc ├── home-network.nix ├── inputs ├── home-manager.json ├── home-manager.nix ├── nixpkgs.json ├── nixpkgs.nix ├── nur.json ├── nur.nix └── update.sh ├── isos └── livecd │ └── default.nix ├── lib └── default.nix ├── machines ├── media │ ├── configuration.nix │ └── hardware-configuration.nix ├── mini │ ├── configuration.nix │ └── hardware-configuration.nix └── srv1 │ ├── backup.nix │ ├── configuration.nix │ ├── ddclient.nix │ ├── hardware-configuration.nix │ └── syncthing.nix ├── options ├── borg-backup.nix ├── cifs-user-mount.nix ├── collectd-graph-panel.nix ├── deconz.nix ├── gitolite-mirror.nix ├── module-list.nix ├── motion.nix ├── nextcloud.nix ├── pia │ ├── pia-generated-server-list.nix │ ├── pia-nm.nix │ └── pia-server-list-generator.sh └── resources.nix ├── pkgs ├── altera-quartus │ ├── default.nix │ ├── generic.nix │ ├── patches │ │ └── glibc │ │ │ └── 0001-Avoid-.symver-on-common-symbols-BZ-21666.patch │ └── sources.nix ├── custom-desktop-entries │ └── default.nix ├── deconz │ └── default.nix ├── default.nix ├── git │ └── default.nix ├── keil-uvision-c51 │ ├── UV4 │ └── default.nix ├── ltsa │ └── default.nix ├── max_perf_pct │ ├── default.nix │ └── max_perf_pct ├── mini-ci │ ├── default.nix │ └── mini-ci.sh ├── nix-check-before-push │ └── default.nix ├── popwk │ ├── default.nix │ └── popwk.sh ├── roomeqwizard │ └── default.nix ├── tmux │ ├── default.nix │ └── tmux.conf ├── vim │ ├── default.nix │ └── vimrc └── winusb │ └── default.nix ├── profiles ├── backup-server.nix └── webserver.nix ├── resources ├── host-addrs.nix └── ssh-keys.nix └── users ├── bf.nix └── media.nix /.gitignore: -------------------------------------------------------------------------------- 1 | /configuration.nix 2 | /hardware-configuration.nix 3 | /doc/*.html 4 | /result 5 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | nixos-config 2 | ============ 3 | Bjørn Forsman 4 | 5 | Configuration files for my https://nixos.org/[NixOS] machines. 6 | 7 | Installation: 8 | 9 | ---- 10 | sudo mv /etc/nixos /etc/nixos.bak 11 | sudo git clone https://github.com/bjornfor/nixos-config /etc/nixos 12 | sudo cp /etc/nixos.bak/hardware-configuration.nix /etc/nixos/ 13 | sudo ln -sr /etc/nixos/machines/$MACHINE/configuration.nix /etc/nixos/configuration.nix 14 | ---- 15 | -------------------------------------------------------------------------------- /cfg/apcupsd.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | services.apcupsd = { 5 | enable = true; 6 | hooks.doshutdown = '' 7 | HOSTNAME=$(${pkgs.nettools}/bin/hostname) 8 | printf "Subject: apcupsd: $HOSTNAME is shutting down\n" | /run/wrappers/bin/sendmail root 9 | ''; 10 | hooks.onbattery = '' 11 | HOSTNAME=$(${pkgs.nettools}/bin/hostname) 12 | printf "Subject: apcupsd: $HOSTNAME is running on battery\n" | /run/wrappers/bin/sendmail root 13 | ''; 14 | hooks.offbattery = '' 15 | HOSTNAME=$(${pkgs.nettools}/bin/hostname) 16 | printf "Subject: apcupsd: $HOSTNAME is running on mains power\n" | /run/wrappers/bin/sendmail root 17 | ''; 18 | configText = '' 19 | UPSTYPE usb 20 | NISIP 127.0.0.1 21 | BATTERYLEVEL 75 22 | MINUTES 10 23 | #TIMEOUT 10 # for debugging, shutdown after N seconds on batteries 24 | ''; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /cfg/avahi.nix: -------------------------------------------------------------------------------- 1 | { 2 | services = { 3 | avahi = { 4 | enable = true; 5 | nssmdns = true; 6 | publish.enable = true; 7 | publish.addresses = true; 8 | publish.workstation = true; 9 | }; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /cfg/base-big.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ 5 | ./base-medium.nix 6 | ./virtualisation.nix 7 | ]; 8 | 9 | environment.systemPackages = with pkgs; [ 10 | (asciidoc-full.override { enableExtraPlugins = true; }) 11 | anki # flash card learning application 12 | aspell 13 | aspellDicts.en 14 | aspellDicts.nb 15 | bind 16 | bmon 17 | llvmPackages.clang # for libclang, required by clang_complete.vim 18 | clangAnalyzer # a.k.a. scan-build 19 | cmakeWithGui 20 | dash 21 | dhex 22 | dia 23 | dstat 24 | eagle 25 | (eclipses.eclipseWithPlugins { 26 | eclipse = eclipses.eclipse-cpp; 27 | jvmArgs = [ "-Xmx2048m" ]; 28 | plugins = with eclipses.plugins; 29 | [ cdt gnuarmeclipse ]; 30 | }) 31 | elinks 32 | evtest 33 | filezilla 34 | freecad 35 | gitAndTools.qgit 36 | gnome3.dconf # Required by virt-manager to store settings (dconf-service will be started when needed). NOTE: enabling GNOME 3 desktop auto-enables this. 37 | gource 38 | gparted 39 | graphviz 40 | gsmartcontrol 41 | hexchat 42 | iftop 43 | ioping 44 | irssi 45 | lftp 46 | libfaketime 47 | libreoffice 48 | linssid 49 | ltsa 50 | config.boot.kernelPackages.perf 51 | ltrace 52 | lynx 53 | meld 54 | mercurial 55 | nfs-utils 56 | nmap_graphical 57 | offlineimap 58 | openconnect 59 | openocd 60 | openscad 61 | pencil 62 | (pidgin-with-plugins.override { plugins = [ pidginsipe ]; }) 63 | poppler 64 | pulseview # sigrok GUI 65 | pwgen 66 | qemu 67 | qmmp 68 | #qtcreator 69 | remake 70 | remmina 71 | riot-desktop 72 | roomeqwizard 73 | saleae-logic 74 | shotwell 75 | sigrok-cli 76 | simplescreenrecorder 77 | skype 78 | slack 79 | sloccount 80 | socat 81 | solfege 82 | spice 83 | spotify 84 | srecord 85 | stellarium 86 | strace 87 | subversion 88 | surfraw 89 | sweethome3d.application 90 | #teamviewer # changes hash all the time 91 | unoconv 92 | virtmanager 93 | virtviewer 94 | wineUnstable 95 | winpdb 96 | wirelesstools 97 | wpa_supplicant 98 | wpa_supplicant_gui 99 | youtube-dl 100 | zoom-us 101 | ]; 102 | } 103 | -------------------------------------------------------------------------------- /cfg/base-medium.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ 5 | ./base-small.nix 6 | ./munin.nix 7 | ./desktop-gnome3.nix 8 | ./dictionary.nix 9 | ./locate.nix 10 | ./postfix.nix 11 | ./pulseaudio.nix 12 | ./syncthing.nix 13 | ]; 14 | 15 | hardware.sane.enable = true; # scanner support 16 | 17 | hardware.bluetooth.enable = true; 18 | 19 | hardware.opengl.driSupport32Bit = true; 20 | 21 | environment.systemPackages = with pkgs; [ 22 | apg 23 | arp-scan 24 | ascii 25 | bc 26 | borgbackup 27 | bridge-utils 28 | ccls 29 | chromium 30 | cifs_utils # for mount.cifs, needed for cifs filesystems in systemd.mounts. 31 | cquery 32 | ddrescue 33 | diffstat 34 | dmidecode 35 | dos2unix 36 | exfat 37 | exiftool 38 | exiv2 39 | file 40 | firefox 41 | gcc 42 | gdb 43 | gitAndTools.git-recent 44 | gitFull 45 | gnumake 46 | hdparm 47 | htop 48 | iotop 49 | iptables 50 | iw 51 | jq 52 | keepassxc 53 | lm_sensors 54 | lshw 55 | lsof 56 | manpages # for "man 2 fork" etc. 57 | minicom 58 | mosh 59 | msmtp 60 | mtr 61 | mutt 62 | my.nix-check-before-push 63 | my.custom-desktop-entries.gmail 64 | my.custom-desktop-entries.netflix 65 | my.custom-desktop-entries.sbanken 66 | my.custom-desktop-entries.tv-get-no 67 | my.custom-desktop-entries.tv-nrk-no 68 | my.custom-desktop-entries.youtube 69 | ncdu 70 | nethogs 71 | networkmanager 72 | networkmanagerapplet 73 | nixops 74 | nixpkgs-fmt 75 | nixpkgs-lint 76 | nix-bash-completions 77 | nix-generate-from-cpan 78 | nix-index 79 | nix-prefetch-scripts 80 | nix-review 81 | nix-serve 82 | nix-top 83 | ntfs3g 84 | owncloud-client 85 | p7zip 86 | parted 87 | patchelf 88 | pavucontrol 89 | perlPackages.ImageExifTool 90 | pciutils 91 | picocom 92 | posix_man_pages 93 | powertop 94 | psmisc 95 | pv 96 | (python3Full.withPackages (ps: [ 97 | (python3.pkgs.buildPythonPackage rec { 98 | pname = "nix-bisect"; 99 | version = "0.2.0"; 100 | src = pkgs.fetchFromGitHub { 101 | owner = "timokau"; 102 | repo = "nix-bisect"; 103 | rev = "v${version}"; 104 | sha256 = "0rg7ndwbn44kximipabfbvvv5jhgi6vs87r64wfs5by81iw0ivam"; 105 | }; 106 | }) 107 | ])) 108 | (python3Packages.ipython.overrideAttrs (oldAttrs: { 109 | propagatedBuildInputs = (oldAttrs.propagatedBuildInputs or []) ++ [ 110 | python3Packages.sympy 111 | ]; 112 | })) 113 | python2nix 114 | python3Packages.glances 115 | ripgrep 116 | rls 117 | rmlint 118 | samba 119 | scrcpy 120 | silver-searcher 121 | smartmontools 122 | sqlite-interactive 123 | sshfsFuse 124 | sshuttle 125 | stdmanpages 126 | sysstat 127 | taskwarrior 128 | tcpdump 129 | tmuxp 130 | torbrowser 131 | traceroute 132 | tree 133 | unrar 134 | unzip 135 | usbutils 136 | vbindiff 137 | vifm 138 | vlc 139 | wavemon 140 | wget 141 | wgetpaste 142 | which 143 | wireshark 144 | w3m 145 | xournalpp 146 | xpra 147 | yubico-piv-tool 148 | yubikey-personalization 149 | yubikey-personalization-gui 150 | ] 151 | # nix-repl was replaced by the built-in "nix repl" from nix in nixos-18.09. 152 | ++ (lib.optional (lib.versionOlder (lib.version or lib.nixpkgsVersion) "18.09") nix-repl); 153 | 154 | networking.networkmanager.pia-vpn.enable = true; 155 | networking.networkmanager.pia-vpn.usernameFile = "/etc/pia-vpn.username"; 156 | networking.networkmanager.pia-vpn.passwordFile = "/etc/pia-vpn.password"; 157 | networking.networkmanager.pia-vpn.serverList = 158 | [ "denmark" "fi" "nl" "no" "sweden" "uk-london" "us-newyorkcity" ]; 159 | 160 | programs.adb.enable = true; 161 | 162 | programs.chromium = { 163 | enable = true; 164 | # Imperatively installed extensions will seamlessly merge with these. 165 | # Removing extensions here will remove them from chromium, no matter how 166 | # they were installed. 167 | extensions = [ 168 | "cmedhionkhpnakcndndgjdbohmhepckk" # Adblock for Youtube™ 169 | "iaalpfgpbocpdfblpnhhgllgbdbchmia" # Asciidoctor.js Live Preview 170 | "gcbommkclmclpchllfjekcdonpmejbdp" # HTTPS Everywhere 171 | "oboonakemofpalcgghocfoadofidjkkk" # KeePassXC-Browser 172 | "dbepggeogbaibhgnhhndojpepiihcmeb" # Vimium 173 | ]; 174 | }; 175 | 176 | programs.sysdig.enable = true; 177 | 178 | programs.wireshark.enable = true; 179 | 180 | services = { 181 | atd.enable = true; 182 | 183 | # TODO: When mouse gets hidden, the element below mouse gets focus 184 | # periodically (annoying). Might try the unclutter fork (see Archlinux) or 185 | # xbanish. 186 | #unclutter.enable = true; 187 | 188 | fail2ban.enable = true; 189 | fail2ban.jails.ssh-iptables = '' 190 | enabled = true 191 | ''; 192 | 193 | # cups, for printing documents 194 | printing.enable = true; 195 | printing.drivers = with pkgs; [ gutenprint ]; 196 | 197 | # for hamster-time-tracker 198 | dbus.packages = with pkgs; [ gnome2.GConf ]; 199 | 200 | # Provide "MODE=666" or "MODE=664 + GROUP=plugdev" for a bunch of USB 201 | # devices, so that we don't have to run as root. 202 | udev.packages = with pkgs; [ 203 | saleae-logic openocd libu2f-host yubikey-personalization 204 | ]; 205 | udev.extraRules = '' 206 | # Rigol oscilloscopes 207 | SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0588", MODE="0660", GROUP="usbtmc" 208 | 209 | # Atmel Corp. STK600 development board 210 | SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", ATTR{idProduct}=="2106", GROUP="plugdev", MODE="0660" 211 | 212 | # Atmel Corp. JTAG ICE mkII 213 | SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", ATTR{idProduct}=="2103", GROUP="plugdev", MODE="0660" 214 | 215 | # Atmel Corp. AVR Dragon 216 | SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", ATTR{idProduct}=="2107", GROUP="plugdev", MODE="0660" 217 | 218 | # Access to /dev/bus/usb/* devices. Needed for virt-manager USB 219 | # redirection. 220 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664", GROUP="wheel" 221 | 222 | # Allow users in group 'usbmon' to do USB tracing, e.g. in Wireshark 223 | # (after 'modprobe usbmon'). 224 | SUBSYSTEM=="usbmon", GROUP="usbmon", MODE="640" 225 | ''; 226 | 227 | samba = { 228 | #enable = true; 229 | nsswins = true; 230 | extraConfig = lib.mkBefore '' 231 | workgroup = WORKGROUP 232 | map to guest = Bad User 233 | 234 | [upload] 235 | path = /home/bf/upload 236 | read only = no 237 | guest ok = yes 238 | force user = bf 239 | ''; 240 | }; 241 | 242 | }; 243 | 244 | # Sources that often disappear from the internet and makes rebuilding 245 | # impossible without upgrading first. 246 | system.extraDependencies = with pkgs; [ 247 | flashplayer.src 248 | spotify.src 249 | torbrowser.src 250 | ]; 251 | } 252 | -------------------------------------------------------------------------------- /cfg/base-small.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ 5 | ./avahi.nix 6 | ./cpu-update-microcode.nix 7 | ./extra-host-addrs.nix 8 | ./fhs-compat.nix 9 | ./fonts.nix 10 | ./fstrim.nix 11 | ./kernel.nix 12 | ./keyboard.nix 13 | ./nix-path.nix 14 | ./nix-settings.nix 15 | ./resources.nix 16 | ./shell.nix 17 | ./sudo.nix 18 | 19 | ../options/module-list.nix 20 | ]; 21 | 22 | # List swap partitions activated at boot time. 23 | #swapDevices = [ 24 | # { device = "/dev/disk/by-label/swap"; } 25 | #]; 26 | 27 | boot.loader.grub = { 28 | enable = true; 29 | version = 2; 30 | # Define on which hard drive you want to install Grub. Set to "nodev" to 31 | # not install it to the MBR at all, but only install the boot menu. This is 32 | # handy if you have NixOS installed on a USB stick that gets a different 33 | # device name when you plug it in different ports or on different machines. 34 | # Then you install using "/dev/..." and set it to "nodev" afterwards. 35 | #device = /*lib.mkDefault*/ "nodev"; 36 | }; 37 | 38 | boot.tmpOnTmpfs = true; 39 | 40 | security.wrappers = {} 41 | // (if (builtins.elem pkgs.smartmontools config.environment.systemPackages) then { 42 | smartctl = { 43 | # Limit access to smartctl to root and members of the munin group. 44 | source = "${pkgs.smartmontools}/bin/smartctl"; 45 | program = "smartctl"; 46 | owner = "root"; 47 | group = "munin"; 48 | setuid = true; 49 | setgid = false; 50 | permissions = "u+rx,g+x"; 51 | }; 52 | } else {}); 53 | 54 | nixpkgs.config = import ./nixpkgs-config.nix; 55 | nixpkgs.overlays = import ./nixpkgs-overlays.nix; 56 | 57 | time.timeZone = "Europe/Oslo"; 58 | 59 | # Block advertisement domains (see 60 | # http://winhelp2002.mvps.org/hosts.htm) 61 | #environment.etc."hosts".source = 62 | # pkgs.fetchurl { 63 | # url = "http://winhelp2002.mvps.org/hosts.txt"; 64 | # sha256 = "18as5cm295yyrns4i2hzxlb1h52x68gbnb1b3yksvzqs283pvbfi"; 65 | # }; 66 | 67 | # for "attic mount -o allow_other" to be shareable with samba 68 | environment.etc."fuse.conf".text = '' 69 | user_allow_other 70 | ''; 71 | 72 | environment.systemPackages = with pkgs; [ 73 | ctags # needed by vim (plugin) 74 | fzf 75 | moreutils 76 | morph 77 | my.git 78 | my.tmux 79 | my.vim 80 | tig 81 | ]; 82 | 83 | home-manager = { 84 | # Set options recommended when running on NixOS (ref. 85 | # https://rycee.gitlab.io/home-manager/#sec-install-nixos-module). 86 | useGlobalPkgs = true; 87 | useUserPackages = true; 88 | 89 | # auto-rename unmanaged files in $HOME 90 | backupFileExtension = "before-home-manager"; 91 | }; 92 | 93 | services = { 94 | fwupd.enable = true; 95 | openssh = { 96 | enable = true; 97 | forwardX11 = true; 98 | passwordAuthentication = false; 99 | extraConfig = '' 100 | AllowUsers backup git bf 101 | # For nix remote / distributed builds 102 | AllowUsers nix-remote-build 103 | 104 | # Doesn't work on NixOS: https://github.com/NixOS/nixpkgs/issues/18503 105 | ## Allow password authentication (only) from local network 106 | #Match Address 192.168.1.0/24 107 | # PasswordAuthentication yes 108 | # # End the match group so that any remaining options (up to the end 109 | # # of file) applies globally 110 | # Match All 111 | ''; 112 | }; 113 | }; 114 | 115 | systemd.services."status-email@" = { 116 | description = "Send Status Email For Unit %i"; 117 | path = [ "/run/wrappers" ]; 118 | serviceConfig = { 119 | Type = "oneshot"; 120 | # If running as nobody:systemd-journal the log is missing and this 121 | # warning is shown: 122 | # Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable. 123 | #User = "nobody"; 124 | #Goup = "systemd-journal"; 125 | SyslogIdentifier = "status-email"; 126 | ExecStart = 127 | let 128 | statusEmail = pkgs.writeScript "status-email" '' 129 | #!${pkgs.bash}/bin/sh 130 | set -e 131 | addr=$1 132 | unit=$2 133 | sendmail -t <<__EOF__ 134 | To: $addr 135 | From: systemd@$HOSTNAME 136 | Subject: $unit 137 | Content-Transfer-Encoding: 8bit 138 | Content-Type: text/plain; charset=UTF-8 139 | 140 | $(systemctl status --full "$unit" -n80) 141 | __EOF__ 142 | echo "Status mail sent to $addr for unit $unit" 143 | ''; 144 | in 145 | # Use config.postfix.rootAlias to configure who gets root's email. 146 | "${statusEmail} root %i"; 147 | }; 148 | }; 149 | 150 | # groups for managing permissions 151 | users.extraGroups = { 152 | plugdev = { }; 153 | tracing = { }; 154 | usbtmc = { }; 155 | usbmon = { }; 156 | }; 157 | } 158 | -------------------------------------------------------------------------------- /cfg/bcache.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | systemd.tmpfiles.rules = 5 | if builtins.elem "bcache" config.boot.initrd.availableKernelModules then [ 6 | # Backing device 7 | "w /sys/block/bcache*/bcache/sequential_cutoff - - - - ${builtins.toString (256*1024*1024)}" # default: 4MiB 8 | "w /sys/block/bcache*/bcache/cache_mode - - - - writeback" # default: writethrough 9 | "w /sys/block/bcache*/bcache/writeback_percent - - - - 30" # default: 10 10 | 11 | # Cache device. 12 | # Prevent reads and writes going to the hdd when the ssd is slow, because 13 | # using this feature doesn't work well in my experience. Things become even 14 | # slower. 15 | "w /sys/fs/bcache/*/congested_read_threshold_us - - - - 0" # default: 2000 16 | "w /sys/fs/bcache/*/congested_write_threshold_us - - - - 0" # default: 20000 17 | ] else []; 18 | } 19 | -------------------------------------------------------------------------------- /cfg/cgit.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | myDomain = "bforsman.name"; 5 | in 6 | { 7 | services.lighttpd = { 8 | enable = true; 9 | extraConfig = lib.mkAfter '' 10 | $HTTP["url"] =~ "^/cgit" { 11 | setenv.add-environment += ( 12 | ${let 13 | pythonEnv = pkgs.python3.buildEnv.override { 14 | extraLibs = with pkgs.python3Packages; [ pygments ]; 15 | }; 16 | cgitPath = with pkgs; lib.makeBinPath [ pythonEnv ]; 17 | in '' 18 | "PATH" => "${cgitPath}:" + env.PATH 19 | ''} 20 | ) 21 | } 22 | ''; 23 | cgit = { 24 | enable = true; 25 | configText = '' 26 | # HTTP endpoint for git clone is enabled by default 27 | #enable-http-clone=1 28 | 29 | # Specify clone URLs using macro expansion 30 | clone-url=http://${myDomain}/cgit/$CGIT_REPO_URL https://${myDomain}/cgit/$CGIT_REPO_URL git://${myDomain}/$CGIT_REPO_URL git@${myDomain}:$CGIT_REPO_URL 31 | 32 | # Show pretty commit graph 33 | #enable-commit-graph=1 34 | 35 | # Show number of affected files per commit on the log pages 36 | enable-log-filecount=1 37 | 38 | # Show number of added/removed lines per commit on the log pages 39 | enable-log-linecount=1 40 | 41 | # Enable 'stats' page and set big upper range 42 | max-stats=year 43 | 44 | # Allow download of archives in the following formats 45 | snapshots=tar.xz zip 46 | 47 | # Don't show the .git suffix of repositories. 48 | remove-suffix=1 49 | 50 | # Enable caching of up to 1000 output entries 51 | cache-size=1000 52 | 53 | # Filter for files shown in the "about" page 54 | about-filter=${pkgs.writeScript "cgit-about-filter.sh" '' 55 | #!${pkgs.bash}/bin/sh 56 | # The filename is available as first argument, but the filter 57 | # should read contents from STDIN (and write to STDOUT). 58 | filename=$1 59 | case "$filename" in 60 | *.asciidoc|*.adoc) 61 | exec ${pkgs.asciidoctor}/bin/asciidoctor --safe --no-header-footer - -o - 62 | # Dropping --safe with asciidoc because: 63 | # asciidoc: ERROR: : line 3: unsafe: ifeval invalid 64 | #exec ''${pkgs.asciidoc}/bin/asciidoc --no-header-footer - 65 | ;; 66 | *.markdown|*.md) 67 | exec ${pkgs.pandoc}/bin/pandoc -f markdown -t html 68 | ;; 69 | *) 70 | echo "
"
 71 |                   ${pkgs.coreutils}/bin/cat
 72 |                   echo "
" 73 | ;; 74 | esac 75 | ''} 76 | 77 | commit-filter=${pkgs.writeScript "cgit-commit-filter.sh" '' 78 | #!${pkgs.bash}/bin/sh 79 | regex= 80 | # This expression generates links to commits referenced by their SHA1. 81 | regex=$regex' 82 | s|\b([0-9a-fA-F]{7,40})\b|\1|g' 83 | 84 | # This expression generates links to a bugtracker. 85 | #regex=$regex' 86 | #s|#([0-9]+)\b|#\1|g' 87 | 88 | # Apply the transformation 89 | sed -re "$regex" 90 | ''} 91 | 92 | source-filter=${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py 93 | 94 | # Search for these files in the root of the default branch of 95 | # repositories for coming up with the about page: 96 | readme=:README.asciidoc 97 | readme=:README.adoc 98 | readme=:README.markdown 99 | readme=:README.md 100 | readme=:README.txt 101 | readme=:README 102 | 103 | # Group repositories on the index page by sub-directory name 104 | section-from-path=1 105 | 106 | # Allow using gitweb.* keys 107 | enable-git-config=1 108 | 109 | # (Can be) maintained by gitolite 110 | project-list=${config.services.gitolite.dataDir}/projects.list 111 | 112 | # scan-path must be last so that earlier settings take effect when 113 | # scanning 114 | scan-path=${config.services.gitolite.dataDir}/repositories 115 | ''; 116 | }; 117 | }; 118 | } 119 | -------------------------------------------------------------------------------- /cfg/clamav.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | services = { 5 | clamav = { 6 | updater.enable = true; 7 | updater.frequency = 1; # number of checks per day 8 | }; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /cfg/cpu-update-microcode.nix: -------------------------------------------------------------------------------- 1 | { 2 | hardware.cpu.amd.updateMicrocode = true; 3 | hardware.cpu.intel.updateMicrocode = true; 4 | } 5 | -------------------------------------------------------------------------------- /cfg/deconz.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | local.services.deconz = { 5 | enable = true; 6 | httpPort = 1080; 7 | #httpPort = 80; # trying to work around https://github.com/dresden-elektronik/deconz-rest-plugin/issues/1788 ("Auth problems on non-80 http port") 8 | wsPort = 1443; 9 | openFirewall = true; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /cfg/desktop-gnome3.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ ./xserver.nix ]; 5 | 6 | services.xserver = { 7 | displayManager.gdm.enable = true; 8 | desktopManager.gnome3.enable = true; 9 | }; 10 | 11 | environment.systemPackages = with pkgs; [ 12 | # Extensions must be manually enabled in GNOME Tweaks (previously named 13 | # Tweak Tool). Adding them here only makes them available, but not active. 14 | gnomeExtensions.clipboard-indicator 15 | gnomeExtensions.dash-to-dock 16 | gnomeExtensions.gsconnect 17 | gnomeExtensions.system-monitor 18 | 19 | gnome3.dconf-editor 20 | 21 | gnome3.gnome-documents 22 | gnome3.gnome-nettool 23 | gnome3.gnome-power-manager 24 | gnome3.gnome-todo 25 | gnome3.gnome-tweaks 26 | gnome3.gnome-usage 27 | ] ++ 28 | (with lib; 29 | # removed in nixos 20.03, it's part of GNOME3 now 30 | optional (versionOlder version "20.03") 31 | gnomeExtensions.nohotcorner 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /cfg/desktop-lxqt.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ ./xserver.nix ]; 5 | 6 | services.xserver = { 7 | displayManager.sddm.enable = true; 8 | desktopManager.lxqt.enable = true; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /cfg/desktop-plasma5.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ ./xserver.nix ]; 5 | 6 | services.xserver = { 7 | displayManager.sddm.enable = true; 8 | desktopManager.plasma5.enable = true; 9 | }; 10 | 11 | environment.systemPackages = with pkgs; [ 12 | kdeApplications.ark 13 | kdeApplications.gwenview 14 | kdeApplications.okular 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /cfg/dictionary.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | myDictDBs = with pkgs.dictdDBs; [ wiktionary wordnet ]; 5 | in 6 | { 7 | # dictd can be used by tools like goldendict, gnome-dictionary. 8 | services.dictd = { 9 | enable = true; 10 | DBs = myDictDBs; 11 | }; 12 | 13 | environment.systemPackages = with pkgs; [ 14 | # Offline wordnet dictionary. 15 | # Global hotkey to lookup a word: Ctrl + Alt + W. 16 | artha 17 | 18 | # goldendict hotkey to lookup a word: Ctrl-c-c. 19 | # Dictionaries in goldendict must be manually configured: 20 | # 1. Go to "Edit -> Dictionaries -> DICTD servers" and add/enable the local 21 | # dictd server (dict://localhost). 22 | # Alternatively: Don't use dictd service and load the dict files 23 | # directly. Go to "Edit -> Dictionaries -> Files" and add 24 | # /run/current-system/sw/share/dictd. 25 | # 2. Go to Dictionaries tab ("Edit -> Dictionaries -> Dictionaries" -- yes, 26 | # twice) and set desired dictionary order/priority. 27 | # 3. Optional: Add separate DICT server entries, each limited to a single 28 | # database. (To list databases, `dict --host localhost --dbs`). Doing 29 | # this makes it easier to see where each result comes from, since 30 | # goldendict highlights the start of new dictionary result set more than 31 | # multiple results within a dictionary. IOW, results from all 32 | # services.dictd.DBs are not visually "squashed" together as much. 33 | # 4. Optional: Add hunspell dictionaries for catching spelling mistakes. 34 | # Go to "Edit -> Dictionaries -> Morphology" and add 35 | # "/run/current-system/sw/share/hunspell". 36 | goldendict 37 | ] ++ (with hunspellDicts; [ en-us ]) 38 | ++ myDictDBs; 39 | } 40 | -------------------------------------------------------------------------------- /cfg/disable-suspend.nix: -------------------------------------------------------------------------------- 1 | { 2 | # Disable the GNOME3/GDM auto-suspend feature that cannot be disabled in GUI! 3 | # If no user is logged in, the machine will power down after 20 minutes. 4 | systemd.targets.sleep.enable = false; 5 | systemd.targets.suspend.enable = false; 6 | systemd.targets.hibernate.enable = false; 7 | systemd.targets.hybrid-sleep.enable = false; 8 | } 9 | -------------------------------------------------------------------------------- /cfg/extra-host-addrs.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | hostAddrs = config.local.resources.hostAddrs; 5 | in 6 | { 7 | networking.extraHosts = 8 | let 9 | list = lib.mapAttrsToList (n: v: "${v} ${n}") hostAddrs; 10 | extraHosts = lib.concatStringsSep "\n" list; 11 | in 12 | extraHosts; 13 | } 14 | -------------------------------------------------------------------------------- /cfg/fhs-compat.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | # Make it easier to work with external scripts 5 | system.activationScripts.fhsCompat = '' 6 | fhscompat=0 # set to 1 or 0 7 | if [ "$fhscompat" = 1 ]; then 8 | echo "enabling (simple) FHS compatibility" 9 | mkdir -p /bin /usr/bin 10 | ln -sfv ${pkgs.bash}/bin/sh /bin/bash 11 | ln -sfv ${pkgs.perl}/bin/perl /usr/bin/perl 12 | ln -sfv ${pkgs.python3Full}/bin/python /usr/bin/python 13 | ln -sfv ${pkgs.python3Full}/bin/python /usr/bin/python3 14 | else 15 | # clean up 16 | find /bin /usr/bin -type l | while read file; do if [ "$file" != "/bin/sh" -a "$file" != "/usr/bin/env" ]; then rm -v "$file"; fi; done 17 | fi 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /cfg/fonts.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | fonts.fonts = with pkgs; [ 5 | #python3Packages.powerline # looks ok 6 | powerline-fonts # looks better 7 | ]; 8 | } 9 | -------------------------------------------------------------------------------- /cfg/fstrim.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.fstrim = { 3 | enable = true; 4 | interval = "daily"; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /cfg/git-daemon.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | gitDaemonUser = "git-daemon"; 5 | gitDaemonGroup = "git-daemon"; 6 | gitoliteGroup = config.users.extraUsers."${config.services.gitolite.user}".group; 7 | in 8 | { 9 | services = { 10 | gitDaemon.enable = true; 11 | gitDaemon.basePath = config.services.gitolite.dataDir + "/repositories"; 12 | gitDaemon.user = gitDaemonUser; 13 | gitDaemon.group = gitDaemonGroup; 14 | # only serve repositories containing 'git-daemon-export-ok' file 15 | gitDaemon.exportAll = false; 16 | }; 17 | 18 | # The NixOS git-daemon service configures a 'git' user and group. This cause 19 | # a conflict because we've assigned this name to the gitolite hosting user. 20 | # The gitolite (hosting) user must be allowed to login to the system, whereas 21 | # the git-daemon user doesn't need that. Also, git-daemon never needs to 22 | # write anything to the git repositories, so using a separate user for 23 | # git-daemon with only read access seems like a good idea. 24 | users.extraUsers."${gitDaemonUser}" = { 25 | description = "Git Daemon User"; 26 | uid = 506; 27 | group = gitDaemonGroup; 28 | extraGroups = [ gitoliteGroup ]; /* get read-only access to gitolite repos */ 29 | }; 30 | 31 | users.extraGroups."${gitDaemonGroup}" = { 32 | gid = 506; 33 | }; 34 | 35 | # So that git doesn't die when it sees a '~' in /etc/gitconfig 36 | systemd.services.git-daemon.environment.HOME = "/var/empty"; 37 | } 38 | -------------------------------------------------------------------------------- /cfg/gitolite.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | miniciGcRootDir = "/nix/var/nix/gcroots/mini-ci"; 5 | 6 | mini-ci = pkgs.my.mini-ci.override { 7 | repositories = "${config.services.gitolite.dataDir}/repositories"; 8 | miniciGcRootDir = miniciGcRootDir; 9 | }; 10 | 11 | # Make a VREF script that takes one optional argument. 12 | # Usage (in gitolite-admin.git/gitolite.conf): 13 | # - VREF/$name = @all # run on all branches/refs 14 | # - VREF/$name/master = @all # run only on master branch 15 | # - VREF/$name/refs/tags/[0-9] = @all # run only on these tag patterns 16 | mkVrefScript = name: text: 17 | pkgs.writeScript name '' 18 | #!${pkgs.bash}/bin/bash 19 | # Description of VREFs arguments is here: 20 | # http://gitolite.com/gitolite/vref.html#what-arguments-are-passed-to-the-vref-maker 21 | ref=$1 22 | oldsha=$2 23 | newsha=$3 24 | oldtree=$4 25 | newtree=$5 26 | access_flag=$6 27 | refex=$7 # full refex, e.g. VREF/COUNT/3/NEWFILES 28 | # Arg 8...N is the refex split by '/', just as a convenience 29 | 30 | selfname="${name}" 31 | # Get the (expanded) ref, like gitolite does. Basically, refs must be 32 | # fully qualified. If not, they are treated as branch names. 33 | vref_ref_arg=$(echo "$refex" | sed -e "s|VREF/$selfname.\?||") 34 | case "$vref_ref_arg" in 35 | refs/heads/*|refs/tags/*) 36 | true # nop 37 | ;; 38 | *) 39 | vref_ref_arg="refs/heads/$vref_ref_arg" 40 | ;; 41 | esac 42 | 43 | # We stop only if $vref_ref_arg is non-empty AND not matching the ref 44 | # that is about to be pushed. Matches are only pinned to start of word 45 | # (regex '^'), like in gitolite. 46 | if [ "x$vref_ref_arg" != x ] && ! echo "$ref" | grep -q "^$vref_ref_arg"; then 47 | exit 0 # silently stop 48 | fi 49 | 50 | # Business logic 51 | ${text} 52 | ''; 53 | 54 | # Custom gitolite VREFs (virtual refs scripts), that can be enabled in 55 | # gitolite-admin.git. 56 | vref = { 57 | # Run nix-build at git push time and cache the result. Branches and tags 58 | # are "cached" indefinitely, so it is also an automatic artifact server. 59 | # Build failures aborts the push. Take care to place this as the last 60 | # VREF (if more than one). 61 | mini-ci = mkVrefScript "mini-ci" '' 62 | ${mini-ci}/bin/mini-ci hook --repo="$GL_REPO" --oldrev="$oldsha" --newrev="$newsha" --ref="$ref" 63 | ''; 64 | }; 65 | in 66 | { 67 | services.gitolite = { 68 | enable = true; 69 | dataDir = "/var/lib/gitolite"; 70 | # Initial admin key (ssh) 71 | adminPubkey = config.local.resources.sshKeys.mini.bf.default; 72 | user = "git"; 73 | group = "git"; 74 | extraGitoliteRc = 75 | let 76 | generatedLocalCode = pkgs.runCommand "gitolite-local-code" {} '' 77 | mkdir -p "$out/VREF" 78 | ln -s "${vref.mini-ci}" "$out"/VREF/mini-ci 79 | ''; 80 | in 81 | '' 82 | # Make dirs/files group readable, needed for webserver/cgit. (Default 83 | # setting is 0077.) 84 | $RC{UMASK} = 0027; 85 | 86 | $RC{GIT_CONFIG_KEYS} = '.*'; 87 | 88 | $RC{LOCAL_CODE} = '${generatedLocalCode}'; 89 | 90 | # Allow creators of "wild repos" to delete their own repos. 91 | push( @{$RC{ENABLE}}, 'D' ); 92 | ''; 93 | }; 94 | 95 | # For convenience / testing 96 | environment.systemPackages = [ mini-ci ]; 97 | 98 | systemd.tmpfiles.rules = 99 | let 100 | user = config.services.gitolite.user; 101 | group = config.services.gitolite.group; 102 | in 103 | [ #Type Path Mode UID GID Age Argument 104 | "d ${miniciGcRootDir} 0755 ${user} ${group} - -" 105 | ]; 106 | 107 | systemd.services.mini-ci-gc = { 108 | description = "Mini-CI Garbage Collection"; 109 | startAt = "daily"; 110 | script = '' 111 | ${mini-ci}/bin/mini-ci gc 112 | ''; 113 | serviceConfig.User = config.services.gitolite.user; 114 | serviceConfig.Group = config.services.gitolite.group; 115 | unitConfig.Documentation = "file://${mini-ci}/bin/mini-ci"; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /cfg/home-manager/dconf.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, ... }: 2 | 3 | { 4 | dconf.settings = { 5 | "org/gnome/desktop/interface" = { 6 | gtk-theme = "Adwaita-dark"; 7 | }; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /cfg/home-manager/home.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, ... }: 2 | 3 | { 4 | imports = [ 5 | ./dconf.nix 6 | ./shell.nix 7 | ]; 8 | } 9 | -------------------------------------------------------------------------------- /cfg/home-manager/shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, ... }: 2 | 3 | { 4 | programs.bash = { 5 | enable = true; 6 | historyControl = [ 7 | "ignoredups" 8 | "ignorespace" 9 | ]; 10 | historyFileSize = 1000000; 11 | historySize = 1000000; # big big history 12 | initExtra = '' 13 | # Continuously save history. 14 | # Use "history -n" to load global history into the shell on demand. This is 15 | # not on by default because it'd be pretty confusing if arrow-up shows 16 | # stuff from _other_ sessions. 17 | _append_history() 18 | { 19 | # preserve exit code 20 | local ret=$? 21 | history -a 22 | return "$ret" 23 | } 24 | # Add trailing semi-colon, if needed. (Two consecutive semi-colons is an 25 | # error.) 26 | if [ "''${PROMPT_COMMAND}" != "" ] && [ "''${PROMPT_COMMAND: -1}" != ";" ]; then 27 | PROMPT_COMMAND+=";" 28 | fi 29 | PROMPT_COMMAND+="_append_history;" 30 | ''; 31 | shellAliases = { 32 | ".." = "cd .."; 33 | "..." = "cd ../.."; 34 | "..2" = "cd ../.."; 35 | "..3" = "cd ../../.."; 36 | "..4" = "cd ../../../.."; 37 | g = "git"; 38 | grep = "grep --color=auto"; 39 | t = "task"; 40 | tmuxm = "tmux new -A -s main"; 41 | }; 42 | shellOptions = [ 43 | "histappend" 44 | ]; 45 | }; 46 | 47 | programs.bat.enable = true; 48 | 49 | programs.direnv = { 50 | enable = true; 51 | enableNixDirenvIntegration = true; 52 | }; 53 | 54 | programs.fzf.enable = true; 55 | 56 | programs.starship = { 57 | enable = true; 58 | settings = 59 | let 60 | disabledModules = [ "python" "java" ]; 61 | in 62 | (lib.genAttrs disabledModules (x: { disabled = true; })) 63 | // { character.symbol = "$"; }; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /cfg/hydra.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | # After rebuilding NixOS with this module you have manually create users. 4 | # Example: 5 | # sudo -E -u hydra hydra-create-user $USER --password $PASSWORD --role admin 6 | 7 | { 8 | services.hydra = { 9 | enable = true; 10 | hydraURL = "http://hydra.bforsman.name"; 11 | minimumDiskFree = 10; # GiB 12 | minimumDiskFreeEvaluator = 10; # GiB 13 | notificationSender = "hydra-noreply@bforsman.name"; 14 | #port = 3000; # web server TCP port 15 | #smtpHost = "localhost"; 16 | }; 17 | 18 | systemd.services.hydra-evaluator = { 19 | # This allows Hydra to evaluate very large derivations if necessary. 20 | # Fixes "Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS". 21 | environment."GC_INITIAL_HEAP_SIZE" = "16G"; 22 | }; 23 | 24 | nix = { 25 | useSandbox = true; 26 | buildCores = lib.mkOverride 90 0; # 0 is special, it means "use all available CPU cores" 27 | nrBuildUsers = lib.mkOverride 90 32; 28 | # Define build slaves (need at least one). 29 | buildMachines = [ 30 | { hostName = "localhost"; 31 | systems = [ "builtin" "x86_64-linux" "i686-linux" ]; 32 | supportedFeatures = [ "kvm" "nixos-test" "big-parallel" "benchmark" ]; 33 | maxJobs = "12"; 34 | } 35 | ]; 36 | extraOptions = '' 37 | build-timeout = 86400 # 24 hours 38 | ''; 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /cfg/kdeconnect.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | ports = { from = 1714; to = 1764; }; 5 | kdeConnectImpl = 6 | if config.services.xserver.desktopManager.gnome3.enable then 7 | pkgs.gnomeExtensions.gsconnect 8 | else if config.services.xserver.desktopManager.plasma5.enable then 9 | pkgs.kdeconnect 10 | else 11 | throw "Don't know which KDE Connect implementation to use for this desktop"; 12 | in 13 | { 14 | environment.systemPackages = [ kdeConnectImpl ]; 15 | 16 | networking.firewall = { 17 | allowedTCPPortRanges = [ ports ]; 18 | allowedUDPPortRanges = [ ports ]; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /cfg/kernel.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | # Select Linux version 5 | boot.kernelPackages = pkgs.linuxPackages; 6 | } 7 | -------------------------------------------------------------------------------- /cfg/keyboard.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | { 4 | # This does not _enable_ X11, so it can still be used by headless configs. 5 | services.xserver = { 6 | layout = "no"; 7 | # For xkbOptions inspiration, see 8 | # $(nix-build -A xkeyboard_config)/share/X11/xkb/rules/base.lst 9 | xkbOptions = "ctrl:nocaps"; # Caps Lock as Ctrl 10 | }; 11 | } 12 | // ( 13 | if lib.versionAtLeast lib.version "20.03" then 14 | { console.useXkbConfig = true; } 15 | else 16 | { i18n.consoleUseXkbConfig = true; } 17 | ) 18 | -------------------------------------------------------------------------------- /cfg/locate.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | services.locate = { 5 | enable = true; 6 | # "findutils" is the default package (as per NixOS 17.03), but "mlocate" 7 | # has benefits: 8 | # 1. It (supposedly) updates its database faster. 9 | # 2. Its 'locate' command checks user permissions so that 10 | # (a) users only see files they have access to on the filesystem and 11 | # (b) indexing can run as root (without leaking file listings to 12 | # unprivileged users). 13 | locate = pkgs.mlocate; 14 | localuser = null; # needed so mlocate can run as root (TODO: improve NixOS module) 15 | interval = "02:15"; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /cfg/lttng.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | boot.extraModulePackages = with config.boot.kernelPackages; [ 5 | lttng-modules 6 | ]; 7 | 8 | environment.systemPackages = with pkgs; [ 9 | babeltrace 10 | lttng-tools 11 | ]; 12 | 13 | systemd.services.lttng-sessiond = { 14 | description = "LTTng Session Daemon"; 15 | wantedBy = [ "multi-user.target" ]; 16 | environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules"; 17 | serviceConfig = { 18 | ExecStart = "${pkgs.lttngTools}/bin/lttng-sessiond"; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /cfg/max-perf-pct.nix: -------------------------------------------------------------------------------- 1 | # Store and restore /sys/devices/system/cpu/intel_pstate/max_perf_pct state. 2 | # 3 | # Background: My laptop has terrible thermal design and a very noisy fan. I 4 | # generally operate it with max_perf_pct=70 and would like to automate this. 5 | # This module adds a script called max_perf_pct that can be invoked to adjust 6 | # the setting (tip: bind to a keyboard shortcut). 7 | 8 | { config, lib, pkgs, ... }: 9 | 10 | let 11 | stateFile = "/var/lib/max_perf_pct/state"; 12 | in 13 | { 14 | environment.systemPackages = with pkgs; [ my.max_perf_pct ]; 15 | 16 | systemd.services.max_perf_pct = { 17 | description = "(Re)store max_perf_pct Sysfs Attribute"; 18 | wantedBy = [ "multi-user.target" ]; 19 | #path = [ "/run/wrappers" /* For sudo. Unneeded when run as root. */ ]; 20 | serviceConfig.ExecStart = pkgs.writeScript "max_perf_pct_start" '' 21 | #!${pkgs.bash}/bin/sh 22 | test -f "${stateFile}" || exit 0 23 | saved_value=$(cat "${stateFile}" 2>/dev/null) 24 | if ! test "$saved_value" -eq "$saved_value" 2>/dev/null; then 25 | echo "error: cannot load state from ${stateFile} because it is empty or has non-numeric contents: $saved_value" 26 | else 27 | echo "Restoring state from ${stateFile}: $saved_value" 28 | ${pkgs.my.max_perf_pct}/bin/max_perf_pct "$saved_value" 29 | fi 30 | ''; 31 | serviceConfig.ExecStop = pkgs.writeScript "max_perf_pct_stop" '' 32 | #!${pkgs.bash}/bin/sh 33 | saved_value=$(${pkgs.my.max_perf_pct}/bin/max_perf_pct) 34 | echo "Saving state to ${stateFile}: $saved_value" 35 | echo "$saved_value" > "${stateFile}" 36 | ''; 37 | serviceConfig.SyslogIdentifier = "max_perf_pct"; 38 | serviceConfig.Type = "oneshot"; 39 | serviceConfig.ProtectSystem = "strict"; 40 | serviceConfig.RemainAfterExit = true; 41 | serviceConfig.StateDirectory = "max_perf_pct"; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /cfg/munin.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | services = { 5 | munin-node.enable = true; 6 | 7 | munin-cron = { 8 | enable = true; 9 | hosts = '' 10 | [${config.networking.hostName}] 11 | address localhost 12 | ''; 13 | }; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /cfg/mytinytodo.nix: -------------------------------------------------------------------------------- 1 | # NixOS module for running http://www.mytinytodo.net/ on lighttpd. 2 | # 3 | # Update to new version (copied from http://www.mytinytodo.net/faq.php) 4 | # 5 | # 1. Download, unpack and replace all files excluding directory 'db' 6 | # (automatically handled by this module). 7 | # 2. Run 'setup.php' and upgrade database if required. 8 | 9 | { config, lib, pkgs, ... }: 10 | 11 | with lib; 12 | 13 | let 14 | appName = "mytinytodo"; 15 | 16 | appDir = "/var/lib/${appName}"; 17 | 18 | phpfpmSocketName = config.services.phpfpm.pools."${appName}".socket; 19 | 20 | mytinytodo = 21 | pkgs.stdenv.mkDerivation rec { 22 | name = "mytinytodo-${version}"; 23 | version = "1.4.3"; 24 | src = pkgs.fetchzip { 25 | name = "${name}-src"; 26 | url = "https://bitbucket.org/maxpozdeev/mytinytodo/downloads/mytinytodo-v${version}.zip"; 27 | sha256 = "0rv5bjd7p2c9wlaxadq3aiavqbxwgyjwp4b0975nghcwp6207my2"; 28 | }; 29 | buildCommand = '' 30 | mkdir -p "$out" 31 | cp -r "$src"/. "$out" 32 | 33 | echo "Tweaking CSS" 34 | chmod -R u+w "$out" 35 | css_mod="input[type=checkbox] 36 | { /* Double-sized checkboxes, because normal size boxes are difficult to hit on phone */ 37 | transform: scale(2); 38 | padding: 10px; 39 | }" 40 | echo "$css_mod" >> "$out/themes/default/style.css" # default style 41 | echo "$css_mod" >> "$out/themes/default/pda.css" # for phones 42 | ''; 43 | }; 44 | in 45 | { 46 | config = { 47 | 48 | services.lighttpd = { 49 | enableModules = [ "mod_alias" "mod_fastcgi" ]; 50 | extraConfig = '' 51 | $HTTP["host"] =~ ".*" { 52 | alias.url += ( "/${appName}" => "${appDir}/" ) 53 | $HTTP["url"] =~ "^/${appName}" { 54 | index-file.names += ( "index.php" ) 55 | fastcgi.server = ( 56 | ".php" => ( 57 | "${appName}" => ( 58 | "socket" => "${phpfpmSocketName}", 59 | ) 60 | ) 61 | ) 62 | } 63 | 64 | # Found by listing .htaccess files 65 | $HTTP["url"] =~ "(^/${appName}/db.*|^/${appName}/tmp.*|^/${appName}/lang.*)" { 66 | url.access-deny = ( "" ) 67 | } 68 | } 69 | ''; 70 | }; 71 | 72 | services.phpfpm.pools = { 73 | "${appName}" = { 74 | user = "lighttpd"; 75 | group = "lighttpd"; 76 | settings = { 77 | "listen.owner" = "lighttpd"; 78 | "listen.group" = "lighttpd"; 79 | "pm" = "dynamic"; 80 | "pm.max_children" = 75; 81 | "pm.start_servers" = 10; 82 | "pm.min_spare_servers" = 5; 83 | "pm.max_spare_servers" = 20; 84 | "pm.max_requests" = 500; 85 | }; 86 | }; 87 | }; 88 | 89 | systemd.services.lighttpd.preStart = '' 90 | echo "Setting up ${appName} in ${appDir}" 91 | if [ -f "${appDir}/db/todolist.db" ]; then 92 | maybe_exclude_db="--exclude db/" 93 | fi 94 | ${pkgs.rsync}/bin/rsync -a --checksum --delete $maybe_exclude_db "${mytinytodo}/" "${appDir}/" 95 | chown -R lighttpd:lighttpd "${appDir}" 96 | chmod u+w "${appDir}/db" 97 | chmod u+w "${appDir}/db/config.php" 98 | chmod u+w "${appDir}/db/todolist.db" 99 | ''; 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /cfg/nix-path.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | dummyNixChannel = pkgs.writeShellScriptBin "nix-channel" '' 5 | echo "nix-channel has been disabled on this machine." >&2 6 | exit 1 7 | ''; 8 | in 9 | { 10 | nix.nixPath = [ 11 | # This is a symlink that is created below. Using a symlink instead of 12 | # direct store path allows using the new nixpkgs without having to 13 | # re-login. 14 | "nixpkgs=/etc/current-nixpkgs" 15 | 16 | # After initial bootstrap with `nixos-rebuild boot -I 17 | # nixos-config=/etc/nixos/$MACHINE/configuration.nix`, the machine 18 | # remembers its configuration file. 19 | "nixos-config=/etc/nixos/machines/${config.networking.hostName}/configuration.nix" 20 | ]; 21 | 22 | # Inspired by https://github.com/NixOS/nix/pull/1731#issuecomment-558126263, 23 | # but using the option environment.etc instead of nixos internal 24 | # system.extraSystemBuilderCmds. 25 | environment.etc.current-nixpkgs.source = let 26 | # make sure store paths are not copied to the store again, which leads to 27 | # long filenames (https://github.com/NixOS/nix/issues/1728) 28 | nixpkgs_str = if lib.isStorePath pkgs.path then builtins.storePath pkgs.path else pkgs.path; 29 | in 30 | nixpkgs_str; 31 | 32 | environment.systemPackages = [ 33 | (lib.hiPrio dummyNixChannel) 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /cfg/nix-remote-build-client.nix: -------------------------------------------------------------------------------- 1 | { 2 | nix.buildMachines = [ 3 | { hostName = "bforsman.name"; 4 | systems = [ "x86_64-linux" ]; 5 | # TODO: I belive maxJobs = "auto" is documented somewhere, but nix-2.2.2 6 | # and 2.3 fail with unhelpful "error: stoull". 7 | maxJobs = 4; 8 | speedFactor = 10; 9 | supportedFeatures = [ 10 | "benchmark" 11 | "big-parallel" 12 | "kvm" 13 | "nixos-test" 14 | ]; 15 | mandatoryFeatures = [ ]; 16 | # The server side user to login with 17 | sshUser = "nix-remote-build"; 18 | # The client side private key for login as sshUser 19 | sshKey = "/root/.ssh/id_ed25519_nix_remote_build"; 20 | } 21 | ]; 22 | nix.distributedBuilds = true; 23 | 24 | # optional, useful when the builder has a faster internet connection than yours 25 | nix.extraOptions = '' 26 | builders-use-substitutes = true 27 | ''; 28 | } 29 | -------------------------------------------------------------------------------- /cfg/nix-remote-build-server.nix: -------------------------------------------------------------------------------- 1 | # TODO: There is a nix.sshServe NixOS option, but it doesn't (yet) allow the 2 | # configuration of the nix-store --write flag. 3 | 4 | { config, ... }: 5 | 6 | let 7 | user = "nix-remote-build"; 8 | in 9 | { 10 | # must be trusted to be allowed to build derivations 11 | nix.trustedUsers = [ user ]; 12 | 13 | users.users."${user}" = { 14 | group = user; 15 | isSystemUser = true; 16 | useDefaultShell = true; 17 | openssh.authorizedKeys.keys = with config.local.resources.sshKeys; [ 18 | (''command="nix-store --serve --write",restrict '' + media.root.nix_remote_build) 19 | (''command="nix-store --serve --write",restrict '' + mini.root.nix_remote_build) 20 | (''command="nix-store --serve --write",restrict '' + whitetip.root.nix_remote_build) 21 | ]; 22 | }; 23 | 24 | users.groups."${user}" = { }; 25 | } 26 | -------------------------------------------------------------------------------- /cfg/nix-settings.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | nix = { 5 | useSandbox = true; 6 | buildCores = 0; # 0 means auto-detect number of CPUs (and use all) 7 | trustedUsers = [ "root" "@wheel" ]; 8 | 9 | extraOptions = '' 10 | # To not get caught by the '''"nix-collect-garbage -d" makes 11 | # "nixos-rebuild switch" unusable when nixos.org is down"''' issue: 12 | gc-keep-outputs = true 13 | 14 | # Number of seconds to wait for binary-cache to accept() our connect() 15 | connect-timeout = 15 16 | ''; 17 | 18 | # Automatic garbage collection 19 | gc.automatic = true; 20 | gc.dates = "Mon *-*-* 00:00:00"; 21 | gc.options = "--delete-older-than 14d"; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /cfg/nixpkgs-config.nix: -------------------------------------------------------------------------------- 1 | # Nixpkgs configuration file. 2 | 3 | { 4 | allowUnfree = true; # allow proprietary packages 5 | 6 | firefox.enableAdobeFlash = true; 7 | chromium.enablePepperFlash = true; 8 | } 9 | -------------------------------------------------------------------------------- /cfg/nixpkgs-overlays.nix: -------------------------------------------------------------------------------- 1 | [ 2 | (self: super: 3 | (import ../pkgs/default.nix { pkgs = super; }) 4 | ) 5 | 6 | (self: super: { 7 | nur = 8 | let 9 | nurSrc = import ../inputs/nur.nix { }; 10 | in 11 | import nurSrc { nurpkgs = super; pkgs = super; }; 12 | }) 13 | ] 14 | -------------------------------------------------------------------------------- /cfg/popwk.nix: -------------------------------------------------------------------------------- 1 | # popwk - Power on/off (PJLINK) projector with (Logitech wireless) keyboard. 2 | 3 | { config, lib, pkgs, ... }: 4 | 5 | let 6 | projectorIpAddr = config.local.resources.hostAddrs.projector; 7 | in 8 | { 9 | # This must be a system service so it works even at the login screen 10 | # (before any user services have started). 11 | systemd.services.popwk = { 12 | description = "Power on/off projector with keyboard"; 13 | wantedBy = [ "multi-user.target" ]; 14 | after = [ "dbus.service" "systemd-logind.service" ]; 15 | path = with pkgs; [ 16 | "/run/wrappers" # for sudo 17 | ]; 18 | serviceConfig = { 19 | ExecStart = "${pkgs.my.popwk}/bin/popwk ${projectorIpAddr}"; 20 | 21 | # This service runs as root, with sandboxing for protection. (See the 22 | # SANDBOXING section in man systemd.exec.) Ideally it would run as 23 | # DynamicUser, but how to get desktop notifications to work then? 24 | # (`sudo -u $otheruser notify-desktop ...` requires access to 25 | # /run/user/). 26 | ProtectSystem = "strict"; 27 | ProtectHome = "read-only"; 28 | InaccessiblePaths = [ "/root" "/home" ]; 29 | PrivateTmp = true; 30 | NoNewPrivileges = true; 31 | DeviceAllow = "char-hidraw rw"; 32 | }; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /cfg/postfix.nix: -------------------------------------------------------------------------------- 1 | { 2 | services = { 3 | postfix = { 4 | enable = true; 5 | # Possibly set "domain" in machine specific configs. 6 | # The default "From:" address is 7 | # user@${config.networking.hostName}.localdomain 8 | #domain = "server1.example"; 9 | rootAlias = "bjorn.forsman@gmail.com"; 10 | extraConfig = '' 11 | inet_interfaces = loopback-only 12 | 13 | # Postfix (or my system) seems to prefer ipv6 now, but that breaks on 14 | # my network: 15 | # 16 | # connect to gmail-smtp-in.l.google.com[2a00:1450:4010:c09::1b]:25: Network is unreachable 17 | # 18 | # So let's force ipv4. 19 | smtp_address_preference = ipv4 20 | ''; 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /cfg/pulseaudio.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | hardware.pulseaudio = { 5 | enable = true; 6 | package = pkgs.pulseaudioFull; 7 | daemon.config = { 8 | flat-volumes = "no"; 9 | }; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /cfg/resources.nix: -------------------------------------------------------------------------------- 1 | # Arbitrary shared resources for use across my NixOS machines. 2 | 3 | { 4 | local.resources = { 5 | hostAddrs = import ../resources/host-addrs.nix; 6 | sshKeys = import ../resources/ssh-keys.nix; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /cfg/shell.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | environment.interactiveShellInit = '' 5 | # Edit the real configuration.nix file, not the /etc/nixos/configuration.nix 6 | # symlink. This fixes using Vim 'gf' to jump to relative file paths. 7 | en() 8 | { 9 | (cd /etc/nixos \ 10 | && vim -c "set makeprg=sudo\ nixos-rebuild\ dry-build errorformat=error:\ %m\ at\ %f:%l:%c" "machines/$HOSTNAME/configuration.nix" \ 11 | && (echo "Activate the new config? sudo nixos-rebuild ...?" 12 | echo " 1) switch" 13 | echo " 2) test" 14 | echo " q) quit" 15 | read -p "Your choice? [q] " ans 16 | case "$ans" in 17 | 1) action=switch;; 18 | 2) action=test;; 19 | *) echo "quit"; exit 0;; 20 | esac 21 | sudo nixos-rebuild "$action" 22 | ) 23 | ) 24 | } 25 | 26 | # Disable use of Ctrl-S/Ctrl-Q to stop/start process output. This frees up 27 | # those keys to do other stuff. 28 | stty stop "" 29 | stty start "" 30 | ''; 31 | 32 | environment.sessionVariables = { 33 | NIX_AUTO_INSTALL = "1"; 34 | EDITOR = "vim"; 35 | VISUAL = "vim"; 36 | LESS = "--ignore-case --quit-if-one-screen"; 37 | }; 38 | 39 | programs.bash.interactiveShellInit = '' 40 | # Add completion for my taskwarrior "t" alias. Hm, we must force load the 41 | # original completion file first, or else the _task function will not be 42 | # defined. 43 | source "${pkgs.taskwarrior}/share/bash-completion/completions/task.bash" 44 | complete -o nospace -F _task t 45 | ''; 46 | } 47 | -------------------------------------------------------------------------------- /cfg/skype-flip-camera.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | # This modifies 'pkgs.skype' so that it flips the video camera input 180 degress. 5 | nixpkgs.config = { 6 | packageOverrides = pkgs: { 7 | skype = 8 | let 9 | libv4l_i686 = pkgs.callPackage_i686 { qt5 = null; }; 10 | in 11 | lib.overrideDerivation pkgs.skype (attrs: { 12 | installPhase = attrs.installPhase + 13 | '' 14 | sed -i "2iexport LD_PRELOAD=${libv4l_i686}/lib/v4l1compat.so" "$out/bin/skype" 15 | ''; 16 | }); 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /cfg/smart-daemon.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | services = { 5 | smartd = { 6 | enable = true; 7 | autodetect = true; # monitor all devices found on startup 8 | # See smartd.conf(5) man page for details about these options: 9 | # "-a": enable all checks 10 | # "-o VALUE": enable/disable automatic offline testing on device (on/off) 11 | # "-s REGEXP": do a short test every day at 3am and a long test every 12 | # sunday at 3am. 13 | defaults.autodetected = "-a -o on -s (S/../.././03|L/../../7/03)"; 14 | notifications = { 15 | mail.enable = true; 16 | x11.enable = true; 17 | #test = true; # send notification on service startup, for test 18 | }; 19 | }; 20 | 21 | # To receive email notifications we need a "sendmail". 22 | # Postfix can be used for this, example below. 23 | #postfix = { 24 | # enable = true; 25 | # domain = "mydomain.example"; 26 | # rootAlias = "your.email@somewhere.example"; 27 | # extraConfig = '' 28 | # inet_interfaces = loopback-only 29 | # ''; 30 | #}; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /cfg/software-defined-radio.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | environment.systemPackages = with pkgs; [ 5 | gnuradio-with-packages 6 | gqrx 7 | kalibrate-rtl 8 | rtl-sdr 9 | ]; 10 | 11 | # Uncomment to compose environments with nix-env (alternative to 12 | # gnuradio-with-packages). 13 | #environment.profileRelativeEnvVars = { 14 | # GRC_BLOCKS_PATH = [ "/share/gnuradio/grc/blocks" ]; 15 | #}; 16 | 17 | services.udev.packages = with pkgs; [ 18 | rtl-sdr 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /cfg/sudo.nix: -------------------------------------------------------------------------------- 1 | { 2 | security.sudo = { 3 | enable = true; 4 | wheelNeedsPassword = false; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /cfg/swraid.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | environment.etc."mdadm.conf".text = '' 5 | MAILADDR root 6 | ''; 7 | 8 | # Hack to run degraded arrays. 9 | # TODO: Let upstream (mdadm) udev rules invoke upstream systemd service 10 | # units. dracut initrds do this, NixOS initrd does not (AFAIK). Since version 11 | # 19.09, NixOS does use upstream units, but only after the rootfs has been 12 | # mounted (too late). 13 | boot.initrd.preLVMCommands = '' 14 | for dev in /dev/md*; do 15 | if [ -b "$dev" ]; then 16 | mdadm --run "$dev" 17 | fi 18 | done 19 | ''; 20 | 21 | systemd.services.mdadm-scrubbing = { 22 | description = "Mdadm Raid Array Scrubbing"; 23 | startAt = "Sun 06:00:00"; 24 | script = '' 25 | for md in /sys/block/md*; do 26 | echo check > "$md/md/sync_action" 27 | done 28 | ''; 29 | }; 30 | 31 | # Scrub on next boot if system was powered off during last schedule. 32 | systemd.timers.mdadm-scrubbing.timerConfig.Persistent = true; 33 | } 34 | -------------------------------------------------------------------------------- /cfg/syncthing.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | services.syncthing = { 5 | enable = true; 6 | group = "syncthing"; # FIXME: NixOS defaults to "nogroup" 7 | }; 8 | 9 | # Undo the 700 perms syncthing sets on /var/lib/syncthing on startup. Without 10 | # this the ACL entries for my user stop working. 11 | # See 12 | # https://github.com/syncthing/syncthing/issues/3434 13 | # https://github.com/NixOS/nixpkgs/issues/47513 14 | systemd.services.syncthing.postStart = lib.mkForce '' 15 | sleep 10 16 | chmod g+rx "${config.services.syncthing.dataDir}" 17 | ''; 18 | 19 | # Enable debug trace to spot permission errors. 20 | #systemd.services.syncthing.environment.STTRACE = "scanner"; 21 | } 22 | -------------------------------------------------------------------------------- /cfg/transmission.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | 5 | services.transmission = { 6 | enable = true; 7 | settings = { 8 | download-dir = "/srv/torrents/"; 9 | incomplete-dir = "/srv/torrents/.incomplete/"; 10 | incomplete-dir-enabled = true; 11 | rpc-whitelist = "127.0.0.1,192.168.1.*"; 12 | rpc-host-whitelist = "*"; 13 | ratio-limit = 2; 14 | ratio-limit-enabled = true; 15 | rpc-bind-address = "0.0.0.0"; # web server 16 | }; 17 | }; 18 | 19 | systemd.tmpfiles.rules = 20 | let 21 | user = "transmission"; 22 | group = "transmission"; 23 | downloadDir = config.services.transmission.settings.download-dir; 24 | in 25 | [ #Type Path Mode UID GID Age Argument 26 | "d ${downloadDir} 0755 ${user} ${group} - -" 27 | ]; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cfg/virtualisation.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | virtualisation.libvirtd.enable = true; 5 | virtualisation.lxc.enable = true; 6 | virtualisation.lxc.usernetConfig = '' 7 | bf veth lxcbr0 10 8 | ''; 9 | virtualisation.docker.enable = true; 10 | 11 | virtualisation.virtualbox.host.enable = true; 12 | #virtualisation.virtualbox.host.enableExtensionPack = true; 13 | } 14 | -------------------------------------------------------------------------------- /cfg/xserver.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.xserver = { 3 | enable = true; 4 | libinput.enable = true; 5 | libinput.additionalOptions = '' 6 | # Reduce sensitiviy of Wacom BambooFun 6x8 Pad 7 | # * 4-point bezier curve: "x0/y0 x1/y1 x2/y2 x3/y3" 8 | # * default value: "0/0 0/0 1/1 1/1" 9 | # A bit too hard: "0.5/0 0.5/0 1/1 1/1" 10 | Option "TabletToolPressureCurve" "0.3/0 0.3/0 1/1 1/1" 11 | ''; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | # Sanity check the repo by evaluating/building all machine configs. 2 | 3 | { branch ? "pinned" # default to pinned/reproducible 4 | , nixpkgs ? import ./inputs/nixpkgs.nix { inherit branch; } 5 | , pkgs ? let p = import nixpkgs { config = import ./cfg/nixpkgs-config.nix; overlays = []; }; in builtins.trace "nixpkgs version: ${p.lib.version} (rev: ${nixpkgs.rev or "unknown"})" p 6 | }: 7 | 8 | let 9 | nixosFunc = import (pkgs.path + "/nixos"); 10 | 11 | iso = import ./isos/livecd/default.nix { inherit pkgs; }; 12 | 13 | buildConfig = config: 14 | # FIXME: Machines that set 'boot.loader.systemd-boot.enable = true' fail to 15 | # build the vmWithBootloader attribute, ref 16 | # https://github.com/NixOS/nixpkgs/pull/65133. 17 | pkgs.lib.filterAttrs 18 | (n: v: n != "vmWithBootLoader") 19 | ((nixosFunc { configuration = config; }) // { recurseForDerivations = true; }); 20 | in 21 | { 22 | inherit iso; 23 | localPkgs = import ./pkgs/default.nix { inherit pkgs; }; 24 | machines = pkgs.recurseIntoAttrs { 25 | media = buildConfig ./machines/media/configuration.nix; 26 | mini = buildConfig ./machines/mini/configuration.nix; 27 | srv1 = buildConfig ./machines/srv1/configuration.nix; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /deploy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | set -x 5 | 6 | morph deploy ./home-network.nix switch "$@" 7 | -------------------------------------------------------------------------------- /doc/disaster-recovery.adoc: -------------------------------------------------------------------------------- 1 | = Disaster recovery 2 | :reproducible: 3 | 4 | 1. Boot NixOS Live CD/USB installer. 5 | (If doing full system restore, the PC must boot in the same firmware 6 | mode (BIOS/MBR v. EFI) as the old system.) 7 | 8 | 2. Install BorgBackup: 9 | 10 | $ nix-env -iA nixos.borgbackup 11 | 12 | 3. Make the backup available to borg. 13 | Here, an SSH example: 14 | 15 | $ export BORG_REMOTE_PATH="sudo borg" 16 | $ export BORG_RSH="ssh -i /path/to/private/key" 17 | $ export BORG_REPO=ssh://user@server/backups/repo.borg 18 | + 19 | (Remember to add SSH keys for the root user to be able to login to 20 | server as user.) 21 | + 22 | Here, a CIFS example: 23 | 24 | $ mkdir /backups 25 | $ mount.cifs //server/backups /backups -o rw,username=$YOUR_USER 26 | $ export BORG_REPO=/backups/backup.borg 27 | 28 | 4. List available archives, choose one to restore from: 29 | 30 | $ borg list 31 | $ export ARCHIVE_NAME=some-archive-name-from-above 32 | 33 | 5. Partition, format and mount disk(s) on `/mnt`: 34 | - If doing full system restore, the partitions must have the same 35 | filesystem labels and/or uuids like the old system. 36 | Hint: 37 | 38 | $ mkdir etc_nixos && cd etc_nixos && borg extract ::$ARCHIVE_NAME etc/nixos 39 | + 40 | Get label and uuid values from etc/nixos/*.nix files. If your 41 | config contains direct refs like `/dev/sda3` (bad idea!) you might 42 | have to do nixos-install. 43 | + 44 | $ mkfs.ext4 -L $label -U $uuid /dev/my-disk-partition 45 | + 46 | For mkfs.vfat the $uuid from the config needs to have the dash 47 | ('-') removed, or else it complains "Volume ID must be a hexadecimal number". 48 | + 49 | $ mkfs.vfat -F32 -n $label -i $uuid /dev/my-disk-partition 50 | 51 | - If booting in EFI mode, the FAT32 formatted EFI System Partition 52 | must be mounted on /mnt/boot. (If booting in BIOS/MBR mode you 53 | don't _have_ to make a separate boot partition, as long as your 54 | root filesystem is supported by GRUB.) 55 | 56 | 6. Restore files: 57 | 58 | $ cd /mnt && borg extract -v --list --numeric-owner ::$ARCHIVE_NAME 59 | + 60 | (If the backup includes the Nix store but you want to do a 61 | re-install anyway (e.g. to redo disk partitioning or migrating from 62 | BIOS/MBR to EFI), add `--exclude /nix` to the borg command.) 63 | 64 | 7. Make the system bootable. 65 | - Alternative 1, the backup includes the Nix store. The disk just 66 | needs to be made bootable: 67 | + 68 | For BIOS/MBR: 69 | 70 | $ grub-install --boot-directory=/mnt/boot /dev/sdX 71 | + 72 | For EFI: 73 | Nothing really needs to be done. The system will be bootable 74 | because there is `/EFI/BOOT/BOOTX64.EFI` in the EFI System 75 | Partition. If you want to add/update EFI variables, here are 76 | some tips: 77 | 78 | $ efibootmgr # see current entries (and HEX_VAL identifier) 79 | $ efibootmgr --delete-bootnum --bootnum HEX_VAL 80 | $ efibootmgr --verbose --create --disk /dev/sda --part 1 --loader /EFI/BOOT/BOOTX64.EFI --label "NixOS" 81 | 82 | - Alternative 2, the backup does NOT include the Nix store. Must 83 | perform NixOS install. However, this allows changing between 84 | BIOS/MBR and EFI booting, as well as completely redesigning 85 | partitions/filesystems. 86 | 87 | * Check that bootloader and filesystem(s) is set up to your liking 88 | in NixOS configuration (which disk label/uuid to use etc.). If 89 | restoring onto new HW, pay attention when updating 90 | hardware-configuration.nix (`nixos-generate-config --dir /tmp`, 91 | then manually merge with /mnt/etc/nixos). 92 | * nixos-install 93 | 94 | 8. Reboot into your new old system :-) 95 | -------------------------------------------------------------------------------- /home-network.nix: -------------------------------------------------------------------------------- 1 | # Usage examples: 2 | # $ morph deploy ./home-network.nix switch 3 | # $ morph deploy --keep-result --reboot ./home-network.nix boot 4 | 5 | { 6 | network.description = "Home network"; 7 | network.pkgs = 8 | let 9 | nixpkgsSrc = import ./inputs/nixpkgs.nix {}; 10 | in 11 | import nixpkgsSrc { 12 | # Q: Why is config set but overlays empty? 13 | # A: As of morph-1.4.0, network.pkgs sets nixpkgs.pkgs, and the latter 14 | # is documented in "man configuration.nix" to ignore nixpkgs.config but 15 | # not nixpkgs.overlays. So we get the right overlays from within the 16 | # nixos configuration, but not the config. Set overlays to empty list 17 | # to prevent undeclared overlays from sneaking in. 18 | config = import ./cfg/nixpkgs-config.nix; 19 | overlays = []; 20 | }; 21 | 22 | "media.local" = import ./machines/media/configuration.nix; 23 | "mini.local" = import ./machines/mini/configuration.nix; 24 | "srv1.local" = import ./machines/srv1/configuration.nix; 25 | } 26 | -------------------------------------------------------------------------------- /inputs/home-manager.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://github.com/rycee/home-manager", 3 | "ref": "refs/heads/release-20.03", 4 | "rev": "318bc0754ed6370cfcae13183a7f13f7aa4bc73f", 5 | "date": "2020-07-05T21:08:04+02:00", 6 | "sha256": "0hgn85yl7gixw1adjfa9nx8axmlpw5y1883lzg3zigknx6ff5hsr", 7 | "fetchSubmodules": false 8 | } 9 | -------------------------------------------------------------------------------- /inputs/home-manager.nix: -------------------------------------------------------------------------------- 1 | # default to pinned/reproducible branch 2 | { branch ? "pinned" }: 3 | 4 | let 5 | hmGitUrl = "https://github.com/rycee/home-manager"; 6 | 7 | pinnedInfo = builtins.fromJSON (builtins.readFile ./home-manager.json); 8 | 9 | branches = { 10 | pinned = builtins.fetchGit { 11 | inherit (pinnedInfo) url ref rev; 12 | }; 13 | release = builtins.fetchGit { 14 | url = hmGitUrl; 15 | ref = "refs/heads/release-20.03"; 16 | }; 17 | master = builtins.fetchGit { 18 | url = hmGitUrl; 19 | ref = "refs/heads/master"; 20 | }; 21 | }; 22 | 23 | badBranchMsg = branch: 24 | let 25 | branchNames = builtins.toString (builtins.attrNames branches); 26 | in 27 | "unsupported branch \"${branch}\", valid branch names: ${branchNames}"; 28 | in 29 | branches."${branch}" or (throw (badBranchMsg branch)) 30 | -------------------------------------------------------------------------------- /inputs/nixpkgs.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://github.com/nixos/nixpkgs", 3 | "ref": "refs/heads/nixos-20.03", 4 | "rev": "d6260a33e43a500528b2be834d3ee4ad45441a6a", 5 | "date": "2020-07-03T12:13:31+02:00", 6 | "sha256": "18ailgn3d8smjdg66di3mg1q1l86s2s5ch856ifzy5kc3a224ssf", 7 | "fetchSubmodules": false 8 | } 9 | -------------------------------------------------------------------------------- /inputs/nixpkgs.nix: -------------------------------------------------------------------------------- 1 | # default to pinned/reproducible branch 2 | { branch ? "pinned" }: 3 | 4 | let 5 | nixpkgsGitUrl = "https://github.com/NixOS/nixpkgs.git"; 6 | 7 | pinnedInfo = builtins.fromJSON (builtins.readFile ./nixpkgs.json); 8 | 9 | # A special nixpkgs fetcher that injects .version-suffix file for better 10 | # lib.version info. 11 | fetchGitWithVersionSuffix = { url, ref, rev ? null }: 12 | let 13 | base = 14 | builtins.fetchGit ({ 15 | inherit url ref; 16 | } // (if rev != null then { inherit rev; } else {})); 17 | basePkgs = import base { config = {}; overlays = []; }; 18 | in 19 | basePkgs.runCommandLocal "nixpkgs-source" { passthru = base; } '' 20 | mkdir -p "$out" 21 | (shopt -s dotglob; cp -r "${base}/"* "$out") 22 | echo ".git.${base.shortRev}" > "$out/.version-suffix" 23 | ''; 24 | 25 | branches = { 26 | # a snapshot of stable 27 | pinned = fetchGitWithVersionSuffix { 28 | inherit (pinnedInfo) url ref rev; 29 | }; 30 | release = fetchGitWithVersionSuffix { 31 | url = nixpkgsGitUrl; 32 | ref = "refs/heads/release-20.03"; 33 | }; 34 | master = fetchGitWithVersionSuffix { 35 | url = nixpkgsGitUrl; 36 | ref = "refs/heads/master"; 37 | }; 38 | # TODO: channels include programs.sqlite (for shell command-not-found 39 | # functionality), but command-not-found.pl hardcodes that path (no 40 | # $NIX_PATH lookup). 41 | stable-channel = builtins.fetchTarball { 42 | url = "https://nixos.org/channels/nixos-20.03/nixexprs.tar.xz"; 43 | }; 44 | unstable-channel = builtins.fetchTarball { 45 | url = "https://nixos.org/channels/nixpkgs-unstable/nixexprs.tar.xz"; 46 | }; 47 | }; 48 | 49 | badBranchMsg = branch: 50 | let 51 | branchNames = builtins.toString (builtins.attrNames branches); 52 | in 53 | "unsupported branch \"${branch}\", valid branch names: ${branchNames}"; 54 | in 55 | branches."${branch}" or (throw (badBranchMsg branch)) 56 | -------------------------------------------------------------------------------- /inputs/nur.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://github.com/nix-community/nur", 3 | "ref": "refs/heads/master", 4 | "rev": "dd503cb923ed9ced0f0e5bec0f8c4cf7f62fc8f6", 5 | "date": "2020-07-13T20:20:29+00:00", 6 | "sha256": "1nm6gsz14fc6r093jsdn7zc7m89s9d5smp6hk0w00ldhihs203bf", 7 | "fetchSubmodules": false 8 | } 9 | -------------------------------------------------------------------------------- /inputs/nur.nix: -------------------------------------------------------------------------------- 1 | # default to pinned/reproducible branch 2 | { branch ? "pinned" }: 3 | 4 | let 5 | nurGitUrl = "https://github.com/nix-community/nur"; 6 | 7 | pinnedInfo = builtins.fromJSON (builtins.readFile ./nur.json); 8 | 9 | # NUR has no other branches than master 10 | branches = { 11 | pinned = builtins.fetchGit { 12 | inherit (pinnedInfo) url ref rev; 13 | }; 14 | master = builtins.fetchGit { 15 | url = nurGitUrl; 16 | ref = "refs/heads/master"; 17 | }; 18 | }; 19 | 20 | badBranchMsg = branch: 21 | let 22 | branchNames = builtins.toString (builtins.attrNames branches); 23 | in 24 | "unsupported branch \"${branch}\", valid branch names: ${branchNames}"; 25 | in 26 | branches."${branch}" or (throw (badBranchMsg branch)) 27 | -------------------------------------------------------------------------------- /inputs/update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # A simple replacement for 'niv', until it adds "datetime of commit" to the 3 | # generated JSON file. 4 | 5 | set -euo pipefail 6 | 7 | ### options 8 | 9 | # array of "name url ref" tuples 10 | sources=( 11 | "nixpkgs https://github.com/nixos/nixpkgs refs/heads/nixos-20.03" 12 | "home-manager https://github.com/rycee/home-manager refs/heads/release-20.03" 13 | "nur https://github.com/nix-community/nur refs/heads/master" 14 | ) 15 | 16 | ### implementation 17 | 18 | compare_and_rename() 19 | { 20 | local f=$1 21 | if cmp --quiet "$f.tmp" "$f"; then 22 | echo "### $f didn't change" 23 | rm "$f.tmp" 24 | else 25 | mv "$f.tmp" "$f" 26 | echo "### $f was updated" 27 | fi 28 | } 29 | 30 | # Because nix-prefetch-git doesn't output branch/ref info, and adding it isn't 31 | # trivial (due to its interface). 32 | insert_ref() 33 | { 34 | local f=$1 35 | local ref=$2 36 | # to make sed insert leading whitespace, escape with '\' 37 | sed -e "3i\ \ \"ref\": \"$ref\"," -i "$f" 38 | } 39 | 40 | update_source() 41 | { 42 | local arr 43 | read -r -a arr <<< "$1" 44 | local name=${arr[0]} 45 | local url=${arr[1]} 46 | local ref=${arr[2]} 47 | echo "### Updating $name..." 48 | local json="$selfdir/$name.json" 49 | nix-prefetch-git "$url" --rev "$ref" >"$json.tmp" 50 | insert_ref "$json.tmp" "$ref" 51 | compare_and_rename "$json" 52 | } 53 | 54 | cleanup() 55 | { 56 | rm -f "$selfdir"/*.json.tmp 57 | } 58 | 59 | main() 60 | { 61 | selfdir=$(readlink -f "$(dirname "$0")") 62 | trap "echo error: something went wrong >&2; cleanup" EXIT 63 | trap "echo Got signalled, exiting...; cleanup; trap - EXIT" INT TERM 64 | for s in "${sources[@]}"; do 65 | update_source "$s" 66 | done 67 | trap - EXIT 68 | } 69 | 70 | main "$@" 71 | -------------------------------------------------------------------------------- /isos/livecd/default.nix: -------------------------------------------------------------------------------- 1 | # A NixOS live CD with ssh enabled. 2 | 3 | { pkgs }: 4 | 5 | let 6 | nixosFunc = import (pkgs.path + "/nixos"); 7 | 8 | iso = (nixosFunc { 9 | configuration = { 10 | imports = [ 11 | (pkgs.path + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix") 12 | #(pkgs.path + "/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix") 13 | #(pkgs.path + "/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix") 14 | 15 | # Provide an initial copy of the NixOS channel so that the user 16 | # doesn't need to run "nix-channel --update" first. 17 | (pkgs.path + "/nixos/modules/installer/cd-dvd/channel.nix") 18 | ]; 19 | 20 | # Activate SSH at boot 21 | systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ]; 22 | users.users.root.openssh.authorizedKeys.keys = with import ../../resources/ssh-keys.nix; [ 23 | mini.bf.default 24 | whitetip.bf.default 25 | ]; 26 | 27 | isoImage.contents = [ 28 | { source = pkgs.writeText "readme" 29 | '' 30 | Custom NixOS installer built from @bjornfor's nixos-config git repo. 31 | ''; 32 | target = "/README.txt"; 33 | } 34 | ]; 35 | }; 36 | }).config.system.build.isoImage; 37 | in 38 | iso 39 | -------------------------------------------------------------------------------- /lib/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | { 4 | makeSimpleWebApp = 5 | { server 6 | , icon ? null 7 | , comment ? null 8 | , desktopName ? comment 9 | , categories ? null 10 | , browser ? "chromium-browser" 11 | }: 12 | pkgs.makeDesktopItem 13 | ({ 14 | name = server; 15 | exec = "${browser} --app=https://${server}/"; 16 | extraEntries = '' 17 | StartupWMClass=${server} 18 | ''; 19 | } // (if icon != null then { inherit icon; } else {}) 20 | // (if comment != null then { inherit comment; } else {}) 21 | // (if desktopName != null then { inherit desktopName; } else {}) 22 | // (if categories != null then { inherit categories; } else {})); 23 | } 24 | -------------------------------------------------------------------------------- /machines/media/configuration.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ 5 | ./hardware-configuration.nix 6 | ../../cfg/base-medium.nix 7 | ../../cfg/disable-suspend.nix 8 | ../../cfg/bcache.nix 9 | ../../cfg/kdeconnect.nix 10 | ../../cfg/nix-remote-build-client.nix 11 | ../../cfg/popwk.nix 12 | ../../cfg/smart-daemon.nix 13 | ../../users/bf.nix 14 | ../../users/media.nix 15 | ]; 16 | 17 | # Use the systemd-boot EFI boot loader. 18 | boot.loader.grub.enable = lib.mkForce false; 19 | boot.loader.systemd-boot.enable = true; 20 | boot.loader.efi.canTouchEfiVariables = true; 21 | 22 | networking.hostName = "media"; 23 | 24 | networking.firewall.allowedTCPPorts = [ 25 | 8081 # kodi web ui / remote control 26 | 9090 # kodi web ui / remote control 27 | ]; 28 | 29 | system.autoUpgrade = { 30 | enable = false; # too many issues with the desktop disappearing 31 | dates = "04:40"; 32 | channel = "https://nixos.org/channels/nixos-20.03"; 33 | }; 34 | 35 | nixpkgs.config = { 36 | # Disabled because it fails to build. 37 | # See https://github.com/NixOS/nixpkgs/issues/22333 38 | #chromium.enableWideVine = true; # for Netflix, requires full chromium build 39 | }; 40 | 41 | systemd.automounts = [ 42 | { where = "/mnt/maria-pc_seagate_expansion_drive_4tb"; 43 | wantedBy = [ "multi-user.target" ]; 44 | } 45 | ]; 46 | 47 | systemd.mounts = [ 48 | { what = "//maria-pc/seagate_expansion_drive_4tb"; 49 | where = "/mnt/maria-pc_seagate_expansion_drive_4tb"; 50 | type = "cifs"; 51 | options = "ro,credentials=/root/.credentials.maria-pc,uid=bf,gid=users,iocharset=utf8"; 52 | } 53 | ]; 54 | 55 | environment.systemPackages = with pkgs; [ 56 | google-chrome 57 | kodi 58 | spotify 59 | transmission_gtk 60 | ]; 61 | 62 | services.samba.enable = true; # required for nsswins to work 63 | services.samba.nsswins = true; 64 | 65 | services.xserver.displayManager.gdm.autoLogin.enable = true; 66 | services.xserver.displayManager.gdm.autoLogin.user = "media"; 67 | 68 | # The NixOS release to be compatible with for stateful data such as databases. 69 | system.stateVersion = "20.03"; 70 | } 71 | -------------------------------------------------------------------------------- /machines/media/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/installer/scan/not-detected.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "sr_mod" "bcache" ]; 12 | boot.initrd.kernelModules = [ "dm-snapshot" ]; 13 | boot.kernelModules = [ "kvm-intel" ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | fileSystems."/" = 17 | { device = "/dev/disk/by-uuid/acbb6b95-1de0-4b53-9d6a-35cdfd3d867f"; 18 | fsType = "ext4"; 19 | }; 20 | 21 | fileSystems."/boot" = 22 | { device = "/dev/disk/by-uuid/0B11-F2F8"; 23 | fsType = "vfat"; 24 | }; 25 | 26 | swapDevices = [ ]; 27 | 28 | nix.maxJobs = lib.mkDefault 4; 29 | powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; 30 | } 31 | -------------------------------------------------------------------------------- /machines/mini/configuration.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | imports = [ 5 | ./hardware-configuration.nix 6 | ../../cfg/base-big.nix 7 | ../../cfg/clamav.nix 8 | ../../cfg/disable-suspend.nix 9 | ../../cfg/nix-remote-build-client.nix 10 | ../../cfg/smart-daemon.nix 11 | ../../users/bf.nix 12 | ]; 13 | 14 | fileSystems = { 15 | "/".device = "/dev/disk/by-label/240gb"; 16 | "/mnt/data".device = "/dev/disk/by-uuid/87c75c5e-67d5-4a61-949a-e514542db339"; 17 | "/mnt/data".options = [ "nofail" ]; 18 | "/mnt/ssd-120".device = "/dev/disk/by-id/ata-KINGSTON_SH103S3120G_50026B722600AA5F-part1"; 19 | "/mnt/ssd-120".options = [ "nofail" ]; 20 | }; 21 | 22 | boot.loader.grub.device = 23 | "/dev/disk/by-id/ata-KINGSTON_SH103S3240G_50026B722A027195"; 24 | 25 | networking.hostName = "mini"; 26 | networking.firewall.allowedTCPPorts = [ 27 | #139 # samba 28 | 445 # samba 29 | ]; 30 | networking.firewall.allowedUDPPorts = [ 31 | #137 # samba 32 | #138 # samba 33 | ]; 34 | 35 | environment.systemPackages = with pkgs; [ 36 | ]; 37 | 38 | services = { 39 | 40 | borg-backup = { 41 | enable = true; 42 | jobs."default" = { 43 | repository = "backup@srv1.local:mini.borg"; 44 | pathsToBackup = [ "/" "/mnt/data" ]; 45 | environment.BORG_RSH = "ssh -i /root/.ssh/id_ed25519_backup"; 46 | environment.BORG_RELOCATED_REPO_ACCESS_IS_OK = "yes"; 47 | }; 48 | }; 49 | 50 | xserver.displayManager.gdm.autoLogin.enable = true; 51 | xserver.displayManager.gdm.autoLogin.user = "bf"; 52 | 53 | samba = { 54 | enable = true; 55 | extraConfig = '' 56 | [media] 57 | path = /mnt/data/media 58 | read only = yes 59 | guest ok = yes 60 | 61 | [pictures] 62 | path = /mnt/data/pictures/ 63 | read only = yes 64 | guest ok = yes 65 | 66 | [software] 67 | path = /mnt/data/software/ 68 | read only = yes 69 | guest ok = yes 70 | '' + (if config.services.transmission.enable then '' 71 | 72 | [torrents] 73 | path = /srv/torrents 74 | read only = no 75 | guest ok = yes 76 | force user = transmission 77 | '' else ""); 78 | }; 79 | 80 | minidlna = { 81 | enable = true; 82 | mediaDirs = [ "/mnt/data/media" ]; 83 | }; 84 | 85 | munin-node.extraConfig = '' 86 | cidr_allow 192.168.1.0/24 87 | ''; 88 | }; 89 | 90 | systemd.services.archive-photos-from-syncthing = { 91 | description = "Archive photos from Syncthing"; 92 | startAt = "weekly"; 93 | path = with pkgs; [ exiftool "/run/wrappers" ]; 94 | serviceConfig.User = "bf"; 95 | serviceConfig.SyslogIdentifier = "archive-photos"; 96 | script = '' 97 | # Where to look for files (images and videos). 98 | input_dir=/var/lib/syncthing/lg-h930-foto/Camera 99 | # Files newer than this are not moved. 100 | days_to_keep=30 101 | # Files older than $days_to_keep are moved here, in YEAR + MONTH 102 | # subdirectories. 103 | pictures_archive=/mnt/data/pictures 104 | 105 | for dir in "$input_dir" "$pictures_archive"; do 106 | if ! [ -d "$dir" ]; then 107 | echo "No such directory: $dir" >&2 108 | exit 1 109 | fi 110 | done 111 | 112 | on_exit() 113 | { 114 | exit_status=$? 115 | 116 | echo "Sending email with job status" 117 | cat << EOM | sendmail -t 118 | From: root 119 | To: bjorn.forsman@gmail.com 120 | Subject: Archived photos from Syncthing 121 | 122 | This is an automatic message sent from host $HOSTNAME showing the status 123 | of the archive-photos-from-syncthing job: 124 | 125 | $(systemctl status archive-photos-from-syncthing -n10000) 126 | EOM 127 | 128 | exit "$exit_status" 129 | } 130 | trap 'on_exit' INT TERM QUIT EXIT 131 | 132 | # For testing, add/change these exiftool args: 133 | # * Add "-o ." to copy instead of move and change the -d value to "$HOME/tmp/exiftool/%Y/%Y-%m". 134 | echo "Processing files in $input_dir. Files older than $days_to_keep days will be moved to $pictures_archive in YEAR + MONTH subdirs." 135 | find "$input_dir" -type f -mtime +"$days_to_keep" -print0 | xargs -0 --no-run-if-empty exiftool '-Directory/dev/null 2>&1; then 57 | "${pkgs.lvm2}/bin/lvremove" --yes "/dev/${vgname}/$snapshotName" || exit_status=1 58 | fi 59 | ''; 60 | }; 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /machines/srv1/configuration.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | lan0 = "enp0s25"; 5 | in 6 | { 7 | imports = [ 8 | ./hardware-configuration.nix 9 | 10 | ./backup.nix 11 | ./ddclient.nix 12 | ./syncthing.nix 13 | 14 | ../../cfg/base-small.nix 15 | ../../cfg/bcache.nix 16 | ../../cfg/cgit.nix 17 | ../../cfg/deconz.nix 18 | ../../cfg/git-daemon.nix 19 | ../../cfg/gitolite.nix 20 | ../../cfg/nix-remote-build-server.nix 21 | ../../cfg/postfix.nix 22 | ../../cfg/smart-daemon.nix 23 | ../../cfg/swraid.nix 24 | ../../cfg/transmission.nix 25 | ../../profiles/backup-server.nix 26 | ../../profiles/webserver.nix 27 | ../../users/bf.nix 28 | ]; 29 | 30 | # Use the systemd-boot EFI boot loader. 31 | boot.loader.grub.enable = lib.mkForce false; 32 | boot.loader.systemd-boot.enable = true; 33 | boot.loader.efi.canTouchEfiVariables = true; 34 | 35 | # This machine has an old nvidia gfx card and "nomodeset" is needed to 36 | # prevent the display from going black / freeze in stage-2 boot. 37 | boot.kernelParams = [ "nomodeset" ]; 38 | 39 | environment.systemPackages = with pkgs; [ 40 | apacheHttpd # for `htpasswd` (manage users/passwords for lighttpd) 41 | htop 42 | iotop 43 | ncdu 44 | nix-review 45 | python # sshuttle needs python on the server side 46 | sysstat 47 | usbutils 48 | ]; 49 | 50 | networking.hostName = "srv1"; 51 | 52 | networking.firewall.allowedTCPPorts = [ 53 | 80 # web / http 54 | 443 # web / https 55 | 445 # samba 56 | 9418 # git daemon 57 | ]; 58 | 59 | # Add a bridge interface to be able to put libvirt/QEMU/KVM VMs directly on 60 | # the LAN. 61 | networking.bridges = { 62 | br0 = { interfaces = [ lan0 ]; }; 63 | }; 64 | # TODO: shouldn't have to turn off useDHCP just because dhcpcd doesn't enable 65 | # dhcp for bridges by default (that should be handled by the next line). 66 | # Ref. https://github.com/NixOS/nixpkgs/pull/82295 67 | networking.useDHCP = lib.mkForce false; 68 | networking.interfaces.br0.useDHCP = true; 69 | 70 | services.atd.enable = true; 71 | 72 | virtualisation.libvirtd.enable = true; 73 | 74 | swapDevices = [ 75 | { device = "/var/swap"; size = 32*1024; /* MiB */ } 76 | ]; 77 | 78 | system.stateVersion = "19.03"; 79 | } 80 | -------------------------------------------------------------------------------- /machines/srv1/ddclient.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.ddclient = { 3 | enable = true; 4 | # Use imperative configuration to keep secrets out of the (world 5 | # readable) Nix store. If this option is not set, the NixOS options from 6 | # services.ddclient.* will be used to populate /etc/ddclient.conf. 7 | configFile = "/var/lib/ddclient/secrets/ddclient.conf"; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /machines/srv1/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/installer/scan/not-detected.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "ehci_pci" "nvme" "usbhid" "usb_storage" "sd_mod" "bcache" ]; 12 | boot.initrd.kernelModules = [ "dm-snapshot" ]; 13 | boot.kernelModules = [ "kvm-intel" ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | fileSystems."/" = 17 | { device = "/dev/disk/by-uuid/a1c0995e-00d3-4b8e-a49b-0b02d4c4824d"; 18 | fsType = "ext4"; 19 | }; 20 | 21 | fileSystems."/boot" = 22 | { device = "/dev/disk/by-uuid/6742-8169"; 23 | fsType = "vfat"; 24 | }; 25 | 26 | swapDevices = [ ]; 27 | 28 | nix.maxJobs = lib.mkDefault 12; 29 | powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; 30 | } 31 | -------------------------------------------------------------------------------- /machines/srv1/syncthing.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../cfg/syncthing.nix 4 | ]; 5 | 6 | networking.firewall.allowedTCPPorts = [ 7 | 8384 # syncthing web ui (TODO: auth) 8 | ]; 9 | 10 | services = { 11 | syncthing.guiAddress = "0.0.0.0:8384"; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /options/borg-backup.nix: -------------------------------------------------------------------------------- 1 | # NixOS module for BorgBackup. 2 | 3 | /* 4 | Restore everything: 5 | $ cd /mnt/restore 6 | $ [sudo] borg extract -v --list --numeric-owner /mnt/backup-disk/repo-name::archive-name 7 | 8 | Restore from remote repository: 9 | $ [sudo BORG_RSH='ssh -i /home/bf/.ssh/id_rsa'] borg extract -v --list --numeric-owner --remote-path="sudo borg" ssh://bf@server/mnt/backup-disk/repo-name::archive-name 10 | 11 | Interactive restore (slower than 'borg extract'): 12 | $ borg mount /mnt/backup-disk/repo-name /mnt/fuse-mountpoint 13 | $ ls -1 /mnt/fuse-mountpoint 14 | my-machine-20150220T234453 15 | my-machine-20150321T114708 16 | ... restore files (cp/rsync) ... 17 | $ borg umount /mnt/fuse-mountpoint 18 | */ 19 | 20 | { config, lib, pkgs, ... }: 21 | 22 | with lib; 23 | 24 | let 25 | cfg = config.services.borg-backup; 26 | 27 | # - The initial backup repo must be created manually: 28 | # $ sudo borg init --encryption none $repository 29 | # - "icfg" is short for "instance configuration" 30 | mkBackupScript = icfg: pkgs.writeScript "borg-backup" '' 31 | #!${pkgs.bash}/bin/sh 32 | repository="${icfg.repository}" 33 | archive="${icfg.archiveBaseName}-$(date +%Y%m%dT%H%M%S)" 34 | archive_in_progress="$archive.IN_PROGRESS" 35 | archive_unsuccessful="$archive.UNSUCCESSFUL" 36 | 37 | on_exit() 38 | { 39 | exit_status=$? 40 | # Reset the EXIT handler, or else we're called again on 'exit' below 41 | trap - EXIT 42 | echo "Running postHook" 43 | ${icfg.postHook} 44 | echo "Done, exiting with status $exit_status." 45 | 46 | # Allow systemd/journal to associate the last messages from this unit 47 | # before exit. Yep, it's a race. 48 | sleep 3 49 | exit $exit_status 50 | } 51 | trap 'on_exit' INT TERM QUIT EXIT 52 | 53 | # Inject the environment variables here, so they'll be available also 54 | # when not run under systemd. 55 | ${lib.concatMapStringsSep "\n" (x: x) (lib.mapAttrsFlatten (n: v: "export ${n}=\"${v}\"") icfg.environment)} 56 | 57 | echo "Running preHook" 58 | ${icfg.preHook} 59 | 60 | # Prevent borg from looking at autofs mountpoints. (Because if the 61 | # underlying filesystem cannot be mounted, stat() returns ENODEV, borg 62 | # prints a warning and exits with status 1. Even with --one-file-system.) 63 | autofs_excludes=$(cat /proc/mounts | while read src mountpoint fstype rest; do 64 | test "$fstype" = autofs && printf "%s %q\n" --exclude "$mountpoint"; done) 65 | 66 | echo "Running 'borg create [...]'" 67 | (cd "${icfg.rootDir}" && borg create \ 68 | --stats \ 69 | --verbose \ 70 | --list \ 71 | --filter ME \ 72 | --show-rc \ 73 | --one-file-system \ 74 | $autofs_excludes \ 75 | --exclude-caches \ 76 | ${if icfg.excludeNix then '' 77 | --exclude /etc/nix/nix.conf \ 78 | --exclude /nix/ \ 79 | '' else ''\''} 80 | ${lib.concatMapStringsSep "\n" (x: "--exclude ${x} \\") icfg.excludes} 81 | --compression lz4 \ 82 | "$repository::$archive_in_progress" \ 83 | ${lib.concatStringsSep " " icfg.pathsToBackup}) 84 | create_ret=$? 85 | 86 | if [ $create_ret = 0 ]; then 87 | final_archive_name="$archive" 88 | else 89 | final_archive_name="$archive_unsuccessful" 90 | fi 91 | echo "Renaming archive: $archive_in_progress -> $final_archive_name" 92 | (cd "${icfg.rootDir}" && borg rename "$repository::$archive_in_progress" "$final_archive_name") || create_ret=1 93 | 94 | echo "Running 'borg prune [...]'" 95 | (cd "${icfg.rootDir}" && borg prune \ 96 | --stats \ 97 | --verbose \ 98 | --list \ 99 | --show-rc \ 100 | --keep-within=2d --keep-daily=7 --keep-weekly=4 --keep-monthly=6 \ 101 | --prefix "${icfg.archiveBaseName}-" \ 102 | "$repository") 103 | prune_ret=$? 104 | 105 | # Rate limit repository checks, since they are quite expensive. 106 | repository_dir="$(dirname ${icfg.repository})" 107 | repository_name="$(basename ${icfg.repository})" 108 | repository_check_stampfile="$repository_dir/.$repository_name.check_stamp" 109 | repo_check_min_interval_in_days=1 110 | repo_check_is_old=0 111 | if [ ! -f "$repository_check_stampfile" ]; then 112 | repo_check_is_old=1 113 | elif [ "$(find "$repository_check_stampfile" -ctime "+$repo_check_min_interval_in_days")" ]; then 114 | repo_check_is_old=1 115 | fi 116 | if [ "$repo_check_is_old" -eq 1 ]; then 117 | check_day=Sunday 118 | this_day=$(date +%A) 119 | if [ "$this_day" = "$check_day" ]; then 120 | echo "Running 'borg check [...]' (since a check is due and today is $this_day)" 121 | (cd "${icfg.rootDir}" && borg check \ 122 | --verbose \ 123 | --show-rc \ 124 | "$repository") 125 | check_ret=$? 126 | touch "$repository_check_stampfile" 127 | else 128 | echo "Skipping 'borg check' since today is not $check_day (it's $this_day)" 129 | check_ret=0 130 | fi 131 | else 132 | echo "Skipping 'borg check' since the last check was done less than $repo_check_min_interval_in_days day(s) ago" 133 | check_ret=0 134 | fi 135 | 136 | # Exit with error if either command failed 137 | if [ $create_ret != 0 ] || [ $prune_ret != 0 ] || [ $check_ret != 0 ]; then 138 | echo "borg create, prune and/or check operation failed. Exiting with error." 139 | false # sets $? for the postHook 140 | fi 141 | ''; 142 | 143 | mkService = name: value: { 144 | name = "borg-backup-${name}"; 145 | value = { 146 | description = "Borg Backup Service ${name}"; 147 | path = with pkgs; [ 148 | borgbackup utillinux coreutils gawk openssh 149 | "/run/wrappers" # for sendmail 150 | ]; 151 | serviceConfig.SyslogIdentifier = "borg-backup-${name}"; # else HASH-borg-backup 152 | serviceConfig.ExecStart = mkBackupScript value; 153 | } // (if value.startAt != null then { startAt = value.startAt; } else { }); 154 | }; 155 | 156 | in 157 | { 158 | options.services.borg-backup = { 159 | 160 | enable = mkEnableOption "enable borg backup service to take nightly backups."; 161 | 162 | jobs = mkOption { 163 | type = types.attrsOf (types.submodule { 164 | options = { 165 | 166 | repository = mkOption { 167 | type = types.str; 168 | default = ""; 169 | example = "/mnt/backups/backup.borg"; 170 | description = '' 171 | Path to Borg repository where the backup will be stored. 172 | ''; 173 | }; 174 | 175 | archiveBaseName = mkOption { 176 | type = types.str; 177 | default = config.networking.hostName; 178 | defaultText = "config.networking.hostName"; 179 | description = '' 180 | Complete archive names look like "$archiveBaseName-DATE". 181 | ''; 182 | }; 183 | 184 | excludeNix = mkOption { 185 | type = types.bool; 186 | default = false; 187 | description = '' 188 | Whether to exclude /nix/ (and the generated file /etc/nix/nix.conf) 189 | from the backup. Set it to false if you want to be able to do full 190 | system restore from your backup. Set it to true if you want to save 191 | some disk space and are okay with having to recover your system by 192 | running nixos-install. A prerequisite for this option is that 193 | pathsToBackup includes the Nix store. 194 | ''; 195 | }; 196 | 197 | excludes = mkOption { 198 | type = types.listOf types.str; 199 | default = [ 200 | "/tmp/" 201 | "/var/tmp/" 202 | "/var/swapfile" 203 | "'/home/*/.cache/'" 204 | "'/home/*/.thumbnails/'" 205 | "'/home/*/.nox/'" 206 | "'*/.Trash*/'" 207 | "'*/$RECYCLE.BIN'" 208 | "'*/System Volume Information'" 209 | ]; 210 | description = '' 211 | List of files/directories/patterns to exclude from the backup. Each 212 | element will be passed to borg as "--exclude elem". 213 | ''; 214 | }; 215 | 216 | rootDir = mkOption { 217 | type = types.path; 218 | default = "/"; 219 | example = [ "/mnt/remote-fs" ]; 220 | description = '' 221 | The directory from where borg commands will be run. Relateive paths 222 | in are relative to this directory. 223 | ''; 224 | }; 225 | 226 | pathsToBackup = mkOption { 227 | type = types.listOf types.str; 228 | default = [ "/" "/boot" ]; 229 | example = [ "/home" "/srv" ]; 230 | description = '' 231 | List of paths to backup, relative to , unless using absolute paths. 232 | The backup does not cross filesystem 233 | boundaries, so each filesystem (mountpoint) you want to have backed up 234 | must be listed here. 235 | ''; 236 | }; 237 | 238 | preHook = mkOption { 239 | type = types.lines; 240 | default = ""; 241 | description = '' 242 | Shell commands to run before backing up. Abort the backup with 243 | 'exit N'. 244 | ''; 245 | }; 246 | 247 | postHook = mkOption { 248 | type = types.lines; 249 | default = ""; 250 | description = '' 251 | Shell commands to run just before exit, for example to undo resource 252 | allocations done by the preHook. These commands are run even on 253 | unsuccessful backups (e.g if the preHook calls 'exit'). The 254 | (planned) exit status is stored in the "exit_status" variable and 255 | can be modified by this hook, if desired. Do not call 'exit' from 256 | this hook, that may cause the most recent log output to not be 257 | associated with this backup job (it's a kernel/systemd/journal race). 258 | ''; 259 | }; 260 | 261 | startAt = mkOption { 262 | type = with types; nullOr str; 263 | default = "*-*-* 01:15:00"; 264 | description = '' 265 | When to run the backup, in systemd.time(7) format. If null, the 266 | backup job will not be started automatically. Use this to start 267 | the backup by some other means -- either manually or by 268 | configuring your own systemd dependencies (e.g. start backup when 269 | a certain USB disk is inserted). 270 | ''; 271 | }; 272 | 273 | environment = mkOption { 274 | type = with types; attrsOf str; 275 | default = {}; 276 | example = lib.literalExample '' 277 | { BORG_PASSCOMMAND = "cat /path/to/password-file"; 278 | BORG_RSH = "ssh -i /root/.ssh/id_backup"; 279 | } 280 | ''; 281 | description = '' 282 | Extra environment variables, set in the job script. 283 | ''; 284 | }; 285 | 286 | }; 287 | }); 288 | default = {}; 289 | description = '' 290 | Each attribute of this option defines a BorgBackup job. The name of 291 | each systemd service is "borg-backup-ATTR". If there is an attribute 292 | named "default", its repository path will be exported in the BORG_REPO 293 | environment variable, for easy (interactive) access. 294 | ''; 295 | }; 296 | 297 | }; 298 | 299 | config = mkIf cfg.enable { 300 | 301 | assertions = [ 302 | { assertion = builtins.length (builtins.attrNames cfg.jobs) > 0; 303 | message = "No backup jobs defined in services.borg-backup.jobs.*"; 304 | } 305 | ] ++ 306 | (mapAttrsToList 307 | (name: value: { 308 | assertion = config.services.borg-backup.jobs."${name}".repository != ""; 309 | message = "Please specify a value in services.borg-backup.jobs.${name}.repository."; 310 | }) 311 | cfg.jobs) 312 | ++ 313 | (mapAttrsToList 314 | (name: value: { 315 | assertion = config.services.borg-backup.jobs."${name}".pathsToBackup != []; 316 | message = "Please specify a value in services.borg-backup.jobs.${name}.pathsToBackup."; 317 | }) 318 | cfg.jobs); 319 | 320 | # for convenience 321 | environment.sessionVariables = mkIf (cfg.jobs ? "default") { 322 | BORG_REPO = "${cfg.jobs."default".repository}"; 323 | }; 324 | 325 | systemd.services = mapAttrs' mkService cfg.jobs; 326 | 327 | }; 328 | 329 | } 330 | -------------------------------------------------------------------------------- /options/cifs-user-mount.nix: -------------------------------------------------------------------------------- 1 | # Mount CIFS share(s) for users at login, as a systemd user services (one per 2 | # share). 3 | # 4 | # Rationale: 5 | # In GNOME one can use gvfs-mount. But in KDE/Plasma there is no equivalent 6 | # tool. And there seems to be no working FUSE implementation for CIFS. 7 | # mount.cifs requires root and/or previously set up entry in /etc/fstab. Hence 8 | # we have to jump through some hoops, which are abstracted by this module. 9 | # 10 | # TODO: Look into pam_mount and pam_cifscreds. 11 | 12 | { config, lib, pkgs, ... }: 13 | 14 | with lib; 15 | 16 | let 17 | cfg = config.services.cifs-user-mount; 18 | 19 | # A mount.cifs/umount wrapper that checks if the mountpoint is inside user's 20 | # home directory (it exits with non-zero status if not). 21 | commonHelper = command: '' 22 | #!${pkgs.bash}/bin/bash 23 | set -e 24 | 25 | path_is_subdir_of_home() 26 | { 27 | # Use readlink to prevent subverting the check with "../.." appended to the path. 28 | normalized_path="$(readlink -f "$1")" 29 | #real_user_home=$(getent passwd $SUDO_USER | cut -d: -f6) 30 | #real_user_home=$(echo ~$SUDO_USER) 31 | #real_user_home=~$SUDO_USER 32 | real_user_home=$PWD # user services are invoked with PWD=$HOME 33 | test -d "$real_user_home" || return 1 34 | # Add trailing slash to prevent user "al" from matching user "alice" 35 | # home (/home/al is substring of /home/alice). 36 | echo x"$normalized_path/" | grep -q "^x$real_user_home/" 37 | } 38 | 39 | # Check all arguments. If any is a path, it must be located within the 40 | # users home directory, else we abort. 41 | for arg in "$@"; do 42 | if [ -d "$arg" ]; then 43 | if path_is_subdir_of_home "$arg"; then 44 | echo "Access to $arg is allowed." 45 | else 46 | echo "Access to $arg is denied -- not a subdirectory of user home ($real_user_home)" 47 | exit 1 48 | fi 49 | fi 50 | done 51 | 52 | # Run the command 53 | echo "${command}" 54 | ${command} 55 | ''; 56 | 57 | cifsMountHelper = pkgs.writeScript "cifs-mount-helper" 58 | (commonHelper ''${pkgs.cifs-utils}/bin/mount.cifs "$@"''); 59 | 60 | cifsUmountHelper = pkgs.writeScript "cifs-umount-helper" 61 | (commonHelper ''${pkgs.utillinux}/bin/umount "$@"''); 62 | 63 | flattenedShareName = share: 64 | replaceChars [ "$" "/" ] [ "" "" ] share.shareName; 65 | 66 | mkStartScript = share: 67 | pkgs.writeScript "cifs-user-mount-start" '' 68 | #!${pkgs.bash}/bin/bash 69 | mkdir -p "${share.mountpoint}/${flattenedShareName share}" || exit 1 70 | # Somethimes the network isn't ready yet, so run a loop. (Systemd 71 | # doesn't support Restart= for oneshot services, see 72 | # https://github.com/systemd/systemd/issues/2582.) 73 | for i in $(seq 10); do 74 | if sudo "${cifsMountHelper}" "//${share.server}/${share.shareName}" "${share.mountpoint}/${flattenedShareName share}" -o "${share.options}"; then 75 | # Sleep to ensure the last log output gets associated with the service 76 | # (known system journal race condition). 77 | sleep 3 78 | exit 0 79 | else 80 | echo "Trying again..." 81 | sleep 2 82 | fi 83 | done 84 | 85 | # Sleep to ensure the last log output gets associated with the service 86 | # (known system journal race condition). 87 | sleep 3 88 | 89 | # Failed 90 | exit 1 91 | ''; 92 | 93 | mkStopScript = share: 94 | pkgs.writeScript "cifs-user-mount-stop" '' 95 | #!${pkgs.bash}/bin/bash 96 | sudo "${cifsUmountHelper}" "${share.mountpoint}/${flattenedShareName share}" 97 | ret=$? 98 | 99 | # Sleep to ensure the last log output gets associated with the service 100 | # (known system journal race condition). 101 | sleep 3 102 | exit $ret 103 | ''; 104 | 105 | mkService = share: { 106 | name = "cifs-user-mount-${flattenedShareName share}"; 107 | value = { 108 | description = "CIFS user mount for //${share.server}/${share.shareName}"; 109 | wantedBy = [ "default.target" ]; 110 | wants = [ "network-online.target" ]; 111 | after = [ "network-online.target" ]; 112 | path = with pkgs; [ "/run/wrappers" /* for sudo */ ]; 113 | serviceConfig = { 114 | ExecStart = mkStartScript share; 115 | ExecStop = mkStopScript share; 116 | Type = "oneshot"; 117 | RemainAfterExit = true; 118 | SyslogIdentifier = "cifs-user-mount-${flattenedShareName share}"; 119 | }; 120 | }; 121 | }; 122 | 123 | in 124 | 125 | { 126 | options.services.cifs-user-mount = { 127 | enable = mkOption { 128 | type = types.bool; 129 | default = false; 130 | description = '' 131 | Whether to enable mounting CIFS shares as systemd user services. 132 | ''; 133 | }; 134 | 135 | shares = mkOption { 136 | type = types.listOf types.attrs; 137 | default = [ ]; 138 | example = literalExample '' 139 | [ { server = "server.example"; 140 | shareName = "files"; 141 | mountpoint = "$HOME/mnt/remote/server.example"; 142 | options = "credentials=$HOME/.server.credentials,uid=$(id -u),gid=$(id -g),file_mode=0600,dir_mode=0700,iocharset=utf8,rw"; 143 | } 144 | ] 145 | ''; 146 | description = '' 147 | List of CIFS shares to be mounted somewhere under user $HOME. The 148 | environment variable $USER can be used in shareName to retrieve 149 | the user login name, for per-user server shares. $HOME is also available. 150 | 151 | The credentials file has the following format: 152 | 153 | domain=YOUR_DOMAIN 154 | username=YOUR_USERNAME 155 | password=YOUR_PASSWORD 156 | 157 | IMPORTANT: Set permissions to 600 on the credentials file to prevent 158 | group/world readable file. 159 | ''; 160 | }; 161 | }; 162 | 163 | config = mkIf cfg.enable { 164 | # Give the "users" group access to the custom cifs (u)mount helpers, without 165 | # being asked for password. 166 | security.sudo.extraConfig = mkAfter '' 167 | %users ALL = NOPASSWD: NOSETENV: ${cifsMountHelper}, ${cifsUmountHelper} 168 | ''; 169 | 170 | systemd.user.services = builtins.listToAttrs (map (x: mkService x) cfg.shares); 171 | }; 172 | } 173 | -------------------------------------------------------------------------------- /options/collectd-graph-panel.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.services.lighttpd.collectd-graph-panel; 7 | 8 | phpfpmSocketName = config.services.phpfpm.pools.collectd-graph-panel.socket; 9 | 10 | collectd-graph-panel-1 = 11 | pkgs.stdenv.mkDerivation rec { 12 | name = "collectd-graph-panel-${version}"; 13 | version = "1"; 14 | src = pkgs.fetchzip { 15 | name = "${name}-src"; 16 | url = "https://github.com/pommi/CGP/archive/v${version}.tar.gz"; 17 | sha256 = "1inifs9rapjyjx43046lcjsz2pvnd0n7dihk07577ld2xw5gydv9"; 18 | }; 19 | appendConf = pkgs.writeText "config.php.append" '' 20 | 21 | # loading configuration passed in environment variable 22 | $local_config_file = getenv('LOCAL_CONFIG_FILE'); 23 | if ($local_config_file != 'FALSE' && file_exists($local_config_file)) 24 | include_once $local_config_file; 25 | ''; 26 | buildCommand = '' 27 | mkdir -p "$out" 28 | cp -r "$src"/. "$out" 29 | chmod +w "$out"/conf 30 | mv "$out"/conf/config.php config.php.orig 31 | cat config.php.orig "${appendConf}" >"$out"/conf/config.php 32 | ''; 33 | }; 34 | in 35 | { 36 | options.services.lighttpd.collectd-graph-panel = { 37 | 38 | enable = mkEnableOption "Collectd Graph Panel in lighttpd"; 39 | 40 | package = mkOption { 41 | type = types.package; 42 | default = collectd-graph-panel-1; 43 | defaultText = "collectd-graph-panel-1"; 44 | description = "Collectd Graph Panel package to use."; 45 | }; 46 | 47 | configText = mkOption { 48 | type = types.lines; 49 | default = '' 50 | 58 | ''; 59 | description = '' 60 | Contents of config.local.php, a file that is included by CGP, to 61 | override/customize its default configuration. 62 | ''; 63 | }; 64 | 65 | urlPrefix = mkOption { 66 | type = types.str; 67 | default = "/collectd"; 68 | example = "/"; 69 | description = '' 70 | The prefix below the web server root URL to serve Collectd Graph Panel. 71 | ''; 72 | }; 73 | 74 | vhostsPattern = mkOption { 75 | type = types.str; 76 | default = ".*"; 77 | example = "(myserver1.example|myserver2.example)"; 78 | description = '' 79 | A virtual host regexp filter. Change it if you want Collectd Graph 80 | Panel to only be served from some host names, instead of all. 81 | ''; 82 | }; 83 | 84 | }; 85 | 86 | config = mkIf (config.services.lighttpd.enable && cfg.enable) { 87 | 88 | services.lighttpd = { 89 | enableModules = [ "mod_alias" "mod_fastcgi" "mod_setenv" ]; 90 | extraConfig = '' 91 | $HTTP["host"] =~ "${cfg.vhostsPattern}" { 92 | alias.url += ( "${cfg.urlPrefix}" => "${cfg.package}/" ) 93 | $HTTP["url"] =~ "^${cfg.urlPrefix}" { 94 | index-file.names += ( "index.php" ) 95 | fastcgi.server = ( 96 | ".php" => ( 97 | "phpfpm-collectd-graph-panel" => ( 98 | "socket" => "${phpfpmSocketName}", 99 | ) 100 | ) 101 | ) 102 | setenv.add-environment = ( 103 | "LOCAL_CONFIG_FILE" => 104 | "${pkgs.writeText "collectd-graph-panel-local-conf.php" 105 | cfg.configText}" 106 | ) 107 | } 108 | } 109 | ''; 110 | }; 111 | 112 | services.phpfpm.pools = { 113 | collectd-graph-panel = { 114 | # Unbreak by using php-7.2 instead of default 7.3: 115 | # Ref. https://github.com/pommi/CGP/issues/171 116 | phpPackage = pkgs.php72; 117 | user = "lighttpd"; 118 | group = "lighttpd"; 119 | settings = { 120 | "listen.owner" = "lighttpd"; 121 | "listen.group" = "lighttpd"; 122 | "pm" = "dynamic"; 123 | "pm.max_children" = 75; 124 | "pm.start_servers" = 10; 125 | "pm.min_spare_servers" = 5; 126 | "pm.max_spare_servers" = 20; 127 | "pm.max_requests" = 500; 128 | }; 129 | }; 130 | }; 131 | }; 132 | 133 | } 134 | -------------------------------------------------------------------------------- /options/deconz.nix: -------------------------------------------------------------------------------- 1 | # NixOS module for running deCONZ ZigBee gateway as a service. 2 | # 3 | # FIXME: These two auth issues: 4 | # https://github.com/dresden-elektronik/deconz-rest-plugin/issues/1788 ("Auth problems on non-80 http port") 5 | # https://github.com/dresden-elektronik/deconz-rest-plugin/issues/1792 ("Trying to change password: "Service not available. Try again later.") 6 | 7 | { config, lib, pkgs, ... }: 8 | 9 | with lib; 10 | 11 | let 12 | cfg = config.local.services.deconz; 13 | name = "deconz"; 14 | stateDir = "/var/lib/${name}"; 15 | in 16 | { 17 | options.local.services.deconz = { 18 | 19 | enable = mkEnableOption "deCONZ, a ZigBee gateway"; 20 | 21 | package = mkOption { 22 | type = types.package; 23 | default = pkgs.deconz; 24 | defaultText = "pkgs.deconz"; 25 | description = "Which deCONZ package to use."; 26 | }; 27 | 28 | device = mkOption { 29 | type = types.str; 30 | default = ""; 31 | description = '' 32 | Force deCONZ to use a specific USB device (e.g. /dev/ttyACM0). By 33 | default it does a search. 34 | ''; 35 | }; 36 | 37 | httpPort = mkOption { 38 | type = types.port; 39 | default = 80; 40 | description = "TCP port for the web server."; 41 | }; 42 | 43 | wsPort = mkOption { 44 | type = types.port; 45 | default = 443; 46 | description = "TCP port for the WebSocket."; 47 | }; 48 | 49 | openFirewall = mkEnableOption "open up the service ports in the firewall"; 50 | 51 | allowRebootSystem = mkEnableOption "allow rebooting the system"; 52 | 53 | allowRestartService = mkEnableOption "allow killing/restarting processes"; 54 | 55 | allowSetSystemTime = mkEnableOption "allow setting the system time"; 56 | 57 | extraOpts = mkOption { 58 | type = types.listOf types.str; 59 | default = [ 60 | "--auto-connect=1" 61 | "--dbg-info=1" 62 | ]; 63 | description = '' 64 | Extra command line options for deCONZ. 65 | These options seem undocumented, but some examples can be found here: 66 | https://github.com/marthoc/docker-deconz/blob/master/amd64/root/start.sh 67 | ''; 68 | }; 69 | }; 70 | 71 | config = mkIf cfg.enable { 72 | 73 | networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 74 | cfg.httpPort 75 | cfg.wsPort 76 | ]; 77 | 78 | systemd.services.deconz = { 79 | description = "deCONZ ZigBee gateway"; 80 | wantedBy = [ "multi-user.target" ]; 81 | 82 | preStart = '' 83 | # The service puts a nix store path reference in here, and that path can 84 | # be garbage collected. Ensure the file gets "refreshed" on every start. 85 | rm -f ${stateDir}/.local/share/dresden-elektronik/deCONZ/zcldb.txt 86 | ''; 87 | serviceConfig = { 88 | ExecStart = 89 | "${cfg.package}/bin/deCONZ" 90 | + " -platform minimal" 91 | + " --http-port=${toString cfg.httpPort}" 92 | + " --ws-port=${toString cfg.wsPort}" 93 | + (if cfg.device != "" then " --dev=${cfg.device}" else "") 94 | + " " + (lib.concatStringsSep " " cfg.extraOpts); 95 | Restart = "on-failure"; 96 | AmbientCapabilities = 97 | let 98 | # ref. upstream deconz.service 99 | caps = lib.optionals (cfg.httpPort < 1024 || cfg.wsPort < 1024) [ "CAP_NET_BIND_SERVICE" ] 100 | ++ lib.optionals (cfg.allowRebootSystem) [ "CAP_SYS_BOOT" ] 101 | ++ lib.optionals (cfg.allowRestartService) [ "CAP_KILL" ] 102 | ++ lib.optionals (cfg.allowSetSystemTime) [ "CAP_SYS_TIME" ]; 103 | in 104 | lib.concatStringsSep " " caps; 105 | UMask = "0027"; 106 | User = name; 107 | StateDirectory = name; 108 | WorkingDirectory = stateDir; 109 | 110 | ProtectSystem = "strict"; 111 | ProtectHome = true; 112 | ReadWritePaths = "/tmp"; 113 | }; 114 | }; 115 | 116 | users.users.deconz = { 117 | group = name; 118 | isSystemUser = true; 119 | home = stateDir; 120 | extraGroups = [ "dialout" ]; # for access to /dev/ttyACM0 (ConBee) 121 | }; 122 | 123 | users.groups.deconz = {}; 124 | }; 125 | } 126 | -------------------------------------------------------------------------------- /options/gitolite-mirror.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.services.gitolite-mirror; 7 | in 8 | { 9 | options.services.gitolite-mirror = { 10 | 11 | enable = mkEnableOption "enable configuration of mirrored git repos served under gitolite. Use wild repo configuration in gitolite to match the mirrorPrefix option"; 12 | 13 | mirrorPrefix = mkOption { 14 | type = types.str; 15 | default = "mirrors/"; 16 | description = '' 17 | Where under the gitolite repositories directory to keep mirrored 18 | git repositories. 19 | ''; 20 | }; 21 | 22 | repoUrls = mkOption { 23 | type = types.listOf types.str; 24 | default = []; 25 | example = [ "https://github.com/nixos/nixpkgs" ]; 26 | description = '' 27 | List of git repository URLs that should be mirrored. 28 | ''; 29 | }; 30 | 31 | }; 32 | 33 | config = mkIf cfg.enable { 34 | 35 | assertions = [ 36 | { assertion = config.services.gitolite.enable; 37 | message = "The gitolite service must be enabled"; 38 | } 39 | ]; 40 | 41 | systemd.services.gitolite-mirror = { 42 | description = "Maintain Git Mirror Repositories"; 43 | # Run 6 minutes past ever every hour during the day. (Don't update at night 44 | # during backup.) See systemd.time(7) for details about the format. 45 | startAt = "*-*-* 7..23:06"; 46 | script = '' 47 | bare_repo_name_from_url() 48 | { 49 | # Normalize by removing optional trailing '.git' and then always 50 | # appending it. 51 | echo "$(basename "$1" | sed -e "s/\.git$//").git" 52 | } 53 | 54 | # $HOME is needed for git to expand ~ in /etc/gitconfig (or else fail) 55 | export HOME="${config.services.gitolite.dataDir}" 56 | 57 | mkdir -p "${config.services.gitolite.dataDir}/repositories/${cfg.mirrorPrefix}" 58 | cd "${config.services.gitolite.dataDir}/repositories/${cfg.mirrorPrefix}" 59 | 60 | #inited_one_or_more=0 61 | for url in ${lib.concatStringsSep " " cfg.repoUrls}; do 62 | # Init repository. 63 | # (git clone is fairly atomic in that either the clone completes or 64 | # not, there is no in-between state if the command is aborted.) 65 | local_repo=$(bare_repo_name_from_url "$url") 66 | if [ ! -d "$local_repo" ]; then 67 | echo "Initializing mirror repo \"$local_repo\" from \"$url\"" 68 | "${pkgs.git}/bin/git" clone --mirror "$url" 69 | inited_one_or_more=1 70 | fi 71 | 72 | # Update repo description 73 | new_repo_description="Mirror of $url" 74 | old_repo_description=$(cat "$local_repo"/description) 75 | if [ "$new_repo_description" != "$old_repo_description" ]; then 76 | echo "Updating repository description in $local_repo" 77 | echo "$new_repo_description" > "$local_repo"/description 78 | fi 79 | 80 | # Update existing repos 81 | echo "Updating repo: $url" 82 | (cd "$local_repo" \ 83 | && "${pkgs.git}/bin/git" remote update --prune \ 84 | && "${pkgs.git}/bin/git" gc \ 85 | ) >/dev/null 86 | done 87 | 88 | # Is this needed? 89 | #if [ "$inited_one_or_more" -eq 1 ]; then 90 | # # Refresh so that new repositories are shown in cgit 91 | # #gitolite setup ... 92 | #fi 93 | ''; 94 | serviceConfig.User = config.services.gitolite.user; 95 | serviceConfig.UMask = "0027"; 96 | serviceConfig.WorkingDirectory = config.services.gitolite.dataDir; 97 | }; 98 | 99 | }; 100 | 101 | } 102 | -------------------------------------------------------------------------------- /options/module-list.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | "${import ../inputs/home-manager.nix {}}/nixos/default.nix" 4 | ../options/borg-backup.nix 5 | ../options/cifs-user-mount.nix 6 | ../options/deconz.nix 7 | ../options/collectd-graph-panel.nix 8 | ../options/gitolite-mirror.nix 9 | ../options/nextcloud.nix 10 | ../options/pia/pia-nm.nix 11 | ../options/resources.nix 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /options/motion.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.services.motion; 7 | 8 | dataDir = "/var/lib/motion"; 9 | 10 | # TODO: add uid/gid to NixOS 11 | motionUser = "motion"; 12 | motionGroup = "motion"; 13 | motionUid = 510; 14 | motionGid = 510; 15 | 16 | umask = "0027"; 17 | 18 | createServiceInstance = name: value: 19 | { name = "motion-instance-${name}"; 20 | value = 21 | let 22 | configFile = pkgs.writeText "motion.conf" (value.configText + '' 23 | target_dir ${dataDir}/${name} 24 | ''); 25 | in 26 | { 27 | description = "Motion Camera Monitor ${name}"; 28 | wantedBy = [ "motion.target" ]; 29 | partOf = [ "motion.target" ]; 30 | after = [ "motion-setup.service" ]; 31 | requires = [ "motion-setup.service" ]; 32 | serviceConfig.User = motionUser; 33 | serviceConfig.Group = motionGroup; 34 | serviceConfig.UMask = umask; 35 | #serviceConfig.WorkingDirectory = "${dataDir}/${name}"; 36 | serviceConfig.ExecStart = "${pkgs.motion}/bin/motion -n -c ${configFile} ${concatStringsSep " " value.extraOpts}"; 37 | }; 38 | }; 39 | 40 | createGarbageCollectScript = name: value: 41 | '' 42 | # 43 | # GC in ${dataDir}/${name} on behalf of motion-instance-${name}.service 44 | # Delete by time: 45 | find "${dataDir}/${name}" -ctime +${builtins.toString value.limitDays} -delete 46 | # Delete by space: 47 | usage=$(du -sb "${dataDir}/${name}" | cut -d ''$'\t' -f 1) 48 | limit=$(( ${builtins.toString value.limitMebibytes} * 1024 * 1024)) 49 | if [ $usage -gt $limit ]; then 50 | find "${dataDir}/${name}" -type f -printf '%T@\t%s\t%p\n' | \ 51 | sort -n | \ 52 | while [ $usage -gt $limit ] && IFS=''$'\t' read timestamp size file; do 53 | rm -- "$file" && usage=$(( $usage - $size )) 54 | done 55 | fi 56 | ''; 57 | in 58 | { 59 | options.services.motion = { 60 | 61 | enable = mkOption { 62 | type = types.bool; 63 | default = false; 64 | description = '' 65 | Whether to enable running Motion, the (security) camera monitoring software. 66 | ''; 67 | }; 68 | 69 | instances = mkOption { 70 | type = types.attrsOf (types.submodule { 71 | options = { 72 | configText = mkOption { 73 | type = types.lines; 74 | default = ""; 75 | description = '' 76 | The contents of motion.conf for this instance. 77 | Note that NixOS injects a 'target_dir 78 | ${dataDir}/INSTANCE_NAME' directive at the end of configText. 79 | ''; 80 | }; 81 | extraOpts = mkOption { 82 | type = types.listOf types.str; 83 | default = [ ]; 84 | example = [ "-d" "7" /* INFO loglevel */ ]; 85 | description = '' 86 | List of extra command line options to pass to this motion instance. 87 | ''; 88 | }; 89 | limitDays = mkOption { 90 | type = types.int; 91 | default = 14; 92 | description = '' 93 | Files older than this will be deleted. Deletion happens every night, 94 | or on the next boot, if the machine is powered off at midnight. 95 | ''; 96 | }; 97 | limitMebibytes = mkOption { 98 | type = types.int; 99 | default = 10 * 1024; 100 | description = '' 101 | If the video/image output directory is bigger than this, old 102 | files will be deleted until below this size. Deletion happens 103 | every night, or on the next boot, if the machine is powered off 104 | at midnight. 105 | ''; 106 | }; 107 | }; 108 | }); 109 | default = {}; 110 | description = '' 111 | Definition of motion instances. 112 | ''; 113 | }; 114 | 115 | }; 116 | 117 | config = mkIf cfg.enable { 118 | systemd.services = 119 | { motion-setup = { 120 | description = "Setup Motion Camera Monitor"; 121 | wantedBy = [ "multi-user.target" ]; 122 | script = '' 123 | mkdir -p "${dataDir}" 124 | chown ${motionUser}:${motionGroup} "${dataDir}" 125 | 126 | # Create /var/lib/motion/NAME directory for each instance (must run as root) 127 | ${concatMapStrings (x: "mkdir -p \"${dataDir}/${x}\"") (builtins.attrNames cfg.instances)} 128 | for dir in "${dataDir}/"*; do 129 | test -d "$dir" || continue 130 | chown ${motionUser}:${motionGroup} "$dir" 131 | done 132 | ''; 133 | # Run as root 134 | serviceConfig.UMask = umask; 135 | }; 136 | 137 | motion-gc = { 138 | description = "Garbage Collect Motion Camera Files"; 139 | startAt = "daily"; 140 | script = '' 141 | ${concatStringsSep "\n\n" (mapAttrsToList createGarbageCollectScript cfg.instances)} 142 | ''; 143 | serviceConfig.User = motionUser; 144 | serviceConfig.Group = motionGroup; 145 | serviceConfig.UMask = umask; 146 | }; 147 | } // (mapAttrs' createServiceInstance cfg.instances); 148 | 149 | systemd.timers.motion-gc = { 150 | timerConfig.Persistent = true; 151 | }; 152 | 153 | # Create a target unit to allow easy start stop of all motion instances. 154 | systemd.targets.motion = { 155 | description = "Motion Camera Monitor"; 156 | wantedBy = [ "multi-user.target" ]; 157 | }; 158 | 159 | users.extraUsers."${motionUser}" = { 160 | group = motionGroup; 161 | description = "Motion Camera User"; 162 | uid = motionUid; 163 | extraGroups = [ "video" ]; 164 | }; 165 | 166 | users.extraGroups."${motionGroup}".gid = motionGid; 167 | 168 | }; 169 | } 170 | -------------------------------------------------------------------------------- /options/nextcloud.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.services.lighttpd.nextcloud; 7 | phpfpmSocketName = config.services.phpfpm.pools.nextcloud.socket; 8 | in 9 | { 10 | options.services.lighttpd.nextcloud = { 11 | 12 | enable = mkEnableOption "Nextcloud in lighttpd"; 13 | 14 | package = mkOption { 15 | type = types.package; 16 | default = pkgs.fetchzip { 17 | url = "https://download.nextcloud.com/server/releases/nextcloud-17.0.6.zip"; 18 | sha256 = "10g9rybqk2ih43bp29s73bc75j28n96ra49b0dl43503fwgy0np5"; 19 | }; 20 | description = "Nextcloud package to use."; 21 | }; 22 | 23 | installPrefix = mkOption { 24 | type = types.path; 25 | default = "/var/lib/nextcloud"; 26 | description = '' 27 | Where to install Nextcloud. By default, user files will be placed in 28 | the data/ directory below the directory. 29 | ''; 30 | }; 31 | 32 | urlPrefix = mkOption { 33 | type = types.str; 34 | default = "/nextcloud"; 35 | example = "/"; 36 | description = '' 37 | The prefix below the web server root URL to serve Nextcloud. 38 | ''; 39 | }; 40 | 41 | vhostsPattern = mkOption { 42 | type = types.str; 43 | default = ".*"; 44 | example = "(myserver1.example|myserver2.example)"; 45 | description = '' 46 | A virtual host regexp filter. Change it if you want Nextcloud to only 47 | be served from some host names, instead of all. 48 | ''; 49 | }; 50 | 51 | }; 52 | 53 | config = mkIf (config.services.lighttpd.enable && cfg.enable) { 54 | 55 | systemd.services.lighttpd.preStart = 56 | '' 57 | echo "Setting up Nextcloud in ${cfg.installPrefix}/" 58 | ${pkgs.rsync}/bin/rsync -a --checksum "${cfg.package}/" "${cfg.installPrefix}/" 59 | 60 | mkdir -p "${cfg.installPrefix}/data" 61 | chown -R lighttpd:lighttpd "${cfg.installPrefix}" 62 | chmod 775 "${cfg.installPrefix}" 63 | chmod 770 "${cfg.installPrefix}/data" 64 | chmod 770 "${cfg.installPrefix}/apps" 65 | chmod 770 "${cfg.installPrefix}/config" 66 | chmod 660 "${cfg.installPrefix}/.user.ini" 67 | chmod 660 "${cfg.installPrefix}/.htaccess" 68 | ''; 69 | 70 | services.lighttpd = { 71 | enableModules = [ "mod_alias" "mod_fastcgi" "mod_access" "mod_setenv" ]; 72 | extraConfig = '' 73 | $HTTP["host"] =~ "${cfg.vhostsPattern}" { 74 | alias.url += ( "${cfg.urlPrefix}" => "${cfg.installPrefix}/" ) 75 | # Prevent direct access to the data directory, like nextcloud warns 76 | # about in its admin interface "Security & setup warnings". 77 | $HTTP["url"] =~ "^${cfg.urlPrefix}/data" { 78 | url.access-deny = ("") 79 | } 80 | $HTTP["url"] =~ "^${cfg.urlPrefix}" { 81 | fastcgi.server = ( 82 | ".php" => ( 83 | "phpfpm-nextcloud" => ( 84 | "socket" => "${phpfpmSocketName}", 85 | ) 86 | ) 87 | ) 88 | } 89 | # Recommended setting (Nextcloud warns about this in the admin interface) 90 | $HTTP["scheme"] == "https" { 91 | setenv.add-response-header += ( 92 | "Strict-Transport-Security" => "max-age=15552000; includeSubDomains; preload" 93 | ) 94 | } 95 | } 96 | ''; 97 | }; 98 | 99 | services.phpfpm.pools = { 100 | nextcloud = { 101 | user = "lighttpd"; 102 | group = "lighttpd"; 103 | settings = { 104 | "listen.owner" = "lighttpd"; 105 | "listen.group" = "lighttpd"; 106 | "pm" = "dynamic"; 107 | "pm.max_children" = 75; 108 | "pm.start_servers" = 10; 109 | "pm.min_spare_servers" = 5; 110 | "pm.max_spare_servers" = 20; 111 | "pm.max_requests" = 500; 112 | }; 113 | }; 114 | }; 115 | 116 | }; 117 | 118 | } 119 | -------------------------------------------------------------------------------- /options/pia/pia-generated-server-list.nix: -------------------------------------------------------------------------------- 1 | # Generated by /etc/nixos/options/pia/pia-server-list-generator.sh 2 | 3 | [ 4 | { id = "PIA - Mexico"; 5 | uuid = "4b1ccfa9-3457-5ea4-824a-0d86d78f40e9"; 6 | remote = "mexico.privateinternetaccess.com"; 7 | } 8 | { id = "PIA - CA Toronto"; 9 | uuid = "80a635f8-df93-56f2-a570-65899ba599bb"; 10 | remote = "ca-toronto.privateinternetaccess.com"; 11 | } 12 | { id = "PIA - CA Montreal"; 13 | uuid = "94380df4-dd68-5446-8ce2-c0a7e6d60c49"; 14 | remote = "ca.privateinternetaccess.com"; 15 | } 16 | { id = "PIA - India"; 17 | uuid = "48e0ff64-2a90-516c-956a-31d0c27be403"; 18 | remote = "in.privateinternetaccess.com"; 19 | } 20 | { id = "PIA - US Florida"; 21 | uuid = "f7c94a50-de0e-5eab-9dd0-25b9ba02fef0"; 22 | remote = "us-florida.privateinternetaccess.com"; 23 | } 24 | { id = "PIA - UK Southampton"; 25 | uuid = "2575a50f-42fe-569f-9045-42643143f922"; 26 | remote = "uk-southampton.privateinternetaccess.com"; 27 | } 28 | { id = "PIA - Japan"; 29 | uuid = "632ed90a-bf6a-555f-a556-de63e62bdca7"; 30 | remote = "japan.privateinternetaccess.com"; 31 | } 32 | { id = "PIA - Turkey"; 33 | uuid = "e2349345-5e54-54ca-a641-a08fc45c59b4"; 34 | remote = "turkey.privateinternetaccess.com"; 35 | } 36 | { id = "PIA - Netherlands"; 37 | uuid = "d2a54487-3987-56a3-bdb7-688635876001"; 38 | remote = "nl.privateinternetaccess.com"; 39 | } 40 | { id = "PIA - Norway"; 41 | uuid = "94ed319f-8dcc-5c35-abc2-d1c0df8f267a"; 42 | remote = "no.privateinternetaccess.com"; 43 | } 44 | { id = "PIA - AU Melbourne"; 45 | uuid = "f8637490-de9e-5a76-94dd-6b40b6d1dbe9"; 46 | remote = "aus-melbourne.privateinternetaccess.com"; 47 | } 48 | { id = "PIA - New Zealand"; 49 | uuid = "13aaa4db-f761-57d3-99de-2582f860efdb"; 50 | remote = "nz.privateinternetaccess.com"; 51 | } 52 | { id = "PIA - France"; 53 | uuid = "ad239203-0b0e-5649-b8e6-57427d738eb8"; 54 | remote = "france.privateinternetaccess.com"; 55 | } 56 | { id = "PIA - AU Sydney"; 57 | uuid = "1be63659-00c4-5e82-bd7e-0243af558ee3"; 58 | remote = "aus.privateinternetaccess.com"; 59 | } 60 | { id = "PIA - Ireland"; 61 | uuid = "c8d2d518-57e1-5e27-948f-3fe73b0eb400"; 62 | remote = "ireland.privateinternetaccess.com"; 63 | } 64 | { id = "PIA - Romania"; 65 | uuid = "4d375e8d-b950-5d95-93ea-f854e0c48f61"; 66 | remote = "ro.privateinternetaccess.com"; 67 | } 68 | { id = "PIA - Brazil"; 69 | uuid = "f9db3ea9-d0ba-580d-91e0-7a21f2b6f6a9"; 70 | remote = "brazil.privateinternetaccess.com"; 71 | } 72 | { id = "PIA - Israel"; 73 | uuid = "afc147bb-ae90-5922-8162-e0276ea85760"; 74 | remote = "israel.privateinternetaccess.com"; 75 | } 76 | { id = "PIA - US Midwest"; 77 | uuid = "9ab0eef6-3e3a-5cd8-936b-2518e28ef9b6"; 78 | remote = "us-midwest.privateinternetaccess.com"; 79 | } 80 | { id = "PIA - US California"; 81 | uuid = "37ac009c-5cc0-5cfc-a2ec-f067c7e0b212"; 82 | remote = "us-california.privateinternetaccess.com"; 83 | } 84 | { id = "PIA - Hong Kong"; 85 | uuid = "708d716c-923f-55d7-bd0f-aced817bb589"; 86 | remote = "hk.privateinternetaccess.com"; 87 | } 88 | { id = "PIA - Germany"; 89 | uuid = "b744d855-d4cc-52b9-aa24-9bee159c0109"; 90 | remote = "germany.privateinternetaccess.com"; 91 | } 92 | { id = "PIA - Finland"; 93 | uuid = "51829104-98b9-5649-850b-37eb33e21f3a"; 94 | remote = "fi.privateinternetaccess.com"; 95 | } 96 | { id = "PIA - US Chicago"; 97 | uuid = "8cf137b6-bea8-5d2b-9687-b0976b8a5341"; 98 | remote = "us-chicago.privateinternetaccess.com"; 99 | } 100 | { id = "PIA - US Silicon Valley"; 101 | uuid = "7f261a73-9487-5d7f-95ee-cb798a2dc904"; 102 | remote = "us-siliconvalley.privateinternetaccess.com"; 103 | } 104 | { id = "PIA - US New York City"; 105 | uuid = "9e3f0be2-87eb-5352-a321-23d22bf0d85e"; 106 | remote = "us-newyorkcity.privateinternetaccess.com"; 107 | } 108 | { id = "PIA - US Texas"; 109 | uuid = "0b5cb308-1d16-56ad-830c-6253b475f4df"; 110 | remote = "us-texas.privateinternetaccess.com"; 111 | } 112 | { id = "PIA - Italy"; 113 | uuid = "b25088c7-3746-5d1d-92c0-79799f5ff80c"; 114 | remote = "italy.privateinternetaccess.com"; 115 | } 116 | { id = "PIA - South Korea"; 117 | uuid = "e914f6a5-3b19-58a2-bd39-bdf3ea36f343"; 118 | remote = "kr.privateinternetaccess.com"; 119 | } 120 | { id = "PIA - Sweden"; 121 | uuid = "c24581b8-69a1-5fd0-9100-56f5f5010944"; 122 | remote = "sweden.privateinternetaccess.com"; 123 | } 124 | { id = "PIA - US West"; 125 | uuid = "c881ad44-b2b6-51d2-b7e3-373b680554c2"; 126 | remote = "us-west.privateinternetaccess.com"; 127 | } 128 | { id = "PIA - US East"; 129 | uuid = "37a27719-7ebd-500a-9a7b-4daa017bb27d"; 130 | remote = "us-east.privateinternetaccess.com"; 131 | } 132 | { id = "PIA - UK London"; 133 | uuid = "1bbd385a-6d03-5661-9871-bca00b9cf66f"; 134 | remote = "uk-london.privateinternetaccess.com"; 135 | } 136 | { id = "PIA - Denmark"; 137 | uuid = "5a5703fc-b960-516a-a786-9b59200ee52f"; 138 | remote = "denmark.privateinternetaccess.com"; 139 | } 140 | { id = "PIA - Switzerland"; 141 | uuid = "961a068b-71a0-5440-aa43-0f63e443cf34"; 142 | remote = "swiss.privateinternetaccess.com"; 143 | } 144 | { id = "PIA - US Seattle"; 145 | uuid = "be257767-864c-560a-8b30-b66c3270a312"; 146 | remote = "us-seattle.privateinternetaccess.com"; 147 | } 148 | { id = "PIA - Singapore"; 149 | uuid = "a92761e1-d0b1-5630-98b5-6b5f225d364a"; 150 | remote = "sg.privateinternetaccess.com"; 151 | } 152 | ] -------------------------------------------------------------------------------- /options/pia/pia-nm.nix: -------------------------------------------------------------------------------- 1 | # NixOS Module for Private Internet Access (VPN) support in NetworkManager. 2 | 3 | { config, lib, pkgs, ... }: 4 | 5 | with lib; 6 | 7 | let 8 | cfg = config.networking.networkmanager.pia-vpn; 9 | 10 | piaCertificateFile = pkgs.fetchurl { 11 | url = "https://www.privateinternetaccess.com/openvpn/ca.rsa.4096.crt"; 12 | sha256 = "1av6dilvm696h7pb5xn91ibw0mrziqsnwk51y8a7da9y8g8v3s9j"; 13 | }; 14 | 15 | # id: human facing name of the connection (visible in NetworkManager) 16 | # uuid: any UUID in the form produced by uuid(1) (or perhaps _any_ string?) 17 | # remote: hostname of PIAs server (e.g. "uk-london.privateinternetaccess.com") 18 | # 19 | # See https://www.privateinternetaccess.com/installer/pia-nm.sh for available 20 | # options. 21 | template = { id, uuid, remote }: 22 | '' 23 | [connection] 24 | id=${id} 25 | uuid=${uuid} 26 | type=vpn 27 | autoconnect=false 28 | 29 | [vpn] 30 | service-type=org.freedesktop.NetworkManager.openvpn 31 | username=${if cfg.username != "" then cfg.username else "@USERNAME@"} 32 | comp-lzo=yes 33 | remote=${remote} 34 | cipher=AES-256-CBC 35 | auth=SHA256 36 | connection-type=password 37 | password-flags=${if cfg.password != "" || cfg.passwordFile != null then "0" else "1"} 38 | port=1197 39 | proto-tcp=no 40 | ca=${piaCertificateFile} 41 | 42 | [ipv4] 43 | method=auto 44 | ${lib.optionalString (cfg.password != "" || cfg.passwordFile != null) '' 45 | 46 | [vpn-secrets] 47 | password=${if cfg.password != "" then cfg.password else "@PASSWORD@"} 48 | ''} 49 | ''; 50 | 51 | toSubdomain = server: 52 | lib.removeSuffix ".privateinternetaccess.com" server; 53 | 54 | # File generated by ./pia-server-list-generator.sh 55 | allServers = import ./pia-generated-server-list.nix; 56 | 57 | filteredServers = 58 | builtins.filter (x: lib.elem (toSubdomain x.remote) cfg.serverList) allServers; 59 | 60 | allServerSubdomains = 61 | map (x: toSubdomain x.remote) allServers; 62 | 63 | serverEntryToEtcFilename = serverEntry: 64 | let n = toSubdomain serverEntry.remote; 65 | in "NetworkManager/system-connections/pia-vpn-${n}"; 66 | 67 | serverEntryToEtcFile = serverEntry: 68 | 69 | { "${serverEntryToEtcFilename serverEntry}" = 70 | { text = template { inherit (serverEntry) id uuid remote; }; 71 | # NetworkManager refuses to load world readable files 72 | mode = "0600"; 73 | }; 74 | }; 75 | 76 | etcFiles = 77 | lib.fold 78 | (x: acc: lib.recursiveUpdate (serverEntryToEtcFile x) acc) 79 | {} 80 | filteredServers; 81 | in 82 | { 83 | options.networking.networkmanager.pia-vpn = { 84 | 85 | enable = mkOption { 86 | type = types.bool; 87 | default = false; 88 | description = '' 89 | Whether to enable Private Internet Access VPN connections in NetworkManager. 90 | 91 | To make NetworkManager update its UI after using this module to 92 | add/remove connections, you either have to run 93 | `sudo nmcli connection reload` or reboot. 94 | ''; 95 | }; 96 | 97 | username = mkOption { 98 | type = types.str; 99 | default = ""; 100 | description = '' 101 | Your PIA username. If you don't want your username to be world readable 102 | in the Nix store, use the usernameFile option. The password for this 103 | username is either entered interactively when starting the connection 104 | for the first time (the password is stored in the OS keyring) or you can use 105 | the password or passwordFile options. 106 | 107 | Warning: The username is world readable in the Nix store. 108 | ''; 109 | }; 110 | 111 | usernameFile = mkOption { 112 | type = types.nullOr types.path; 113 | default = null; 114 | example = "/run/keys/pia-vpn.username"; 115 | description = '' 116 | Path to a file containing your PIA username. (To not leak username to 117 | the Nix store.) The username will be copied into the file(s) 118 | /etc/NetworkManager/system-connections/pia-vpn-*. 119 | ''; 120 | }; 121 | 122 | password = mkOption { 123 | type = types.str; 124 | default = ""; 125 | description = '' 126 | Your PIA password (optional). If null, NetworkManager will prompt for 127 | the password when enabling the connection. That password will then be 128 | stored in the OS keyring. If non-null, the password will be stored, in 129 | plain text, in the file(s) 130 | /etc/NetworkManager/system-connections/pia-vpn-*. 131 | 132 | Warning: If this option is used (i.e. non-null), it stores the password 133 | in world readable Nix store, in addition to a file under 134 | /etc/NetworkManager/system-connections/. See passwordFile option as an 135 | alternative that doesn't leak password info to the Nix store. 136 | ''; 137 | }; 138 | 139 | passwordFile = mkOption { 140 | type = types.nullOr types.path; 141 | default = null; 142 | example = "/run/keys/pia-vpn.password"; 143 | description = '' 144 | Path to a file containing your PIA password (optional). If neither this 145 | nor the password option is defined, NetworkManager will prompt for 146 | the password when enabling the connection. That password will then be 147 | stored in the OS keyring. If non-null, the password in this file will 148 | be embedded (in plain text) into the file(s) 149 | /etc/NetworkManager/system-connections/pia-vpn-*. 150 | 151 | This option doesn't leak the password to the Nix store. 152 | ''; 153 | }; 154 | 155 | serverList = mkOption { 156 | type = types.listOf types.str; 157 | default = allServerSubdomains; 158 | description = '' 159 | List of PIA VPN servers that will be available for use. If you only use 160 | a few servers you can reduce some UI clutter by listing only those 161 | servers here. 162 | ''; 163 | }; 164 | 165 | }; 166 | 167 | config = mkIf cfg.enable { 168 | 169 | assertions = [ 170 | { assertion = cfg.username != "" || cfg.usernameFile != null; 171 | message = "Either networking.networkmanager.pia-vpn.username or ..usernameFile must be set."; 172 | } 173 | { assertion = (cfg.username != "") == (cfg.usernameFile == null); 174 | message = "Only one of networking.networkmanager.pia-vpn.username and ..usernameFile can be set."; 175 | } 176 | { # Password can be unset, NetworkManager will use OS keyring. 177 | assertion = if cfg.password != "" then (cfg.passwordFile == null) else true; 178 | message = "Only one of networking.networkmanager.pia-vpn.password and ..passwordFile can be set."; 179 | } 180 | { assertion = (lib.length cfg.serverList) > 0; 181 | message = "The option networking.networkmanager.pia-vpn.serverList is empty, no VPN connections can be made."; 182 | } 183 | { assertion = all (x: elem x allServerSubdomains) cfg.serverList; 184 | message = 185 | let 186 | badElements = builtins.filter (x: !(lib.elem x allServerSubdomains)) cfg.serverList; 187 | in 188 | '' 189 | The option networking.networkmanager.pia-vpn.serverList contains one or more bad elements: ${builtins.toString badElements} 190 | Allowed elements: ${builtins.toString allServerSubdomains} 191 | ''; 192 | } 193 | ]; 194 | 195 | environment.etc = etcFiles; 196 | 197 | system.activationScripts.pia-nm-usernameFile = lib.mkIf (cfg.usernameFile != null) (stringAfter [ "etc" "specialfs" "var" ] 198 | '' 199 | if [ -f "${cfg.usernameFile}" ]; then 200 | ${pkgs.systemd}/bin/systemd-cat -t nixos echo "<6>loading networking.networkmanager.pia-vpn.usernameFile from ${cfg.usernameFile}" 201 | ${lib.concatMapStringsSep "\n" 202 | (f: "${pkgs.gnused}/bin/sed -ie \"s/@USERNAME@/$(< ${cfg.usernameFile})/\" ${f}") 203 | (map (s: "/etc/${serverEntryToEtcFilename s}") filteredServers)} 204 | else 205 | msg="WARNING: networking.networkmanager.pia-vpn.usernameFile (${cfg.usernameFile}) does not exist." 206 | echo "$msg" 207 | ${pkgs.systemd}/bin/systemd-cat -t nixos echo "<4>$msg" 208 | fi 209 | ''); 210 | 211 | system.activationScripts.pia-nm-passwordFile = lib.mkIf (cfg.passwordFile != null) (stringAfter [ "etc" "specialfs" "var" ] 212 | '' 213 | if [ -f "${cfg.passwordFile}" ]; then 214 | ${pkgs.systemd}/bin/systemd-cat -t nixos echo "<6>loading networking.networkmanager.pia-vpn.passwordFile from ${cfg.passwordFile}" 215 | ${lib.concatMapStringsSep "\n" 216 | (f: "${pkgs.gnused}/bin/sed -ie \"s/@PASSWORD@/$(< ${cfg.passwordFile})/\" ${f}") 217 | (map (s: "/etc/${serverEntryToEtcFilename s}") filteredServers)} 218 | else 219 | msg="WARNING: networking.networkmanager.pia-vpn.passwordFile (${cfg.passwordFile}) does not exist." 220 | echo "$msg" 221 | ${pkgs.systemd}/bin/systemd-cat -t nixos echo "<4>$msg" 222 | fi 223 | ''); 224 | }; 225 | 226 | } 227 | -------------------------------------------------------------------------------- /options/pia/pia-server-list-generator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | # Generate list of PIA VPN servers for NixOS module. 4 | # Inspired by the pia-nm.sh[1] script. 5 | # 6 | # [1] https://www.privateinternetaccess.com/installer/pia-nm.sh 7 | 8 | set -e 9 | 10 | error() { 11 | echo "$@" >&2 12 | exit 1 13 | } 14 | 15 | thisfile=$(readlink -f -- "$0") 16 | thisdir=$(dirname "$thisfile") 17 | outputfile="$thisdir/pia-generated-server-list.nix" 18 | IFS=$(echo) 19 | servers=$(curl -Ss "https://www.privateinternetaccess.com/vpninfo/servers?version=24" | head -1) 20 | 21 | if [ -z "$servers" ]; then 22 | error "Failed to download server list, aborting." 23 | fi 24 | 25 | servers=$(python2.7 < "$outputfile" 37 | printf "[\n" >> "$outputfile" 38 | echo "$servers" | while read server; do 39 | name="PIA - "$(echo "$server" | cut -d: -f2) 40 | host=$(echo "$server" | cut -d: -f1) 41 | 42 | cat <> "$outputfile" 43 | { id = "$name"; 44 | uuid = "$(uuid -v 5 ns:URL "$name-$host")"; 45 | remote = "$host"; 46 | } 47 | EOF 48 | done 49 | printf "]" >> "$outputfile" 50 | 51 | echo "Generated $(echo "$servers" | wc -l) server entries in $outputfile" 52 | -------------------------------------------------------------------------------- /options/resources.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | options.local = { 5 | resources = lib.mkOption { 6 | type = lib.types.attrs; 7 | default = {}; 8 | description = "Arbitrary shared resources to pass around in the NixOS configuration."; 9 | }; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /pkgs/altera-quartus/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, utillinux, file, bash, glibc, pkgsi686Linux, writeScript 2 | , nukeReferences, glibcLocales, libfaketime, coreutils, gnugrep, gnused, proot 3 | # Runtime libraries: 4 | , zlib, glib, libpng12, freetype, libSM, libICE, libXrender, fontconfig 5 | , libXext, libX11, libXtst, gtk2, bzip2, libelf 6 | }: 7 | 8 | let 9 | 10 | sources = import ./sources.nix { inherit fetchurl; }; 11 | 12 | buildQuartus = import ./generic.nix { 13 | inherit 14 | stdenv fetchurl utillinux file bash glibc pkgsi686Linux writeScript 15 | nukeReferences glibcLocales libfaketime coreutils gnugrep gnused proot 16 | # Runtime libraries: 17 | zlib glib libpng12 freetype libSM libICE libXrender fontconfig 18 | libXext libX11 libXtst gtk2 bzip2 libelf; 19 | }; 20 | 21 | mkCommonQuartus = srcAttrs: 22 | buildQuartus { 23 | inherit (srcAttrs) baseName prettyName is32bitPackage; 24 | version = srcAttrs.updates.version; 25 | components = with srcAttrs.components; [ 26 | quartus cyclonev 27 | ]; 28 | updateComponents = with srcAttrs.updates.components; [ 29 | quartus 30 | ]; 31 | }; 32 | 33 | in rec { 34 | 35 | inherit sources; 36 | 37 | altera-quartus-ii-web-13 = 38 | mkCommonQuartus sources.v13.web_edition; 39 | 40 | altera-quartus-ii-subscription-13 = 41 | mkCommonQuartus sources.v13.subscription_edition; 42 | 43 | altera-quartus-ii-web-14 = 44 | mkCommonQuartus sources.v14.web_edition; 45 | 46 | altera-quartus-ii-subscription-14 = 47 | mkCommonQuartus sources.v14.subscription_edition; 48 | 49 | altera-quartus-prime-lite-15 = 50 | mkCommonQuartus sources.v15.lite_edition; 51 | 52 | altera-quartus-prime-standard-15 = 53 | mkCommonQuartus sources.v15.standard_edition; 54 | 55 | altera-quartus-prime-lite-16 = 56 | mkCommonQuartus sources.v16.lite_edition; 57 | 58 | altera-quartus-prime-standard-16 = 59 | mkCommonQuartus sources.v16.standard_edition; 60 | 61 | altera-quartus-prime-lite-17 = 62 | mkCommonQuartus sources.v17.lite_edition; 63 | 64 | altera-quartus-prime-standard-17 = 65 | mkCommonQuartus sources.v17.standard_edition; 66 | 67 | # Aliases to latest versions 68 | altera-quartus-prime-lite = altera-quartus-prime-lite-17; 69 | altera-quartus-prime-standard = altera-quartus-prime-standard-17; 70 | 71 | } 72 | -------------------------------------------------------------------------------- /pkgs/altera-quartus/patches/glibc/0001-Avoid-.symver-on-common-symbols-BZ-21666.patch: -------------------------------------------------------------------------------- 1 | From 388b4f1a02f3a801965028bbfcd48d905638b797 Mon Sep 17 00:00:00 2001 2 | From: "H.J. Lu" 3 | Date: Fri, 23 Jun 2017 14:38:46 -0700 4 | Subject: [PATCH] Avoid .symver on common symbols [BZ #21666] 5 | 6 | The .symver directive on common symbol just creates a new common symbol, 7 | not an alias and the newer assembler with the bug fix for 8 | 9 | https://sourceware.org/bugzilla/show_bug.cgi?id=21661 10 | 11 | will issue an error. Before the fix, we got 12 | 13 | $ readelf -sW libc.so | grep "loc[12s]" 14 | 5109: 00000000003a0608 8 OBJECT LOCAL DEFAULT 36 loc1 15 | 5188: 00000000003a0610 8 OBJECT LOCAL DEFAULT 36 loc2 16 | 5455: 00000000003a0618 8 OBJECT LOCAL DEFAULT 36 locs 17 | 6575: 00000000003a05f0 8 OBJECT GLOBAL DEFAULT 36 locs@GLIBC_2.2.5 18 | 7156: 00000000003a05f8 8 OBJECT GLOBAL DEFAULT 36 loc1@GLIBC_2.2.5 19 | 7312: 00000000003a0600 8 OBJECT GLOBAL DEFAULT 36 loc2@GLIBC_2.2.5 20 | 21 | in libc.so. The versioned loc1, loc2 and locs have the wrong addresses. 22 | After the fix, we got 23 | 24 | $ readelf -sW libc.so | grep "loc[12s]" 25 | 6570: 000000000039e3b8 8 OBJECT GLOBAL DEFAULT 34 locs@GLIBC_2.2.5 26 | 7151: 000000000039e3c8 8 OBJECT GLOBAL DEFAULT 34 loc1@GLIBC_2.2.5 27 | 7307: 000000000039e3c0 8 OBJECT GLOBAL DEFAULT 34 loc2@GLIBC_2.2.5 28 | 29 | [BZ #21666] 30 | * misc/regexp.c (loc1): Add __attribute__ ((nocommon)); 31 | (loc2): Likewise. 32 | (locs): Likewise. 33 | --- 34 | ChangeLog | 7 +++++++ 35 | misc/regexp.c | 9 +++++---- 36 | 2 files changed, 12 insertions(+), 4 deletions(-) 37 | 38 | [Bjørn Forsman: remove the ChangeLog hunk to ease backporting.] 39 | 40 | diff --git a/misc/regexp.c b/misc/regexp.c 41 | index 19d76c0c37..eaea7c3b89 100644 42 | --- a/misc/regexp.c 43 | +++ b/misc/regexp.c 44 | @@ -29,14 +29,15 @@ 45 | 46 | #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23) 47 | 48 | -/* Define the variables used for the interface. */ 49 | -char *loc1; 50 | -char *loc2; 51 | +/* Define the variables used for the interface. Avoid .symver on common 52 | + symbol, which just creates a new common symbol, not an alias. */ 53 | +char *loc1 __attribute__ ((nocommon)); 54 | +char *loc2 __attribute__ ((nocommon)); 55 | compat_symbol (libc, loc1, loc1, GLIBC_2_0); 56 | compat_symbol (libc, loc2, loc2, GLIBC_2_0); 57 | 58 | /* Although we do not support the use we define this variable as well. */ 59 | -char *locs; 60 | +char *locs __attribute__ ((nocommon)); 61 | compat_symbol (libc, locs, locs, GLIBC_2_0); 62 | 63 | 64 | -- 65 | 2.19.2 66 | 67 | -------------------------------------------------------------------------------- /pkgs/custom-desktop-entries/default.nix: -------------------------------------------------------------------------------- 1 | { lib, fetchurl, makeDesktopItem, pkgs }: 2 | 3 | # StartupWMClass is found with `xprop WM_CLASS`. When multiple entries are 4 | # returned, use the first one (most specific). (Ideally, all values could be 5 | # used, for most precise match, but I haven't found a way to do so.) 6 | 7 | let 8 | localLib = import ../../lib/default.nix { inherit pkgs; }; 9 | 10 | makeSimpleWebApp = localLib.makeSimpleWebApp; 11 | 12 | entries = { 13 | 14 | tv-get-no = makeSimpleWebApp { 15 | server = "tv.get.no"; 16 | # Chromium fails with 17 | # This video file cannot be played. 18 | # (Error Code: 102630) 19 | # so use google-chrome instead. 20 | browser = "google-chrome-stable"; 21 | icon = fetchurl { 22 | name = "get-nett-tv-favicon.png"; 23 | url = "https://tv.get.no/favicon.png"; 24 | sha256 = "0acrlix5qmnb32zaqcch0khb6s7ajrw4qv5ikx33bpf71mimkc94"; 25 | }; 26 | comment = "Get Nett-TV"; 27 | }; 28 | 29 | gmail = makeSimpleWebApp { 30 | server = "mail.google.com"; 31 | icon = fetchurl { 32 | url = "https://upload.wikimedia.org/wikipedia/commons/a/ab/Gmail_Icon.svg"; 33 | sha256 = "1avrc2laqmviih3gx4pkxrd7v2hkcgp48c7zcb1wmxbnxvcqxgqr"; 34 | }; 35 | comment = "GMail"; 36 | }; 37 | 38 | netflix = makeSimpleWebApp { 39 | server = "www.netflix.com"; 40 | # It's a pain to maintain widewine for Chromium (slow to build, breaks), so 41 | # use google-chrome for netflix. 42 | browser = "google-chrome-stable"; 43 | icon = fetchurl { 44 | url = "http://www.iconarchive.com/download/i106070/papirus-team/papirus-apps/netflix.svg"; 45 | sha256 = "06n3crmfc3k8yahybic399p832vzj5afrdqvlizrk8lbk3plrjd2"; 46 | }; 47 | comment = "Netflix"; 48 | }; 49 | 50 | tv-nrk-no = makeSimpleWebApp { 51 | server = "tv.nrk.no"; 52 | icon = fetchurl { 53 | name = "nrk-tv-logo.png"; 54 | url = "http://mirrors.kodi.tv/addons/leia/plugin.video.nrk/icon.png"; 55 | sha256 = "0a0cn831qcn1wn2zqrgjhw3q3ch9li7fqgazvcii4a8gcrvcc3sm"; 56 | }; 57 | comment = "NRK TV"; 58 | }; 59 | 60 | sbanken = makeSimpleWebApp { 61 | server = "sbanken.no"; 62 | # icon from google play 63 | # (https://play.google.com/store/apps/details?id=no.skandiabanken) 64 | icon = fetchurl { 65 | name = "sbanken_icon.png"; 66 | url = "https://lh3.googleusercontent.com/qY0PzdGykNPdmbLmHQKGYAesB7CgmXO-bqCJdI957RRMZ57p82BME081WcSgDCH4OSQ=s180"; 67 | sha256 = "1n4mjyhjn3npc785bvb3r0cpwndrzdzq8qq60d93hbgh9y04mdda"; 68 | }; 69 | comment = "Sbanken"; 70 | }; 71 | 72 | youtube = makeSimpleWebApp { 73 | server = "www.youtube.com"; 74 | icon = fetchurl { 75 | url = "https://upload.wikimedia.org/wikipedia/commons/4/40/Youtube_icon.svg"; 76 | sha256 = "0gqnp61pbcsfd34w6r9bjxnpzkrlb0nhwb8z3h2a4xbyawa9dpcq"; 77 | }; 78 | comment = "YouTube"; 79 | }; 80 | 81 | }; 82 | 83 | in 84 | entries 85 | -------------------------------------------------------------------------------- /pkgs/deconz/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, mkDerivation, dpkg, autoPatchelfHook 2 | , qtserialport, qtwebsockets 3 | , libredirect, makeWrapper, gzip, gnutar 4 | }: 5 | 6 | # The default user and password for the WebApp is delight/delight. Hm, it looks 7 | # like the "WebApp" is deprecated, and the new Phoscon App is its replacement 8 | # (the button to the left of the WebApp). The Phoscon App asks to create 9 | # user/password at first startup, instead of hardcoding a default. 10 | 11 | mkDerivation rec { 12 | name = "deconz-${version}"; 13 | version = "2.05.77"; 14 | 15 | src = fetchurl { 16 | url = "https://deconz.dresden-elektronik.de/ubuntu/beta/deconz-${version}-qt5.deb"; 17 | sha256 = "16ssp6rxnqpgl9avdlcaabja05rr3l4xhghbv2l8afv0wcgbj29k"; 18 | }; 19 | 20 | devsrc = fetchurl { 21 | url = "https://deconz.dresden-elektronik.de/ubuntu/beta/deconz-dev-${version}.deb"; 22 | sha256 = "0xav93kd9l8lpaw0fikghmrxfglan85krgh47rjpd7napr648ikg"; 23 | }; 24 | 25 | nativeBuildInputs = [ dpkg autoPatchelfHook makeWrapper ]; 26 | 27 | buildInputs = [ qtserialport qtwebsockets ]; 28 | 29 | unpackPhase = '' 30 | dpkg -x $src ./deconz-src 31 | dpkg -x $devsrc ./deconz-devsrc 32 | ''; 33 | 34 | installPhase = '' 35 | mkdir -p "$out" 36 | cp -r deconz-src/* "$out" 37 | cp -r deconz-devsrc/* "$out" 38 | 39 | # Flatten /usr and manually merge lib/ and usr/lib/, since mv refuses to. 40 | mv "$out/lib" "$out/orig_lib" 41 | mv "$out/usr/"* "$out/" 42 | mv "$out/orig_lib/systemd/system/"* "$out/lib/systemd/system/" 43 | rmdir "$out/orig_lib/systemd/system" 44 | rmdir "$out/orig_lib/systemd" 45 | rmdir "$out/orig_lib" 46 | rmdir "$out/usr" 47 | 48 | # Remove empty directory tree 49 | rmdir "$out/etc/systemd/system" 50 | rmdir "$out/etc/systemd" 51 | rmdir "$out/etc" 52 | 53 | for f in "$out/lib/systemd/system/"*.service \ 54 | "$out/share/applications/"*.desktop; do 55 | substituteInPlace "$f" \ 56 | --replace "/usr/" "$out/" 57 | done 58 | 59 | wrapProgram "$out/bin/deCONZ" \ 60 | --set LD_PRELOAD "${libredirect}/lib/libredirect.so" \ 61 | --set NIX_REDIRECTS "/usr/share=$out/share" \ 62 | --prefix PATH : "${stdenv.lib.makeBinPath [ gzip gnutar ]}" 63 | ''; 64 | 65 | meta = with stdenv.lib; { 66 | description = "Manage ZigBee network with ConBee, ConBee II or RaspBee hardware"; 67 | # 2019-08-19: The homepage links to old software that doesn't even work -- 68 | # it fails to detect ConBee2. 69 | homepage = "https://www.dresden-elektronik.de/funktechnik/products/software/pc-software/deconz/?L=1"; 70 | license = licenses.unfree; 71 | platforms = with platforms; linux; 72 | maintainers = with maintainers; [ bjornfor ]; 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /pkgs/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | { 4 | altera-quartuses = pkgs.callPackage ./altera-quartus { }; 5 | 6 | deconz = pkgs.qt5.callPackage ./deconz {}; 7 | 8 | keil-uvision-c51 = pkgs.callPackage ./keil-uvision-c51 { }; 9 | 10 | ltsa = pkgs.callPackage ./ltsa/default.nix { }; 11 | 12 | roomeqwizard = pkgs.callPackage ./roomeqwizard { }; 13 | 14 | # Things for which I'm the author, or wrappers of upstream projects that 15 | # source custom configs. 16 | my = pkgs.recurseIntoAttrs { 17 | custom-desktop-entries = pkgs.callPackage ./custom-desktop-entries {}; 18 | 19 | git = pkgs.callPackage ./git { }; 20 | 21 | max_perf_pct = pkgs.callPackage ./max_perf_pct { }; 22 | 23 | # Added for completeness' sake. (Most likey a .override is in order to 24 | # customize it appropriately.) 25 | mini-ci = pkgs.callPackage ./mini-ci { }; 26 | 27 | nix-check-before-push = pkgs.callPackage ./nix-check-before-push { }; 28 | 29 | popwk = pkgs.callPackage ./popwk/default.nix {}; 30 | 31 | tmux = pkgs.callPackage ./tmux { }; 32 | 33 | vim = pkgs.callPackage ./vim { }; 34 | }; 35 | 36 | winusb = pkgs.callPackage ./winusb/default.nix { }; 37 | } 38 | -------------------------------------------------------------------------------- /pkgs/git/default.nix: -------------------------------------------------------------------------------- 1 | # Wrapped git with custom gitconfig (no global state). 2 | 3 | { pkgs }: 4 | 5 | let 6 | # There doesn't seem to be a -f path/to/gitconfig option. Workaround: pass 7 | # all options using -c section.key=value. 8 | gitConfig = { 9 | core = { 10 | editor = "vim"; 11 | excludesfile = "~/.gitignore"; 12 | }; 13 | color = { 14 | ui = "auto"; 15 | }; 16 | alias = { 17 | st = "status"; 18 | df = "diff"; 19 | ci = "commit"; 20 | co = "checkout"; 21 | wc = "whatchanged"; 22 | br = "branch"; 23 | f = "fetch"; 24 | a = "add"; 25 | l = "log"; 26 | lga = "log --graph --pretty=oneline --abbrev-commit --decorate --all"; 27 | rup = "remote update -p"; 28 | # Working with github pull-requests: 29 | # - git pullify # just once 30 | # - git fetch 31 | # - git checkout pr/PULL_REQUEST_NUMBER 32 | pullify = "config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*'"; 33 | incoming = "log ..@{u}"; 34 | outgoing = "log @{u}.."; 35 | # "git serve" is from https://gist.github.com/datagrok/5080545 36 | serve = "daemon --verbose --export-all --base-path=.git --reuseaddr --strict-paths .git/"; 37 | suir = "submodule update --init --recursive"; 38 | }; 39 | sendemail = { 40 | # Must be absolute path or else it's interpreted as a hostname. 41 | smtpserver = "${pkgs.msmtp}/bin/msmtp"; 42 | }; 43 | # gitconfig snippet like "[diff "word"]\ntextconv=..." get expressed as 44 | # nested sections like -c diff.word.textconf=... on the command-line. 45 | diff = { 46 | word.textconv = "antiword"; 47 | }; 48 | push = { 49 | default = "simple"; 50 | }; 51 | }; 52 | 53 | argsFromConf = conf: 54 | with pkgs.lib; 55 | let 56 | toArg = path: value: 57 | "-c " + (concatStringsSep "." path) + "=\"${value}\""; 58 | argsInAttrs = 59 | mapAttrsRecursiveCond isAttrs toArg conf; 60 | in 61 | concatStringsSep " \\\n " (collect isString argsInAttrs); 62 | 63 | gitWithConf = pkgs.writeScriptBin "git" '' 64 | #!${pkgs.bash}/bin/bash 65 | exec "${pkgs.gitFull}/bin/git" \ 66 | ${argsFromConf gitConfig} \ 67 | "$@" 68 | ''; 69 | 70 | in 71 | pkgs.symlinkJoin { 72 | name = "${pkgs.gitFull.name}-with-config"; 73 | paths = [ pkgs.gitFull.all ]; 74 | postBuild = '' 75 | rm "$out/bin/git" 76 | cp "${gitWithConf}/bin/git" "$out/bin" 77 | ''; 78 | } 79 | -------------------------------------------------------------------------------- /pkgs/keil-uvision-c51/UV4: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Wine wrapper for Keil uVision. 3 | 4 | WINE_BIN=@wine@/bin/wine 5 | REGEDIT_BIN=@wine@/bin/regedit 6 | MKDIR_BIN=@coreutils@/bin/mkdir 7 | LN_BIN=@coreutils@/bin/ln 8 | RM_BIN=@coreutils@/bin/rm 9 | UV4_EXE=@out@/wine/drive_c/Keil_v5/UV4/UV4.exe 10 | 11 | # UV4.exe tries to run support tools from C:\...: 12 | # 13 | # --- Error: failed to execute 'C:\Keil_v5\C51\BIN\C51.EXE' 14 | # 15 | # Deal with that by creating a link from $WINEPREFIX to the installation files. 16 | 17 | # Use default $WINEPREFIX (~/.wine) 18 | if [ -z "$WINEPREFIX" ]; then 19 | WINEPREFIX="$HOME/.wine" 20 | fi 21 | dest="$WINEPREFIX/drive_c" 22 | dest_link="$dest/Keil_v5" 23 | "$MKDIR_BIN" -p "$dest" || exit 1 24 | "$RM_BIN" -rf "$dest_link" || exit 1 25 | "$LN_BIN" -sf "@out@/wine/drive_c/Keil_v5/" "$dest_link" || exit 1 26 | 27 | # Disable all error messages that Wine usually outputs 28 | export WINEDEBUG=err-all,fixme-all 29 | 30 | # Stop Wine from asking about installing Mono and Gecko packages at startup 31 | export WINEDLLOVERRIDES="mscoree,mshtml=" 32 | 33 | # Optionally import license info 34 | for lic_file in "@out@"/wine/drive_c/Keil_v5/license-info*.reg; do 35 | test -f "$lic_file" || continue 36 | "$REGEDIT_BIN" /C "$lic_file" || exit 1 37 | done 38 | 39 | exec "$WINE_BIN" "$UV4_EXE" "$@" 40 | -------------------------------------------------------------------------------- /pkgs/keil-uvision-c51/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, wine, coreutils }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "keil-uvision-c51-${version}"; 5 | version = "9.56"; # "Help -> About uVision" shows "5.20.0.39" 6 | 7 | # Packaging issues: 8 | # * Installer only available for Windows 9 | # * Installer does not support unattended installs. 10 | # As a workaround we run the installer manually and create a package of the 11 | # resulting files: 12 | # 13 | # mkdir /tmp/wine-keil 14 | # export WINEPREFIX=/tmp/wine-keil 15 | # wine c51v956.exe # run the installer 16 | # # Optional steps, for full version: 17 | # # - If you have an, ehm, "alternate" L51.dll file, copy it over the 18 | # # original now ($WINEPREFIX/drive_c/Keil_v5/C51/BIN/L51.dll). 19 | # # - Start UV4.exe once to populate the registry: 20 | # # $ wine $WINEPREFIX/drive_c/Keil_v5/UV4/UV4.exe 21 | # # - Make backup of registry: 22 | # # $ cp $WINEPREFIX/system.reg{,.1} 23 | # # - Add license (start UV4.exe and go to "File -> License Management", 24 | # # add the license, click "close" for the registry to be written to disk) 25 | # # - Make another backup of the registry: 26 | # # $ cp $WINEPREFIX/system.reg{,.2} 27 | # # - Diff the two registry files to find out which keys should be 28 | # # exported to have working license. If you only added _one_ license, 29 | # # there will be _two_ keys that need to be exported. 30 | # # The registry keys look something like this: 31 | # # "HKEY_LOCAL_MACHINE\\Software\\Classes\\K10.0GACE.K\\CXSID" 32 | # # "HKEY_LOCAL_MACHINE\\Software\\Classes\\{4E50B08E-28CB-44DA-B5B4-EFC45C1EBE6B}" 33 | # # If you added several licenses, you have to export all keys related 34 | # # to the license, or create a .reg file manually based on the 35 | # # diff (export one or two keys with "regedit" first to see what the 36 | # # format looks like -- the input format is slightly different from 37 | # # the format stored in ~/.wine/system.reg!). 38 | # # - Export the keys: 39 | # # $ wine regedit /E $WINEPREFIX/drive_c/Keil_v5/license-info-1.reg "HKEY_LOCAL_MACHINE\\Software\\Classes\\\\CXSID" 40 | # # $ wine regedit /E $WINEPREFIX/drive_c/Keil_v5/license-info-2.reg "HKEY_LOCAL_MACHINE\\Software\\Classes\\{}" 41 | # # The UV4 wrapper script will load all registry files matching 42 | # # "license-info*.reg" pattern in the Keil_v5/ directory. 43 | # (cd $WINEPREFIX/drive_c/ && tar cvJf /tmp/keil-uvision-c51-9.56-preinstalled.tar.xz ./Keil_v5) 44 | # 45 | # [NOTES] 46 | # ---- 47 | # If you want to add a license, you have to do that _before_ creating 48 | # the tarball. Adding a license when the installation files are in the Nix 49 | # store (read-only) will not work. (The license ID is stored in 50 | # $WINEPREFIX/drive_c/Keil_v5/TOOLS.INI). 51 | # 52 | # Instead of exporting the (exact) license keys from the registry, one could 53 | # simply copy the whole system.reg file. However, that would force running 54 | # this program in a separate $WINEPREFIX to not mess with the existing 55 | # registry. 56 | # 57 | # Since we don't preserve the whole registry, we lose some information that 58 | # the installer sets up. For instance, file associations, and wine/windows 59 | # not knowing that this program is "installed". It's a tradeoff. 60 | # ---- 61 | 62 | src = fetchurl { 63 | url = file:///tmp/keil-uvision-c51-9.56-preinstalled.tar.xz; 64 | sha256 = "135d2baa054046fff7fe706ac67509bb701ff8f04e1cb7b1e82fb1e588b0f6dd"; 65 | }; 66 | 67 | buildCommand = '' 68 | mkdir -p "$out/bin" 69 | mkdir -p "$out/wine/drive_c/" 70 | 71 | cp ${./UV4} "$out/bin/UV4" 72 | chmod +x "$out/bin/UV4" 73 | tar xvf "$src" -C "$out/wine/drive_c/" 74 | 75 | substituteInPlace "$out/bin/UV4" \ 76 | --replace @wine@ ${wine} \ 77 | --replace @coreutils@ ${coreutils} \ 78 | --replace @out@ "$out" 79 | ''; 80 | 81 | meta = with stdenv.lib; { 82 | description = "IDE for embedded development"; 83 | license = licenses.unfree; 84 | platforms = [ "x86_64-linux" ]; # only tested this 85 | maintainers = [ maintainers.bjornfor ]; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /pkgs/ltsa/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, unzip, jre, bash }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "ltsa-3.0"; 5 | 6 | src = fetchurl { 7 | # The archive is unfortunately unversioned 8 | url = "http://www.doc.ic.ac.uk/~jnm/book/ltsa/ltsatool.zip"; 9 | sha256 = "0ilhzr2m0k2gas2sr9l5zvw0i2xk6qznx3pllhcy28mfyb299n4y"; 10 | }; 11 | 12 | buildInputs = [ unzip ]; 13 | 14 | phases = [ "installPhase" ]; 15 | 16 | installPhase = '' 17 | unzip "$src" 18 | 19 | mkdir -p "$out/bin" 20 | mkdir -p "$out/lib" 21 | mkdir -p "$out/share/ltsa" 22 | 23 | cd ltsatool 24 | cp *.jar "$out/lib" 25 | cp *.txt "$out/share/ltsa" 26 | cp -r Chapter_examples/ "$out/share/ltsa" 27 | 28 | # Keep a ref to the source, in case it disappears from the Internet. 29 | ln -s "${src}" "$out/share/ltsa/ltsatool.zip" 30 | 31 | cat > "$out/bin/ltsa" << EOF 32 | #!${bash}/bin/sh 33 | exec ${jre}/bin/java -jar "$out/lib/ltsa.jar" "\$@" 34 | EOF 35 | 36 | chmod +x "$out/bin/ltsa" 37 | ''; 38 | 39 | meta = with stdenv.lib; { 40 | description = "Verification tool for concurrent systems"; 41 | longDescription = '' 42 | LTSA (Labelled Transition System Analyser) mechanically checks that 43 | the specification of a concurrent system satisfies the properties 44 | required of its behaviour. In addition, LTSA supports specification 45 | animation to facilitate interactive exploration of system 46 | behaviour. 47 | 48 | A system in LTSA is modelled as a set of interacting finite state 49 | machines. The properties required of the system are also modelled 50 | as state machines. LTSA performs compositional reachability 51 | analysis to exhaustively search for violations of the desired 52 | properties. 53 | ''; 54 | homepage = http://www.doc.ic.ac.uk/ltsa/; 55 | license = "unknown"; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /pkgs/max_perf_pct/default.nix: -------------------------------------------------------------------------------- 1 | { runCommand }: 2 | 3 | runCommand "max_perf_pct" {} '' 4 | mkdir -p "$out/bin" 5 | cp "${./max_perf_pct}" "$out/bin/max_perf_pct" 6 | '' 7 | -------------------------------------------------------------------------------- /pkgs/max_perf_pct/max_perf_pct: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Manipulate Intel P-state "max_perf_pct" sysfs parameter. 3 | # 4 | # Author: Bjørn Forsman 5 | 6 | usage() 7 | { 8 | cat << EOF 9 | Manipulate Intel P-state "max_perf_pct" sysfs parameter. 10 | 11 | Usage: $progname [ num_0_to_100 | + | - ] 12 | 13 | Examples: 14 | $progname # print current value 15 | $progname num_0_to_100 # set given value 16 | $progname + # increment by $increment and print new value 17 | $progname - # decrement by $increment and print new value 18 | 19 | To reduce fan noise (and performance, of course), try "$progname 70". 20 | EOF 21 | } 22 | 23 | if [ "$UID" -eq 0 ]; then 24 | maybe_sudo= 25 | else 26 | maybe_sudo=sudo 27 | fi 28 | 29 | # Since kernel X.Y(?) we have to use powersave governor to be able to change 30 | # max_perf_pct. (Otherwise, the default governor ("performance") simply ignores 31 | # our writes to max_perf_pct.) 32 | setup() 33 | { 34 | echo powersave | $maybe_sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor >/dev/null 35 | } 36 | 37 | set_val() 38 | { 39 | val="$1" 40 | test "$val" -lt 0 && val=0 41 | test "$val" -gt 100 && val=100 42 | setup 43 | echo "$val" | $maybe_sudo tee "$max_perf_pct" >/dev/null 44 | } 45 | 46 | print_val() 47 | { 48 | cat "$max_perf_pct" 49 | } 50 | 51 | max_perf_pct=/sys/devices/system/cpu/intel_pstate/max_perf_pct 52 | increment=5 53 | progname="$(basename "$0")" 54 | 55 | for arg in "$@"; do 56 | case "$arg" in 57 | -h|--help) usage; exit 0;; 58 | "") usage; exit 1;; 59 | esac 60 | done 61 | 62 | arg="$1" 63 | cur_val=$(cat "$max_perf_pct") 64 | 65 | case "$arg" in 66 | +) set_val $(($cur_val + $increment)); print_val;; 67 | -) set_val $(($cur_val - $increment)); print_val;; 68 | "") print_val;; 69 | *) set_val "$arg";; 70 | esac 71 | -------------------------------------------------------------------------------- /pkgs/mini-ci/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , shellcheck, git, nix, utillinux, gnused 3 | , repositories ? "/var/lib/gitolite/repositories" 4 | , miniciGcRootDir ? "/nix/var/nix/gcroots/mini-ci" 5 | }: 6 | 7 | stdenv.mkDerivation { 8 | name = "mini-ci"; 9 | src = ./mini-ci.sh; 10 | unpackPhase = "true"; 11 | installPhase = '' 12 | mkdir -p "$out/bin" 13 | install -m 755 "$src" "$out/bin/mini-ci" 14 | # Set configurable paths 15 | sed -e "s|^repositories=.*|repositories=\"${repositories}\"|" \ 16 | -e "s|^default_datadir=.*|default_datadir=${miniciGcRootDir}|" \ 17 | -e "s|^GIT_BIN=.*|GIT_BIN=${git}/bin/git|" \ 18 | -e "s|^NIX_BUILD_BIN=.*|NIX_BUILD_BIN=${nix}/bin/nix-build|" \ 19 | -e "s|^NIX_STORE_BIN=.*|NIX_STORE_BIN=${nix}/bin/nix-store|" \ 20 | -e "s|^FLOCK_BIN=.*|FLOCK_BIN=${utillinux}/bin/flock|" \ 21 | -e "s|^SED_BIN=.*|SED_BIN=${gnused}/bin/sed|" \ 22 | -i "$out/bin/mini-ci" 23 | ${shellcheck}/bin/shellcheck "$out/bin/mini-ci" 24 | ''; 25 | } 26 | -------------------------------------------------------------------------------- /pkgs/nix-check-before-push/default.nix: -------------------------------------------------------------------------------- 1 | { writeShellScriptBin }: 2 | 3 | writeShellScriptBin "nix-check-before-push" '' 4 | # Check for evaluation errors in nixpkgs (and nixos?) git repositories. 5 | # Run it before git push. 6 | 7 | set -x 8 | nix-env -f . -qa \* --meta --xml --drv-path --show-trace >/dev/null || { echo FAILED; exit 1; } 9 | nix-build pkgs/top-level/release.nix -A tarball || { echo FAILED; exit 1; } 10 | '' 11 | -------------------------------------------------------------------------------- /pkgs/popwk/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, shellcheck 2 | , ltunify, mawk, notify-desktop, systemd, jq, coreutils, dbus, libressl 3 | }: 4 | 5 | stdenv.mkDerivation rec { 6 | name = "popwk-${version}"; 7 | version = "0"; 8 | 9 | # building is only a few sed operations on a shell script 10 | preferLocalBuild = true; 11 | 12 | buildCommand = '' 13 | mkdir -p "$out/bin" 14 | dest="$out/bin/popwk" 15 | cp "${./popwk.sh}" "$dest" 16 | ${shellcheck}/bin/shellcheck "$dest" 17 | chmod +x "$dest" 18 | patchShebangs "$dest" 19 | 20 | # SUDO_BIN= is deliberately not fixed to an absolute path, because 21 | # the correct path depends on the operating system: NixOS uses 22 | # /run/wrappers/bin/sudo, but nobody else does. So rely on PATH 23 | # lookup for that one. 24 | sed -e "s|^LTUNIFY_BIN=.*|LTUNIFY_BIN=${ltunify}/bin/ltunify|" \ 25 | -e "s|^MAWK_BIN=.*|MAWK_BIN=${mawk}/bin/mawk|" \ 26 | -e "s|^NOTIFY_DESKTOP_BIN=.*|NOTIFY_DESKTOP_BIN=${notify-desktop}/bin/notify-desktop|" \ 27 | -e "s|^LOGINCTL_BIN=.*|LOGINCTL_BIN=${systemd}/bin/loginctl|" \ 28 | -e "s|^JQ_BIN=.*|JQ_BIN=${jq}/bin/jq|" \ 29 | -e "s|^WC_BIN=.*|WC_BIN=${coreutils}/bin/wc|" \ 30 | -e "s|^DBUS_SEND_BIN=.*|DBUS_SEND_BIN=${dbus}/bin/dbus-send|" \ 31 | -e "s|^NC_BIN=.*|NC_BIN=${libressl.nc}/bin/nc|" \ 32 | -i "$dest" 33 | ''; 34 | 35 | meta = { 36 | description = "Power on/off projector with keyboard"; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /pkgs/roomeqwizard/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, openjdk8, coreutils, gawk, gnused, gnugrep }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "roomeqwizard-${version}"; 5 | version = "5.19"; 6 | 7 | src = fetchurl { 8 | url = "https://www.roomeqwizard.com/installers/REW_linux_5_19.sh"; 9 | sha256 = "0xvxb8x16yh97n0p6nj9dnzvficgqkywdi3gds0skkqccgv2dwlb"; 10 | }; 11 | 12 | buildInputs = [ openjdk8 ]; 13 | 14 | unpackPhase = "true"; 15 | 16 | # Pre-built software 17 | buildPhase = "true"; 18 | 19 | installPhase = '' 20 | # First, keep a ref to the source, in case it disappears from the Internet. 21 | mkdir -p "$out/share/REW" 22 | ln -s "${src}" "$out/share/REW/installer-${version}.sh" 23 | 24 | # Run the installer, with prepared answers. 25 | (echo o # "This will install Room EQ Wizard on your computer." OK? 26 | echo # view next page of license text 27 | echo # view next page of license text 28 | echo 1 # accept the license agreement 29 | echo "$out/REW" # where to install 30 | echo y # create symlinks? 31 | echo "$out/bin/" # where to create symlinks 32 | echo y # create desktop icon? 33 | ) | sh "$src" 34 | 35 | # Remove unneded scripts 36 | rm "$out/REW/uninstall" 37 | 38 | # Fix location of the desktop file. 39 | mkdir -p "$out/share/applications" 40 | mv "$out/REW/REW.desktop" "$out/share/applications" 41 | # Specify an icon, since upstream doesn't provide one. 42 | echo "Icon=$out/REW/.install4j/s_yn6vx9.png" >> "$out/share/applications/REW.desktop" 43 | 44 | # * Give the startup script a java package to use. 45 | # * Don't rely on finding progs in PATH. Mind the trailing space when 46 | # matching "ls " (since not all "ls" should be modified). 47 | sed -e "s|^INSTALL4J_JAVA_HOME_OVERRIDE=.*|INSTALL4J_JAVA_HOME_OVERRIDE=${openjdk8}|" \ 48 | -e "s|\|${coreutils}/bin/basename|" \ 49 | -e "s|\|${coreutils}/bin/dirname|" \ 50 | -e "s|\ |${coreutils}/bin/ls |" \ 51 | -e "s|\|${coreutils}/bin/expr|" \ 52 | -e "s|\|${coreutils}/bin/rm|" \ 53 | -e "s|\|${coreutils}/bin/mv|" \ 54 | -e "s|\|${coreutils}/bin/chmod|" \ 55 | -e "s|\|${gawk}/bin/awk|" \ 56 | -e "s|\|${gnused}/bin/sed|" \ 57 | -e "s|\|${gnugrep}/bin/egrep|" \ 58 | -i "$out/REW/roomeqwizard" 59 | 60 | # Add udev rules for the MiniDSP UMIK-1 calibrated USB microphone that is 61 | # recommended for use with REW. 62 | mkdir -p "$out/lib/udev/rules.d" 63 | cat > "$out/lib/udev/rules.d/90-roomeqwizard.rules" << EOF 64 | # MiniDSP UMIK-1 calibrated USB microphone 65 | SUBSYSTEM=="usb", ATTR{idVendor}=="2752", ATTR{idProduct}=="0007", TAG+="uaccess" 66 | EOF 67 | ''; 68 | 69 | meta = with stdenv.lib; { 70 | description = "Measuring and analysing room and loudspeaker responses"; 71 | homepage = "https://www.roomeqwizard.com/"; 72 | license = licenses.unfree; 73 | # this expression is limited to linux, but upstream supports more 74 | platforms = platforms.linux; 75 | maintainers = [ maintainers.bjornfor ]; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /pkgs/tmux/default.nix: -------------------------------------------------------------------------------- 1 | # Wrapped tmux with custom tmux.conf (no global state). 2 | 3 | { pkgs }: 4 | 5 | let 6 | plugins = with pkgs.tmuxPlugins; [ 7 | # prefix + Ctrl-s - save 8 | # prefix + Ctrl-r - restore 9 | resurrect 10 | 11 | # Uses tmux-resurrect to automatically save and restore of environment 12 | # (windows and panes). Depends on resurrect, so must be after it (if plugin 13 | # load order matters). 14 | continuum 15 | 16 | # prefix + C - Create a session by prompting for its name 17 | # prefix + X - Deletes the current session 18 | # prefix + g - Lists all the sessions (alternative to prefix + s) 19 | sessionist 20 | ]; 21 | 22 | fullTmuxConf = pkgs.runCommand "tmux.conf" 23 | { # Variables to be substituted in tmux.conf 24 | pythonPackages_powerline = pkgs.python3Packages.powerline; 25 | } 26 | '' 27 | cp ${./tmux.conf} "$out" 28 | substituteAllInPlace "$out" 29 | 30 | # Assert that there are no remaining @metaVars@. 31 | if grep -rn "@[a-z][a-zA-Z0-9_-]*@" "$out"; then 32 | echo "error: found one or more unpatched @metaVars@" 33 | exit 1 34 | fi 35 | 36 | # Configure plugins 37 | echo "" >> "$out" 38 | # tmux-continuum config 39 | # Last saved environment is automatically restored when tmux is started. 40 | echo "set-option -g @continuum-restore 'on'" >> "$out" 41 | 42 | # Install plugins 43 | echo "" >> "$out" 44 | echo "# Plugins" >> "$out" 45 | echo '${pkgs.lib.concatMapStrings (x: "run-shell ${x.rtp}\n") plugins}' >> "$out" 46 | ''; 47 | 48 | tmuxWithConf = pkgs.writeScriptBin "tmux" '' 49 | #!${pkgs.bash}/bin/bash 50 | export PATH="''${PATH}''${PATH:+:}${with pkgs; lib.makeBinPath [ python3Packages.powerline xclip ]}" 51 | exec "${pkgs.tmux}/bin/tmux" -f "${fullTmuxConf}" "$@" 52 | ''; 53 | 54 | tmuxSourceConf = pkgs.writeScriptBin "tmux-source-conf" '' 55 | #!${pkgs.bash}/bin/bash 56 | # Helper script to source the new tmux.conf without global state (only 57 | # $PATH lookup). 58 | "${pkgs.tmux}/bin/tmux" source-file "${fullTmuxConf}" 59 | "${pkgs.tmux}/bin/tmux" display-message "Sourced ${fullTmuxConf}" 60 | ''; 61 | in 62 | pkgs.symlinkJoin { 63 | name = "${pkgs.tmux.name}-with-config"; 64 | paths = [ pkgs.tmux.all ]; 65 | postBuild = '' 66 | rm "$out/bin/tmux" 67 | cp "${tmuxWithConf}/bin/tmux" "$out/bin" 68 | cp "${tmuxSourceConf}/bin/tmux-source-conf" "$out/bin/tmux-source-conf" 69 | ''; 70 | } 71 | -------------------------------------------------------------------------------- /pkgs/tmux/tmux.conf: -------------------------------------------------------------------------------- 1 | # Use "tmux show-options [-s|-g]" to see current options. 2 | 3 | # Force 256 colors 4 | set-option -g default-terminal "tmux-256color" 5 | 6 | # Let the mouse select panes, resize panes, scroll, select and copy text. 7 | set-option -g mouse on 8 | 9 | # This is a command line, so make emacs keys work there ( + :) 10 | set-option -g status-keys "emacs" 11 | set-option -g mode-keys "vi" 12 | 13 | # Show tmux messages for N ms (or until a key is pressed) 14 | set-option -g display-time 4000 15 | 16 | # 24-hour clock 17 | set-window-option -g clock-mode-style 24 18 | 19 | # How long to display pane numbers ( + q). When pane numbers are 20 | # displayed, you can press numeric keys to jump to that pane. 21 | set-option -g display-panes-time 4000 22 | 23 | # When a window is closed, renumber higher numbered windows to fill the gap. 24 | set-option -g renumber-windows on 25 | 26 | # Start windows and panes at 1, not 0 27 | set-option -g base-index 1 28 | set-window-option -g pane-base-index 1 29 | 30 | # Big history 31 | set-option -g history-limit 100000 32 | 33 | # The default green line is easy to miss. 34 | set-option -g pane-active-border-style fg=red,bg=red 35 | 36 | # Change the prefix key from C-b (default) to C-Space 37 | set-option -g prefix C-Space 38 | unbind-key C-b 39 | bind-key C-Space send-prefix 40 | 41 | # Use the system clipboard (and primary selection). 42 | # (Use xclip since it allows (reliably) copying to both destinations at the 43 | # same time.) 44 | bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -selection primary -selection clipboard" 45 | bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "xclip -selection primary -selection clipboard" 46 | 47 | # Mouse middle click to paste from the clipboard 48 | unbind-key MouseDown2Pane 49 | bind-key -n MouseDown2Pane run "tmux set-buffer \"$(xclip -o -selection clipboard)\"; tmux paste-buffer" 50 | 51 | # Mouse drag to re-order windows 52 | bind-key -n MouseDrag1Status swap-window -t= 53 | 54 | # Mouse double-click on window list to open new window 55 | bind-key -n DoubleClick1Status new-window 56 | 57 | # Move between panes using Vim keys. 58 | # NOTE: This clobbers + l to select last active window. 59 | bind-key h select-pane -L 60 | bind-key C-h select-pane -L 61 | bind-key j select-pane -D 62 | bind-key C-j select-pane -D 63 | bind-key k select-pane -U 64 | bind-key C-k select-pane -U 65 | bind-key l select-pane -R 66 | bind-key C-l select-pane -R 67 | # And Alt+ movement. This might conflict with tiling WMs. 68 | # Must set escape time low, else things get weird (Esc+key gets interpreted as 69 | # Alt+key.) 70 | set-option -g escape-time 10 71 | # Smart pane switching with awareness of Vim splits, based 72 | # on https://github.com/christoomey/vim-tmux-navigator. 73 | # Differences: use Alt instead of Ctrl, since I like to keep using Ctrl-j and 74 | # Ctrl-l for "run command" and "clear screen". For the grep below, beware that 75 | # vim from nixpkgs gets called ".vim-wrapped" in ps listings. But neovim is 76 | # simply "nvim". 77 | is_vim="ps -o state= -o comm= -t '#{pane_tty}' \ 78 | | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'" 79 | bind-key -n M-h if-shell "$is_vim" "send-keys M-h" "select-pane -L" 80 | bind-key -n M-j if-shell "$is_vim" "send-keys M-j" "select-pane -D" 81 | bind-key -n M-k if-shell "$is_vim" "send-keys M-k" "select-pane -U" 82 | bind-key -n M-l if-shell "$is_vim" "send-keys M-l" "select-pane -R" 83 | bind-key -T copy-mode-vi M-h select-pane -L 84 | bind-key -T copy-mode-vi M-j select-pane -D 85 | bind-key -T copy-mode-vi M-k select-pane -U 86 | bind-key -T copy-mode-vi M-l select-pane -R 87 | 88 | # Move between panes using Alt+. It's very similar (in effort) though 89 | # to use the default binding: + . 90 | bind-key -n M-Left select-pane -L 91 | bind-key -n M-Down select-pane -D 92 | bind-key -n M-Up select-pane -U 93 | bind-key -n M-Right select-pane -R 94 | 95 | # Switch windows with Alt+number. 96 | # WARN: gnome-terminal eats these for itself, if using tabs. 97 | bind-key -n M-1 select-window -t 1 98 | bind-key -n M-2 select-window -t 2 99 | bind-key -n M-3 select-window -t 3 100 | bind-key -n M-4 select-window -t 4 101 | bind-key -n M-5 select-window -t 5 102 | bind-key -n M-6 select-window -t 6 103 | bind-key -n M-7 select-window -t 7 104 | bind-key -n M-8 select-window -t 8 105 | bind-key -n M-9 select-window -t 9 106 | 107 | # Easier and faster switching between next/prev window (don't have to let go of 108 | # Ctrl). 109 | bind-key C-n next-window 110 | bind-key C-p previous-window 111 | 112 | # Inherit current working directory when splitting panes 113 | bind-key '%' split-window -h -c '#{pane_current_path}' 114 | bind-key '"' split-window -v -c '#{pane_current_path}' 115 | # and creating windows 116 | #bind-key c new-window -c '#{pane_current_path}' 117 | 118 | # Fast mappings for splitting windows 119 | bind-key -n M-v split-window -h -c '#{pane_current_path}' 120 | bind-key -n M-s split-window -v -c '#{pane_current_path}' 121 | 122 | # tmux sources files only at startup, when creating a session. To be able to 123 | # reload the config in a running session, when tmux.conf is generated in the 124 | # /nix/store, each time with a new and unique path, we have this wrapper script 125 | # that can be looked up in PATH and that sources the new config for us. 126 | bind-key R run-shell "tmux-source-conf" 127 | 128 | # powerline neeeds custom fonts. 129 | # On NixOS: 130 | # fonts.fonts = with pkgs; [ powerline-fonts ]; 131 | # On non-NixOS, this might work: 132 | # nix-env -iA nixpkgs.python3Packages.powerline 133 | source-file "@pythonPackages_powerline@/share/tmux/powerline.conf" 134 | -------------------------------------------------------------------------------- /pkgs/vim/default.nix: -------------------------------------------------------------------------------- 1 | # Custom Vim package with bundled plugins and .vimrc. 2 | # 3 | # Measure Vim startup time, to see which plugins slow it down: 4 | # $ time vim --startuptime /dev/stdout +q 5 | # 6 | # Some vim and neovim differences: 7 | # Startup time: 8 | # nvim: ~450 ms 9 | # vim: ~250 ms 10 | # Easy to map Alt+: 11 | # nvim: yes 12 | # vim: no 13 | # Whether :!COMMAND is tty-capable (no means: cannot run 'tig' nor 'git add 14 | # -p' and 'git df' is without colors): 15 | # nvim: no 16 | # vim: yes 17 | 18 | { pkgs, useNeovim ? true }: 19 | 20 | let 21 | vimConfig = { 22 | customRC = 23 | let 24 | # get the ./src/ tree from the source tarball of a rustc package 25 | mkRustSrcPath = rustc: 26 | pkgs.runCommand "${rustc.name}-srcpath" { preferLocalBuild = true; } '' 27 | mkdir -p "$out" 28 | tar --strip-components=2 -xf "${rustc.src}" -C "$out" "${rustc.name}-src" 29 | ''; 30 | in 31 | (builtins.readFile ./vimrc) + '' 32 | let $RUST_SRC_PATH = '${mkRustSrcPath pkgs.rustc}' 33 | ''; 34 | packages.myVimPackage = with pkgs.vimPlugins; { 35 | # loaded on launch 36 | start = [ 37 | csapprox 38 | csv-vim 39 | deoplete-nvim 40 | editorconfig-vim 41 | fugitive 42 | fzf-vim 43 | fzfWrapper 44 | gundo-vim 45 | LanguageClient-neovim # also supports vim >= 8.0 46 | matchit-zip 47 | nerdcommenter 48 | nerdtree 49 | taglist-vim 50 | vim-airline 51 | vim-eunuch 52 | vim-gitgutter 53 | vim-nix 54 | vim-racer 55 | vim-speeddating 56 | vim-tmux-navigator 57 | ]; 58 | # manually loadable by calling `:packadd $plugin-name` 59 | opt = [ /* ... */ ]; 60 | # To automatically load a plugin when opening a filetype, add vimrc lines 61 | # like: 62 | # autocmd FileType php :packadd phpCompletion 63 | }; 64 | }; 65 | in 66 | 67 | if useNeovim then 68 | pkgs.neovim.override { 69 | vimAlias = true; 70 | configure = vimConfig; 71 | } 72 | else 73 | pkgs.vim_configurable.customize { 74 | name = "vim"; 75 | vimrcConfig = vimConfig; 76 | } 77 | -------------------------------------------------------------------------------- /pkgs/winusb/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchzip, wxGTK30 }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "winusb-2017-01-30"; 5 | 6 | src = fetchzip { 7 | url = "https://github.com/slacka/WinUSB/archive/599f00cdfd5c931056c576e4b2ae04d9285c4192.zip"; 8 | sha256 = "1219425d1m4463jy85nrc5xz5qy5m8svidbiwnqicy7hp8pdwa7x"; 9 | }; 10 | 11 | buildInputs = [ wxGTK30 ]; 12 | 13 | meta = with stdenv.lib; { 14 | description = "Create bootable USB disks from Windows ISO images"; 15 | homepage = https://github.com/slacka/WinUSB; 16 | license = licenses.gpl3; 17 | maintainers = [ maintainers.bjornfor ]; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /profiles/backup-server.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | backupDiskMountpoint = "/mnt/backup-disk"; 5 | 6 | # The external backup is split over two disk sets. Each set has 3 disks in 7 | # rotation. Complete sets are found on disks (n,n+3), for example (1,4). Each 8 | # week the disk set gets rotated in a round robin fashion. 9 | # 10 | # sourceDirs is relative to "${backupDiskMountpoint}/backups/hosts". 11 | backupSet0 = { 12 | sourceDirs = [ 13 | "maria-pc" 14 | ]; 15 | diskLabels = [ 16 | "usb_4tb_backup1" 17 | "usb_4tb_backup2" 18 | "usb_4tb_backup3" 19 | ]; 20 | }; 21 | 22 | backupSet1 = { 23 | sourceDirs = [ 24 | "media.local" 25 | "mini.local" 26 | "srv1.local" 27 | "whitetip.local" 28 | ]; 29 | diskLabels = [ 30 | "usb_4tb_backup4" 31 | "usb_4tb_backup5" 32 | "usb_4tb_backup6" 33 | ]; 34 | }; 35 | 36 | externalBackupDiskLabels = backupSet0.diskLabels ++ backupSet1.diskLabels; 37 | 38 | printBackupAgeInDays = pkgs.writeScript "print-backup-age-in-days" '' 39 | #!${pkgs.bash}/bin/sh 40 | set -e 41 | repository=$1 42 | if [ "x$repository" = "x" ]; then 43 | echo "Usage: $0 BORG_REPO_URL" >&2 44 | exit 1 45 | fi 46 | today=$(date +%Y-%m-%d) 47 | newest_backup_date=$(${pkgs.borgbackup}/bin/borg list --last 1 --json "$repository" | ${pkgs.jq}/bin/jq --raw-output ".archives[0].start") 48 | # POSIX sh: 49 | #n_days_old=$(echo "scale=0; ( $(date -d "$today" +%s) - $(date -d "$newest_backup_date" +%s) ) / (24*3600)" | bc) 50 | # bash(?): 51 | n_days_old=$(( ( $(date -d "$today" +%s) - $(date -d "$newest_backup_date" +%s) ) / (24*3600) )) 52 | if [ "$n_days_old" -eq "$n_days_old" ] 2>/dev/null 53 | then 54 | # $n_days_old is an integer 55 | echo "$n_days_old" 56 | else 57 | exit 1 58 | fi 59 | ''; 60 | 61 | # Use borg for this? 62 | mkExternalBackupService = backupSetInfo: id: 63 | { 64 | description = "External Backup Set ${toString id}"; 65 | # every morning (try to make it so all other backup jobs have completed 66 | # before this) 67 | startAt = "*-*-* 06:00:00"; 68 | path = with pkgs; [ utillinux rsync ]; 69 | script = '' 70 | num_copies=0 71 | for diskLabel in ${toString backupSetInfo.diskLabels}; do 72 | if [ -a "/dev/disk/by-label/$diskLabel" ]; then 73 | mp="/mnt/$diskLabel" 74 | set -x 75 | for srcDir in ${toString backupSetInfo.sourceDirs}; do 76 | rsync -ai --delete "${backupDiskMountpoint}/backups/hosts/$srcDir/" "$mp/backups/hosts/$srcDir/" 77 | done 78 | set +x 79 | num_copies=$((num_copies + 1)) 80 | fi 81 | done 82 | 83 | echo "Made $num_copies backup copies of: ${toString backupSetInfo.sourceDirs}" 84 | 85 | if [ "$num_copies" -eq 0 ]; then 86 | exit 1 87 | fi 88 | ''; 89 | serviceConfig.SyslogIdentifier = "external-backup${toString id}"; 90 | }; 91 | 92 | in 93 | { 94 | fileSystems = { 95 | # My backup disk: 96 | "${backupDiskMountpoint}" = { device = "/dev/disk/by-label/backup2"; options = [ "nofail" ]; }; 97 | }; 98 | 99 | services.borg-backup = { 100 | enable = true; 101 | jobs."maria-pc" = rec { 102 | repository = "${backupDiskMountpoint}/backups/hosts/maria-pc/maria-pc.borg"; 103 | archiveBaseName = "maria-pc_seagate_expansion_drive_4tb"; 104 | rootDir = "/mnt/${archiveBaseName}"; 105 | pathsToBackup = [ "." ]; 106 | excludes = [ 107 | "'pp:$RECYCLE.BIN'" 108 | "'pp:System Volume Information'" 109 | ]; 110 | startAt = "*-*-* 01:15:00"; # every night 111 | preHook = '' 112 | if [ $(ls "/mnt/${archiveBaseName}" | wc -l) -lt 1 ]; then 113 | echo "/mnt/${archiveBaseName} has no files, assuming mount failure" 114 | exit 1 115 | fi 116 | # sanity check the backup source 117 | expect_path="/mnt/${archiveBaseName}/BILDER/BILDER 1" 118 | if [ ! -d "$expect_path" ]; then 119 | echo "$expect_path is missing. /mnt/${archiveBaseName} contents: $(echo; ls -F /mnt/${archiveBaseName})" 120 | exit 1 121 | fi 122 | ''; 123 | postHook = '' 124 | # Email notification receivers. 125 | # Separate multiple addresses with comma and space (", "). 126 | to_recipients="$(cat /etc/marias-email-address.txt)" 127 | cc_recipients="bjorn.forsman@gmail.com" 128 | 129 | maybe_send_failure_notification() 130 | { 131 | n_days_old=$(${printBackupAgeInDays} "$repository") 132 | echo "Last backup is $n_days_old days old" 133 | if [ "$n_days_old" -ge 7 -a $(( "$n_days_old" % 7 )) = 0 ]; then 134 | echo "Warning: backup is old ($n_days_old days), sending email" 135 | send_email $n_days_old 136 | fi 137 | } 138 | 139 | send_email() 140 | { 141 | n_days_old=$1 142 | test "$n_days_old" -eq "$n_days_old" || { echo "ERROR: Programming error, n_days_old=$n_days_old is not an integer"; exit 1; } 143 | cat << EOM | sendmail -t 144 | From: "Mr. Robot" 145 | To: $to_recipients 146 | Cc: $cc_recipients 147 | Subject: Obs, sikkerhetskopien din er gammel 148 | 149 | Hei Maria, 150 | 151 | Jeg heter Hal og en robot som Bjørn har laget. 152 | Hver natt tar jeg sikkerhetskopi av dataene fra den eksterne 153 | harddisken din og over til Bjørn sin PC. Men nå er det $n_days_old dager siden sist. 154 | 155 | Kan du la PCen stå på en natt slik at jeg får tatt en ny sikkerhetskopi for deg? 156 | 157 | Ha en fin dag! 158 | 159 | Mvh 160 | Hal 9000 / Bjørn Forsman 161 | EOM 162 | } 163 | 164 | # For test 165 | #send_email $(${printBackupAgeInDays} "$repository") 166 | #exit 0 167 | 168 | maybe_send_failure_notification 169 | ''; 170 | }; 171 | }; 172 | 173 | services.samba = { 174 | enable = true; 175 | extraConfig = '' 176 | [borg-backups-maria-pc] 177 | path = /mnt/borg-backups-maria-pc/ 178 | read only = yes 179 | guest ok = yes 180 | ''; 181 | }; 182 | 183 | systemd.services."borg-backup-default" = { 184 | onFailure = [ "status-email@%n" ]; 185 | }; 186 | systemd.services."borg-backup-maria-pc" = { 187 | # borg-backup-maria-pc is set to conflict with mount-borg-backup-maria-pc. 188 | # Because of that we have to start the latter _after_ the backup service. 189 | # If not, systemd would kill the backup service to resolve the conflict. 190 | # TODO: mount-borg-backup-maria-pc cause frequent borg repo locking issues 191 | #postStop = '' 192 | # systemctl start mount-borg-backup-maria-pc 193 | #''; 194 | }; 195 | 196 | systemd.services.external-backup0 = mkExternalBackupService backupSet0 0; 197 | systemd.services.external-backup1 = mkExternalBackupService backupSet1 1; 198 | 199 | systemd.services.mount-borg-backup-maria-pc = { 200 | description = "Mount Borg Backup Repository for Maria PC"; 201 | # TODO: mount-borg-backup-maria-pc cause frequent borg repo locking issues 202 | enable = false; 203 | wantedBy = [ "multi-user.target" ]; 204 | before = [ "samba.target" ]; 205 | conflicts = [ "borg-backup-maria-pc.service" ]; 206 | path = with pkgs; [ 207 | borgbackup utillinux coreutils fuse 208 | ]; 209 | preStart = '' 210 | # deal with stale mount processes 211 | fusermount -uz /mnt/borg-backups-maria-pc || true 212 | mkdir -p /mnt/borg-backups-maria-pc 213 | ''; 214 | serviceConfig.ExecStart = '' 215 | ${pkgs.borgbackup}/bin/borg mount --foreground -o allow_other ${backupDiskMountpoint}/backups/hosts/maria-pc/maria-pc.borg /mnt/borg-backups-maria-pc 216 | ''; 217 | postStop = '' 218 | # deal with stale mount processes 219 | fusermount -uz /mnt/borg-backups-maria-pc || true 220 | ''; 221 | }; 222 | 223 | systemd.services.backup-status = { 224 | description = "Send weekly status email about the backup"; 225 | path = [ "/run/wrappers" /* for sendmail */ ]; 226 | # Run after the local backup jobs (since otherwise the borg repos will be 227 | # locked). Remote backup jobs might still cause trouble. 228 | # TODO: This will not work until the backup jobs are made into "oneshot" 229 | # types. 230 | #after = 231 | # map 232 | # (x: "borg-backup-${x}.service") 233 | # (lib.mapAttrsToList (n: v: n) config.services.borg-backup.jobs); 234 | startAt = "Mon *-*-* 17:00:00"; # weekly 235 | script = 236 | let 237 | jobsAsList = 238 | lib.mapAttrsToList 239 | (n: v: v) 240 | config.services.borg-backup.jobs; 241 | in 242 | '' 243 | set -e 244 | set -u 245 | 246 | overall_status_file=$(mktemp) 247 | trap "rm $overall_status_file" EXIT 248 | echo "GOOD" > "$overall_status_file" 249 | 250 | indent() 251 | { 252 | n=$1 253 | sed "s/^/$(for i in $(seq $n); do printf " "; done)/" 254 | } 255 | 256 | check_repo() 257 | { 258 | repository=$1 259 | indent=$2 260 | # "borg info" is more expensive than "borg list", but the latter doesn't include "nfiles" 261 | json_info=$(${pkgs.borgbackup}/bin/borg info --last 1 --json "$repository") 262 | latest_archive_name=$(echo "$json_info" | ${pkgs.jq}/bin/jq --raw-output ".archives[0].name") 263 | nfiles=$(echo "$json_info" | ${pkgs.jq}/bin/jq --raw-output ".archives[0].stats.nfiles") 264 | echo 265 | echo "$repository:" | indent $indent 266 | n_days_old=$(${printBackupAgeInDays} "$repository") 267 | if [ "$n_days_old" -ge 2 ]; then 268 | if [ "x$set_overall_status" = "x1" ]; then 269 | echo "BAD" > "$overall_status_file" 270 | fi 271 | suffix=" (WARNING)" 272 | else 273 | suffix= 274 | fi 275 | if [ "x$latest_archive_name" = x ]; then 276 | echo "\$latest_archive_name is empty, failed to get info from repo $repository (missing ssh key? repo locked?)" | indent $(($indent * 2)) 277 | if [ "x$set_overall_status" = "x1" ]; then 278 | echo "BAD" > "$overall_status_file" 279 | fi 280 | else 281 | echo "$latest_archive_name -> nfiles=$nfiles, age_days=$n_days_old$suffix" | indent $(($indent * 2)) 282 | fi 283 | } 284 | 285 | check_local_repos() 286 | { 287 | ${lib.concatMapStringsSep "\n" 288 | (job: '' 289 | export BORG_RSH="${job.environment.BORG_RSH or ""}" 290 | check_repo "${job.repository}" 4 291 | '') 292 | jobsAsList 293 | } 294 | } 295 | 296 | check_other_repos() 297 | { 298 | for repo in ${backupDiskMountpoint}/backups/hosts/*/*.borg; do 299 | case "$repo" in 300 | ${lib.concatMapStringsSep "\n" 301 | (job: '' 302 | ${job.repository}) true;; # skip locally configured repo 303 | '') 304 | jobsAsList 305 | } 306 | *) check_repo "$repo" 4;; 307 | esac 308 | done 309 | } 310 | 311 | set_overall_status=1 312 | local_repos_info=$(check_local_repos) 313 | set_overall_status=0 314 | other_repos_info=$(check_other_repos) 315 | 316 | overall_status=$(cat "$overall_status_file") 317 | 318 | cat << EOM | sendmail -t 319 | From: "Mr. Robot" 320 | To: root 321 | Subject: Status of backup(s): $overall_status 322 | 323 | Locally configured repos: 324 | $local_repos_info 325 | 326 | Other repos (not affecting overall status): 327 | $other_repos_info 328 | 329 | - Mr. Robot 330 | EOM 331 | ''; 332 | }; 333 | 334 | systemd.automounts = [ 335 | { where = "/mnt/maria-pc_seagate_expansion_drive_4tb"; 336 | wantedBy = [ "multi-user.target" ]; 337 | } 338 | ] ++ (map (x: 339 | { 340 | where = "/mnt/${x}"; 341 | wantedBy = [ "multi-user.target" ]; 342 | automountConfig.TimeoutIdleSec = "5min"; 343 | }) externalBackupDiskLabels 344 | ); 345 | 346 | systemd.mounts = [ 347 | { what = "//maria-pc/seagate_expansion_drive_4tb"; 348 | where = "/mnt/maria-pc_seagate_expansion_drive_4tb"; 349 | type = "cifs"; 350 | options = "ro,credentials=/root/.credentials.maria-pc,uid=bf,gid=users,iocharset=utf8"; 351 | } 352 | ] ++ (map (x: 353 | { 354 | what = "/dev/disk/by-label/${x}"; 355 | where = "/mnt/${x}"; 356 | }) externalBackupDiskLabels 357 | ); 358 | 359 | environment.systemPackages = with pkgs; [ 360 | borgbackup 361 | cifs_utils # for mount.cifs, needed for cifs filesystems in systemd.mounts. 362 | ]; 363 | 364 | users.extraUsers = { 365 | # A system user for backup automation 366 | backup = { 367 | description = "Backup user"; 368 | uid = 600; 369 | group = "backup"; 370 | home = "/var/lib/backup"; 371 | createHome = true; 372 | useDefaultShell = true; 373 | }; 374 | }; 375 | 376 | users.extraGroups = { 377 | backup = { gid = 600; }; 378 | }; 379 | 380 | users.extraUsers.backup.openssh.authorizedKeys.keys = with config.local.resources.sshKeys; [ 381 | (''command="dir=\"${backupDiskMountpoint}/backups/hosts/media.local\" && cd \"$dir\" && borg serve --restrict-to-path \"$dir\"",restrict '' + media.root.backup) 382 | (''command="dir=\"${backupDiskMountpoint}/backups/hosts/mini.local\" && cd \"$dir\" && borg serve --restrict-to-path \"$dir\"",restrict '' + mini.root.backup) 383 | (''command="dir=\"${backupDiskMountpoint}/backups/hosts/whitetip.local\" && cd \"$dir\" && borg serve --restrict-to-path \"$dir\"",restrict '' + whitetip.root.backup) 384 | # For convenience, allow bf too 385 | (''command="dir=\"${backupDiskMountpoint}/backups/hosts/mini.local\" && cd \"$dir\" && borg serve --restrict-to-path \"$dir\"",restrict '' + mini.bf.default) 386 | (''command="dir=\"${backupDiskMountpoint}/backups/hosts/whitetip.local\" && cd \"$dir\" && borg serve --restrict-to-path \"$dir\"",restrict '' + whitetip.bf.default) 387 | ]; 388 | } 389 | -------------------------------------------------------------------------------- /profiles/webserver.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | myDomain = "bforsman.name"; 5 | phpSockName1 = config.services.phpfpm.pools.pool1.socket; 6 | acmeChallengesDir = "/var/www/challenges/"; 7 | gitwebConfig = { 8 | projectroot = "${config.services.gitolite.dataDir}/repositories"; 9 | extraConfig = '' 10 | our $projects_list = '${config.services.gitolite.dataDir}/projects.list'; 11 | ''; 12 | }; 13 | in 14 | { 15 | imports = [ 16 | ../cfg/mytinytodo.nix 17 | ]; 18 | 19 | users.extraUsers."lighttpd".extraGroups = [ "git" ]; 20 | 21 | # See https://letsencrypt.org/repository/ 22 | security.acme.acceptTerms = true; 23 | 24 | security.acme.certs = { 25 | "${myDomain}" = { 26 | email = "bjorn.forsman@gmail.com"; 27 | webroot = acmeChallengesDir; 28 | extraDomains = 29 | { "mariaogbjorn.no" = null; 30 | "sky.mariaogbjorn.no" = null; 31 | }; 32 | # TODO: When lighttpd 1.4.46 comes out we can switch from "restart" to "reload" 33 | postRun = '' 34 | systemctl restart lighttpd 35 | ''; 36 | }; 37 | }; 38 | 39 | services = { 40 | 41 | postfix = { 42 | domain = myDomain; 43 | hostname = myDomain; 44 | }; 45 | 46 | lighttpd = { 47 | enable = true; 48 | mod_status = true; 49 | mod_userdir = true; 50 | enableModules = [ "mod_alias" "mod_proxy" "mod_access" "mod_fastcgi" "mod_redirect" "mod_openssl" "mod_auth" ]; 51 | extraConfig = '' 52 | # Uncomment one or more of these in case something doesn't work right 53 | #debug.log-request-header = "enable" 54 | #debug.log-request-header-on-error = "enable" 55 | #debug.log-response-header = "enable" 56 | #debug.log-file-not-found = "enable" 57 | #debug.log-request-handling = "enable" 58 | #debug.log-condition-handling = "enable" 59 | 60 | $HTTP["host"] =~ ".*" { 61 | dir-listing.activate = "enable" 62 | alias.url += ( "/munin" => "/var/www/munin" ) 63 | 64 | # for Let's Encrypt certificates (NixOS security.acme.certs option) 65 | alias.url += ( "/.well-known/acme-challenge" => "${acmeChallengesDir}/.well-known/acme-challenge" ) 66 | 67 | # Reverse proxy for transmission bittorrent client 68 | proxy.server += ( 69 | "/transmission" => ( "transmission" => ( 70 | "host" => "127.0.0.1", 71 | "port" => 9091 72 | ) ) 73 | ) 74 | # Fix transmission URL corner case: get error 409 if URL is 75 | # /transmission/ or /transmission/web. Redirect those URLs to 76 | # /transmission (no trailing slash). 77 | url.redirect += ( "^/transmission/(web)?$" => "/transmission" ) 78 | 79 | fastcgi.server = ( 80 | ".php" => ( 81 | "localhost" => ( 82 | "socket" => "${phpSockName1}", 83 | )) 84 | ) 85 | 86 | ## Block access to certain URLs if remote IP is not on LAN 87 | ## Use auth instead (see below) 88 | #$HTTP["remoteip"] !~ "^(192\.168\.1|127\.0\.0\.1)" { 89 | # $HTTP["url"] =~ "(^/transmission/.*|^/server-.*|^/munin/.*|^${config.services.lighttpd.collectd-graph-panel.urlPrefix}.*)" { 90 | # url.access-deny = ( "" ) 91 | # } 92 | #} 93 | } 94 | 95 | # Lighttpd SSL/HTTPS documentation: 96 | # http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_SSL 97 | 98 | $HTTP["host"] == "${myDomain}" { 99 | $SERVER["socket"] == ":443" { 100 | ssl.engine = "enable" 101 | ssl.pemfile = "/var/lib/acme/${myDomain}/full.pem" 102 | } 103 | $HTTP["scheme"] == "http" { 104 | url.redirect += ("^/.*" => "https://${myDomain}$0") 105 | } 106 | } 107 | 108 | $HTTP["host"] == "mariaogbjorn.no" { 109 | $SERVER["socket"] == ":443" { 110 | ssl.engine = "enable" 111 | ssl.pemfile = "/var/lib/acme/${myDomain}/full.pem" 112 | } 113 | $HTTP["scheme"] == "http" { 114 | url.redirect += ("^/.*" => "https://mariaogbjorn.no$0") 115 | } 116 | } 117 | 118 | # TODO: Reduce config duplication between vhosts 119 | $HTTP["host"] == "sky.mariaogbjorn.no" { 120 | $SERVER["socket"] == ":443" { 121 | ssl.engine = "enable" 122 | ssl.pemfile = "/var/lib/acme/${myDomain}/full.pem" 123 | } 124 | url.redirect += ("^/$" => "/nextcloud/") 125 | $HTTP["scheme"] == "http" { 126 | url.redirect += ("^/.*" => "https://sky.mariaogbjorn.no$0") 127 | } 128 | } 129 | 130 | # Authentication/authorization 131 | # To add or update a user: 132 | # sudo -u lighttpd htpasswd /etc/lighttpd/users.htpasswd USERNAME 133 | auth.backend = "htpasswd" 134 | auth.backend.htpasswd.userfile = "/etc/lighttpd/users.htpasswd" 135 | 136 | $HTTP["url"] =~ "(^/transmission/.*|^/server-.*|^/munin/.*|^${config.services.lighttpd.collectd-graph-panel.urlPrefix}.*)" { 137 | auth.require += ( 138 | "" => ( 139 | "method" => "basic", 140 | "realm" => "Misc apps", 141 | # Allow all users with a valid password 142 | #"require" => "valid-user" 143 | # Or specific (sub)set of users 144 | #"require" => "user=agent007|user=agent008" 145 | "require" => "user=bf" 146 | ) 147 | ) 148 | } 149 | 150 | $HTTP["url"] =~ "(^/mytinytodo)" { 151 | auth.require += ( 152 | "" => ( 153 | "method" => "basic", 154 | "realm" => "Misc apps", 155 | "require" => "user=bf|user=maria" 156 | ) 157 | ) 158 | } 159 | ''; 160 | collectd-graph-panel.enable = true; 161 | nextcloud.enable = true; 162 | # NixOS 18.09+ renamed services.lighttpd.gitweb.* to services.gitweb.* 163 | gitweb = { enable = true; } // 164 | (if lib.versionOlder (lib.version or lib.nixpkgsVersion) "18.09" 165 | then gitwebConfig 166 | else {}); 167 | }; 168 | 169 | phpfpm.pools = lib.mkIf config.services.lighttpd.enable { 170 | pool1 = { 171 | user = "lighttpd"; 172 | group = "lighttpd"; 173 | settings = { 174 | "listen.owner" = "lighttpd"; 175 | "listen.group" = "lighttpd"; 176 | "pm" = "dynamic"; 177 | "pm.max_children" = 75; 178 | "pm.start_servers" = 10; 179 | "pm.min_spare_servers" = 5; 180 | "pm.max_spare_servers" = 20; 181 | "pm.max_requests" = 500; 182 | }; 183 | }; 184 | }; 185 | 186 | collectd = { 187 | enable = true; 188 | extraConfig = '' 189 | # Interval at which to query values. Can be overwritten on per plugin 190 | # with the 'Interval' option. 191 | # WARNING: You should set this once and then never touch it again. If 192 | # you do, you will have to delete all your RRD files. 193 | Interval 10 194 | 195 | # Load plugins 196 | LoadPlugin apcups 197 | LoadPlugin contextswitch 198 | LoadPlugin cpu 199 | LoadPlugin df 200 | LoadPlugin disk 201 | LoadPlugin ethstat 202 | LoadPlugin interface 203 | LoadPlugin irq 204 | LoadPlugin virt 205 | LoadPlugin load 206 | LoadPlugin memory 207 | LoadPlugin network 208 | LoadPlugin nfs 209 | LoadPlugin processes 210 | LoadPlugin rrdtool 211 | LoadPlugin sensors 212 | LoadPlugin tcpconns 213 | LoadPlugin uptime 214 | 215 | 216 | Host "localhost" 217 | Port "3551" 218 | 219 | 220 | 221 | Connection "qemu:///system" 222 | 223 | 224 | 225 | MountPoint "/" 226 | MountPoint "/mnt/data/" 227 | MountPoint "/mnt/backup-disk/" 228 | 229 | 230 | # Output/write plugin (need at least one, if metrics are to be persisted) 231 | 232 | CacheFlush 120 233 | WritesPerSecond 50 234 | 235 | ''; 236 | }; 237 | }; 238 | 239 | # NixOS 18.09+ renamed services.lighttpd.gitweb.* to services.gitweb.* 240 | services.gitweb = 241 | lib.mkIf (lib.versionAtLeast (lib.version or lib.nixpkgsVersion) "18.09") 242 | gitwebConfig; 243 | 244 | systemd.services.lighttpd = { 245 | # nextcloud startup can take a lot of time due to rsync in the data dir 246 | serviceConfig.TimeoutStartSec = "60m"; 247 | wants = [ "acme-selfsigned-${myDomain}.service" "acme-${myDomain}.service" ]; 248 | after = [ "acme-selfsigned-${myDomain}.service" ]; 249 | }; 250 | 251 | } 252 | -------------------------------------------------------------------------------- /resources/host-addrs.nix: -------------------------------------------------------------------------------- 1 | # Host names and their addresses... because I don't have a proper DNS server on 2 | # my network (yet) and avahi and wins doesn't work reliably (in my experience). 3 | # 4 | # This is basically a copy from my router config. 5 | 6 | { 7 | bf-phone = "192.168.0.9"; 8 | bf-work-laptop = "192.168.0.32"; 9 | chromecast = "192.168.0.3"; 10 | maria-pc = "192.168.0.14"; 11 | maria-phone = "192.168.0.19"; 12 | media = "192.168.0.6"; 13 | mini = "192.168.0.5"; 14 | projector = "192.168.0.11"; 15 | reolink = "192.168.0.10"; 16 | srv1 = "192.168.0.8"; 17 | tl-sg108e_v2 = "192.168.0.21"; 18 | tl-sg108e_v3 = "192.168.0.16"; 19 | whitetip = "192.168.0.4"; 20 | wifi-ap = "192.168.0.13"; 21 | } 22 | -------------------------------------------------------------------------------- /resources/ssh-keys.nix: -------------------------------------------------------------------------------- 1 | # SSH public keys, stored in an attribute set hierarchy of ... 2 | # 3 | # Suggestion on where to store the keys on the client side. 4 | # Default key: ~/.ssh/id_ 5 | # Other keys: ~/.ssh/id__ 6 | 7 | { 8 | media.root.backup = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJsLLEZxPtdFQJVqG8zOuBZTUYHhhh026F2BDsHXJXPW root@media (for backup automation)''; 9 | media.root.nix_remote_build = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILoDrnvYjSPBWVLgwmuVaOUTnNF1ASaO7Y+oej+6WRBm root@media (nix remote build)''; 10 | 11 | mini.root.backup = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPCwtdqwE2WLolrNQmf5M/DmzaKjG29yq0lr4WgUa2z7 root@mini (for backup automation)''; 12 | mini.root.nix_remote_build = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE62OwZK96RYNiHbVWpQR+aD98wJn9TFmjKTnCV9pv5k root@mini (nix remote build)''; 13 | 14 | mini.bf.default = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILCS9V2jUQGA3qcd7x7amjdhRZidqz8iD+MBkgjY0AN/ bf@mini''; 15 | 16 | whitetip.bf.default = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEp3BjfuW2qc4qmAogtPOPdKChXOWY3PIx4UQkQbQg+A bf@whitetip''; 17 | whitetip.root.nix_remote_build = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBOgHOn3+Sr8WUZQiEVN3NZ6nXOL1NPUSo2Sen+63G6j root@whitetip (nix remote build)''; 18 | whitetip.root.backup = ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAMnppoIYKUmeW09hw2nEofL3aDL12T/P8P81HMnwPpE root@whitetip (for backup automation)''; 19 | 20 | my_phone.user.default = ''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZ63+kGCJbSI8P8LThqXJHZdiGWHpR7K/NUkimWn+3r4y22JhuRLpUHnHRfvPm16HIbrVwrHbZ6vxqvxx7hP9UGRTdRT9HjOvVoOQGIYjRtjrRiMHE/DmrBxdQ5FtQVeARKcNCWYIlubtuxg1c6ZD0fScs5yWrlumblsQxJgqS5K6csyh9yZL8rtBC0VqkroynMoYONqTTAAnx6lg9X6t2FZ3SFqCZ5VYk9DkwLZNIrwwEF87tQSuCSTX8pKw9THP0H07pafR0hWwKHuhPqbK7qlE1ZXzVtbujg/GndLbjFFV7Lpkc5h5B+fC4VBAiaKG9DQSV5LNRjrolprQkijNiFNqojnsCSJVDHSercDSTLNsN2wNPKXUlzkNyWEnefvPFrW1vPBoTF8YrPICNOi8mGLkX+ygP0ROycuKupSqkfAjXqdabAnuHNZHI1gY9j4/qlK5YhgbOu1pWVe9xVKCEfR0MG/iTi83ExiDlkzGgOcFkiDoUaKF6HMM2w6u+pgwDSsP8jmHrUuGqib3mMm3M7VMoGvxQE+T8bQ53G1/z/FI3xITpnNUs61DtUxf6uSCYJFDE5vRYSAnPW9L7/dLo5klJbDbyGyHgneFeGb5gdQEqhUZHXHXwCPyH5fn2XLA6DErMGWAvEqNVs6p2XO54UY/HuKnjr1W8eMqLVMpvVw== My phone''; 21 | } 22 | -------------------------------------------------------------------------------- /users/bf.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | users.extraUsers = { 5 | bf = { 6 | description = "Bjørn Forsman"; 7 | uid = 1000; 8 | extraGroups = [ 9 | "audio" 10 | "cdrom" 11 | "dialout" # for access to /dev/ttyUSBx 12 | "docker" 13 | "git" # for read-only access to gitolite repos on the filesystem 14 | "libvirtd" 15 | "motion" 16 | "networkmanager" 17 | "plugdev" 18 | "scanner" 19 | "syncthing" 20 | "systemd-journal" 21 | "tracing" 22 | "transmission" 23 | "tty" 24 | "usbmon" 25 | "usbtmc" 26 | "vboxusers" 27 | "video" 28 | "wheel" # admin rights 29 | "wireshark" 30 | ]; 31 | isNormalUser = true; 32 | initialPassword = "bf"; 33 | # Subordinate user ids that user is allowed to use. They are set into 34 | # /etc/subuid and are used by newuidmap for user namespaces. (Needed for 35 | # LXC.) 36 | subUidRanges = [ 37 | { startUid = 100000; count = 65536; } 38 | ]; 39 | subGidRanges = [ 40 | { startGid = 100000; count = 65536; } 41 | ]; 42 | openssh.authorizedKeys.keys = with config.local.resources.sshKeys; [ 43 | mini.bf.default 44 | whitetip.bf.default 45 | ]; 46 | }; 47 | }; 48 | 49 | home-manager.users.bf = import ../cfg/home-manager/home.nix; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /users/media.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | { 4 | users.extraUsers = { 5 | media = { 6 | description = "Media user"; 7 | uid = 1001; 8 | extraGroups = [ 9 | "cdrom" 10 | "transmission" 11 | "wheel" 12 | ]; 13 | isNormalUser = true; 14 | initialPassword = "media"; 15 | }; 16 | }; 17 | } 18 | --------------------------------------------------------------------------------